<?php
// STORAGE/BALANCES — wallet_balances (load/upsert/save)
require_once __DIR__ . '/db.php';

// ===============================================================
// STATE — wallet/pool баланс, позиции, engine state, watching
// ===============================================================

// ---------------------------------------------------------------
// Балансы (wallet_balances)
// ---------------------------------------------------------------

/**
 * Загружает баланс entity. Если записи нет — возвращает дефолт со стартовым балансом.
 */
function storage_load_balance(string $entityType, string $entityId, float $startBalance): array
{
    $db   = storage_db();
    $stmt = $db->prepare('SELECT * FROM wallet_balances WHERE entity_type = ? AND entity_id = ?');
    $stmt->execute([$entityType, $entityId]);
    $row  = $stmt->fetch();

    $default = [
        'balance'          => $startBalance,
        'peak_balance'     => $startBalance,
        'max_drawdown_pct' => 0.0,
        'total_gross_pnl'  => 0.0,
        'total_net_pnl'    => 0.0,
        'total_fees'       => 0.0,
        'total_funding'    => 0.0,
        'trades_count'     => 0,
        'wins_count'       => 0,
        'gross_profit_sum' => 0.0,
        'gross_loss_sum'   => 0.0,
        // Mark-to-market: пик эквити (баланс + нереализованный PnL) и макс.
        // просадка по нему. Стартовый пик = стартовый баланс.
        'mtm_peak_equity'      => $startBalance,
        'mtm_max_drawdown_pct' => 0.0,
    ];

    if (!$row) {
        return $default;
    }

    // На случай нулевого mtm_peak_equity (строка создана до первого MTM-прохода)
    // подстраховываемся реализованным peak_balance.
    $mtmPeak = (float) ($row['mtm_peak_equity'] ?? 0);
    if ($mtmPeak <= 0) {
        $mtmPeak = (float) $row['peak_balance'];
    }

    return array_merge($default, [
        'balance'          => (float)   $row['balance'],
        'peak_balance'     => (float)   $row['peak_balance'],
        'max_drawdown_pct' => (float)   $row['max_drawdown_pct'],
        'total_gross_pnl'  => (float)   $row['total_gross_pnl'],
        'total_net_pnl'    => (float)   $row['total_net_pnl'],
        'total_fees'       => (float)   $row['total_fees'],
        'total_funding'    => (float)   $row['total_funding'],
        'trades_count'     => (int)     $row['trades_count'],
        'wins_count'       => (int)     $row['wins_count'],
        'gross_profit_sum' => (float)   $row['gross_profit_sum'],
        'gross_loss_sum'   => (float)   $row['gross_loss_sum'],
        'mtm_peak_equity'      => $mtmPeak,
        'mtm_max_drawdown_pct' => (float) ($row['mtm_max_drawdown_pct'] ?? 0),
    ]);
}

/**
 * Низкоуровневый UPSERT баланса на переданном PDO-хэндле.
 * Единственное место с этим INSERT ... ON CONFLICT — используется и
 * обычным сохранением (storage_save_balance), и атомарным закрытием
 * (storage_close_trade_atomic), чтобы список колонок не расходился.
 */
function storage_upsert_balance_row(PDO $db, string $entityType, string $entityId, array $s): void
{
    $db->prepare('
        INSERT INTO wallet_balances
            (entity_type, entity_id, balance, peak_balance, max_drawdown_pct,
             total_gross_pnl, total_net_pnl, total_fees, total_funding,
             trades_count, wins_count, gross_profit_sum, gross_loss_sum,
             mtm_peak_equity, mtm_max_drawdown_pct, updated_at)
        VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, datetime(\'now\'))
        ON CONFLICT(entity_type, entity_id) DO UPDATE SET
            balance          = excluded.balance,
            peak_balance     = excluded.peak_balance,
            max_drawdown_pct = excluded.max_drawdown_pct,
            total_gross_pnl  = excluded.total_gross_pnl,
            total_net_pnl    = excluded.total_net_pnl,
            total_fees       = excluded.total_fees,
            total_funding    = excluded.total_funding,
            trades_count     = excluded.trades_count,
            wins_count       = excluded.wins_count,
            gross_profit_sum = excluded.gross_profit_sum,
            gross_loss_sum   = excluded.gross_loss_sum,
            mtm_peak_equity      = excluded.mtm_peak_equity,
            mtm_max_drawdown_pct = excluded.mtm_max_drawdown_pct,
            updated_at       = excluded.updated_at
    ')->execute([
        $entityType, $entityId,
        $s['balance'],          $s['peak_balance'],     $s['max_drawdown_pct'],
        $s['total_gross_pnl'],  $s['total_net_pnl'],    $s['total_fees'],
        $s['total_funding'],    $s['trades_count'],     $s['wins_count'],
        $s['gross_profit_sum'], $s['gross_loss_sum'],
        $s['mtm_peak_equity']      ?? $s['peak_balance'] ?? 0,
        $s['mtm_max_drawdown_pct'] ?? 0,
    ]);
}

/**
 * Сохраняет (UPSERT) баланс entity.
 */
function storage_save_balance(string $entityType, string $entityId, array $s): void
{
    storage_upsert_balance_row(storage_db(), $entityType, $entityId, $s);
}
