<?php
/**
 * MT5 Unmatched Trades Resolution Page
 *
 * Rebuilt 2026-08-19. The old page read its lists from $_SESSION or a
 * base64 ?data= URL param that mt5-upload.php's own JS never actually
 * populated - meaning this page always showed "All Trades Resolved"
 * regardless of what had really been left unmatched. It also wrote
 * "skip" actions to a table (mt5_skipped_trades) that has never existed
 * in this schema, so every Skip/Skip All click threw a real SQL error.
 *
 * This version reads directly from the real, persisted tables
 * (unmatched_broker_trades + broker_reconciliations, both written by
 * api/mt5/reconcile.php) - every list here survives a reload, a new
 * login, a different day. "TraderAlign trades with no matching broker
 * execution" is derived live from `trades` rather than stored a second
 * time, since the trade row itself already IS the durable record.
 */

require_once __DIR__ . '/../src/PropFirmHelpers.php';
require_once __DIR__ . '/../src/RenderHelpers.php';
require_once __DIR__ . '/../src/Mt5Reconciler.php';
require_once __DIR__ . '/../src/TradeClassificationEngine.php';
require_once __DIR__ . '/../src/Csrf.php';
$userId = $auth->requireAuth();

$tier = 'free';
try {
    $stmt = $pdo->prepare('SELECT tier FROM user_profiles WHERE user_id = :uid LIMIT 1');
    $stmt->execute([':uid' => $userId]);
    $profileRow = $stmt->fetch(PDO::FETCH_ASSOC);
    if ($profileRow && !empty($profileRow['tier'])) $tier = $profileRow['tier'];
} catch (\Throwable $e) {
    error_log("Failed to read user tier: " . $e->getMessage());
}
$hasAccess = in_array($tier, ['pro', 'elite', 'ultimate'], true);

$message = null;
$messageType = 'success';
$selectedAccountId = trim((string)($_GET['account_id'] ?? $_POST['account_id'] ?? ''));

// ── POST actions ─────────────────────────────────────────────────────
if ($hasAccess && $_SERVER['REQUEST_METHOD'] === 'POST') {
    if (!Csrf::verify()) {
        $message = 'Your session expired - please refresh and try again.';
        $messageType = 'error';
    } else {
        $action = $_POST['action'] ?? '';

        if ($action === 'match_pair' && isset($_POST['unmatched_id'], $_POST['ta_id'], $_POST['account_id'])) {
            [$ok, $err] = resolveMatchPair($pdo, $userId, $_POST['unmatched_id'], $_POST['ta_id'], $_POST['account_id']);
            $message = $ok ? 'Trade matched successfully.' : ('Failed to match: ' . $err);
            $messageType = $ok ? 'success' : 'error';
        }

        elseif ($action === 'dismiss' && isset($_POST['unmatched_id'])) {
            $resolution = ($_POST['resolution'] ?? '') === 'dismissed_other_account' ? 'dismissed_other_account' : 'dismissed_ghost';
            $stmt = $pdo->prepare("UPDATE unmatched_broker_trades SET resolution = :res, resolved_at = NOW() WHERE id = :id AND user_id = :uid AND resolution = 'unresolved'");
            $stmt->execute([':res' => $resolution, ':id' => $_POST['unmatched_id'], ':uid' => $userId]);
            $message = $stmt->rowCount() > 0
                ? ($resolution === 'dismissed_other_account' ? 'Marked as belonging to a different account.' : 'Dismissed - this execution will not be journaled.')
                : 'Nothing to update (already resolved).';
        }

        elseif ($action === 'dismiss_all') {
            $sql = "UPDATE unmatched_broker_trades SET resolution = 'dismissed_ghost', resolved_at = NOW() WHERE user_id = :uid AND resolution = 'unresolved'";
            $params = [':uid' => $userId];
            if ($selectedAccountId !== '') { $sql .= ' AND account_id = :aid'; $params[':aid'] = $selectedAccountId; }
            $stmt = $pdo->prepare($sql);
            $stmt->execute($params);
            $message = $stmt->rowCount() . ' broker execution(s) dismissed.';
        }

        elseif ($action === 'create_trade' && isset($_POST['unmatched_id'], $_POST['account_id'], $_POST['strategy_version_id'])) {
            [$ok, $err] = createTradeFromUnmatched($pdo, $userId, $_POST['unmatched_id'], $_POST['account_id'], $_POST['strategy_version_id']);
            $message = $ok ? 'Trade created and reconciled from the broker execution.' : ('Failed to create trade: ' . $err);
            $messageType = $ok ? 'success' : 'error';
        }
    }
}

// ── Data for the page ───────────────────────────────────────────────
$accounts = [];
$strategies = [];
if ($hasAccess) {
    $stmt = $pdo->prepare('SELECT id, label, account_type, broker_server FROM trading_accounts WHERE user_id = :uid AND deleted_at IS NULL ORDER BY updated_at DESC');
    $stmt->execute([':uid' => $userId]);
    $accounts = $stmt->fetchAll(PDO::FETCH_ASSOC);

    $stmt = $pdo->prepare('SELECT id, name, current_version_id FROM strategies WHERE user_id = :uid AND is_active = 1 AND (is_validation = 0 OR is_validation IS NULL) AND deleted_at IS NULL ORDER BY created_at DESC');
    $stmt->execute([':uid' => $userId]);
    $strategies = $stmt->fetchAll(PDO::FETCH_ASSOC);
}

$accountsById = [];
foreach ($accounts as $a) $accountsById[$a['id']] = $a;

$unmatchedBroker = [];
$unmatchedTa = [];
$accountsInvolved = [];

if ($hasAccess) {
    $sql = "
        SELECT ubt.*, br.statement_period_start, br.statement_period_end, br.uploaded_at
        FROM unmatched_broker_trades ubt
        LEFT JOIN broker_reconciliations br ON br.id = ubt.reconciliation_id
        WHERE ubt.user_id = :uid AND ubt.resolution = 'unresolved'
    ";
    $params = [':uid' => $userId];
    if ($selectedAccountId !== '') { $sql .= ' AND ubt.account_id = :aid'; $params[':aid'] = $selectedAccountId; }
    $sql .= ' ORDER BY ubt.open_time DESC LIMIT 500';

    $stmt = $pdo->prepare($sql);
    $stmt->execute($params);
    foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
        $raw = json_decode($row['raw_broker_row'], true) ?: [];
        $row['mt5'] = $raw;
        $unmatchedBroker[] = $row;
        $accountsInvolved[$row['account_id']] = true;
    }

    // Widest real period across every involved account's reconciliations,
    // used to bound the "ghost journal entry" query below.
    foreach (array_keys($accountsInvolved) as $accId) {
        $bounds = $pdo->prepare('SELECT MIN(statement_period_start) s, MAX(statement_period_end) e FROM broker_reconciliations WHERE user_id = :uid AND account_id = :aid');
        $bounds->execute([':uid' => $userId, ':aid' => $accId]);
        $b = $bounds->fetch(PDO::FETCH_ASSOC);
        if (empty($b['s']) || empty($b['e'])) continue;

        $taStmt = $pdo->prepare("
            SELECT t.*, ta.label AS account_label, ta.account_type
            FROM trades t
            JOIN trading_accounts ta ON ta.id = t.account_id
            WHERE t.user_id = :uid AND t.account_id = :aid
              AND t.status = 'closed'
              AND (t.is_reconciled IS NULL OR t.is_reconciled = 0)
              AND (t.is_validation = 0 OR t.is_validation IS NULL)
              AND t.deleted_at IS NULL
              AND t.captured_at BETWEEN DATE_SUB(:s, INTERVAL 1 DAY) AND DATE_ADD(:e, INTERVAL 1 DAY)
            ORDER BY t.captured_at DESC
            LIMIT 500
        ");
        $taStmt->execute([':uid' => $userId, ':aid' => $accId, ':s' => $b['s'], ':e' => $b['e']]);
        foreach ($taStmt->fetchAll(PDO::FETCH_ASSOC) as $t) {
            $unmatchedTa[] = $t;
        }
    }
}

// ── Server-side helpers ─────────────────────────────────────────────

function resolveMatchPair(PDO $pdo, string $userId, string $unmatchedId, string $taId, string $accountId): array
{
    $stmt = $pdo->prepare("SELECT raw_broker_row FROM unmatched_broker_trades WHERE id = :id AND user_id = :uid AND account_id = :aid AND resolution = 'unresolved'");
    $stmt->execute([':id' => $unmatchedId, ':uid' => $userId, ':aid' => $accountId]);
    $row = $stmt->fetch(PDO::FETCH_ASSOC);
    if (!$row) return [false, 'That broker execution is no longer available.'];
    $mt5 = json_decode($row['raw_broker_row'], true);
    if (!$mt5) return [false, 'Broker execution data is corrupted.'];

    $reconciler = new MT5Reconciler($pdo, $userId, $accountId, null);
    $ok = $reconciler->applyReconciliation($taId, $mt5);
    if (!$ok) return [false, 'Could not apply reconciliation to that trade.'];

    $upd = $pdo->prepare("UPDATE unmatched_broker_trades SET resolution = 'linked_manually', resolved_trade_id = :tid, resolved_at = NOW() WHERE id = :id AND user_id = :uid");
    $upd->execute([':tid' => $taId, ':id' => $unmatchedId, ':uid' => $userId]);
    return [true, null];
}

/**
 * Creates a brand-new trades row from a real broker execution that was
 * never journaled - the recovery path for "I took the trade but forgot
 * to log it," not a way to fabricate history. Requires an account AND a
 * strategy (checklist_results.strategy_version_id is NOT NULL, so
 * neither this trade nor its lifecycle row can exist without one) and
 * is explicitly, honestly recorded as trade_source='broker' with an
 * empty checklist - this trade never actually went through the app's
 * real capture flow, and nothing here should pretend otherwise.
 */
function createTradeFromUnmatched(PDO $pdo, string $userId, string $unmatchedId, string $accountId, string $strategyVersionId): array
{
    $stmt = $pdo->prepare("SELECT * FROM unmatched_broker_trades WHERE id = :id AND user_id = :uid AND resolution = 'unresolved'");
    $stmt->execute([':id' => $unmatchedId, ':uid' => $userId]);
    $row = $stmt->fetch(PDO::FETCH_ASSOC);
    if (!$row) return [false, 'That broker execution is no longer available.'];
    $mt5 = json_decode($row['raw_broker_row'], true);
    if (!$mt5) return [false, 'Broker execution data is corrupted.'];

    $acctCheck = $pdo->prepare('SELECT id FROM trading_accounts WHERE id = :id AND user_id = :uid AND deleted_at IS NULL');
    $acctCheck->execute([':id' => $accountId, ':uid' => $userId]);
    if (!$acctCheck->fetch()) return [false, 'Account not found.'];

    $svCheck = $pdo->prepare('SELECT sv.id FROM strategy_versions sv JOIN strategies s ON s.id = sv.strategy_id WHERE sv.id = :id AND sv.user_id = :uid AND s.deleted_at IS NULL');
    $svCheck->execute([':id' => $strategyVersionId, ':uid' => $userId]);
    if (!$svCheck->fetch()) return [false, 'Strategy not found.'];

    $tradeId = null;
    try {
        $pdo->beginTransaction();

        $lifecycleId = strtolower(bin2hex(random_bytes(16)));
        $lifecycleId = sprintf('%s-%s-%s-%s-%s', substr($lifecycleId,0,8), substr($lifecycleId,8,4), substr($lifecycleId,12,4), substr($lifecycleId,16,4), substr($lifecycleId,20,12));

        $pdo->prepare("
            INSERT INTO checklist_results (id, trade_lifecycle_id, user_id, strategy_version_id, items_ticked, items_required, ticked_pct, status, ticked_at, expires_at)
            VALUES (UUID(), :lifecycle_id, :uid, :svid, '[]', '[]', 0.00, 'completed', NOW(), NOW())
        ")->execute([':lifecycle_id' => $lifecycleId, ':uid' => $userId, ':svid' => $strategyVersionId]);

        $direction = ($mt5['type'] ?? 'long') === 'short' ? 'short' : 'long';
        $netted = (float)($mt5['profit'] ?? 0) + (float)($mt5['commission'] ?? 0) + (float)($mt5['swap'] ?? 0);
        $closeTime = $mt5['close_time'] ?? $mt5['time'] ?? date('Y-m-d H:i:s');

        $tradeId = strtolower(bin2hex(random_bytes(16)));
        $tradeId = sprintf('%s-%s-%s-%s-%s', substr($tradeId,0,8), substr($tradeId,8,4), substr($tradeId,12,4), substr($tradeId,16,4), substr($tradeId,20,12));

        $pdo->prepare("
            INSERT INTO trades (
                id, trade_lifecycle_id, user_id, trade_source, account_id, strategy_version_id,
                instrument, direction, entry_price, sl_price, tp_price,
                actual_entry_price, actual_exit_price, actual_lots, lots_per_position,
                broker_pnl, broker_open_time, broker_close_time, broker_lot_size,
                broker_entry_price, broker_exit_price, broker_sl_price, broker_commission, broker_swap,
                mt5_position_id, captured_at, opened_at, closed_at, status,
                is_reconciled, reconciled_at
            ) VALUES (
                :id, :lifecycle_id, :uid, 'broker', :account_id, :svid,
                :instrument, :direction, :entry_price, :sl_price, :tp_price,
                :actual_entry, :actual_exit, :actual_lots, :lots,
                :broker_pnl, :open_time, :close_time, :lot_size,
                :b_entry, :b_exit, :b_sl, :commission, :swap,
                :position_id, :captured_at, :opened_at, :closed_at, 'closed',
                1, NOW()
            )
        ")->execute([
            ':id' => $tradeId, ':lifecycle_id' => $lifecycleId, ':uid' => $userId,
            ':account_id' => $accountId, ':svid' => $strategyVersionId,
            ':instrument' => $mt5['symbol'] ?? '', ':direction' => $direction,
            ':entry_price' => (float)($mt5['price'] ?? 0), ':sl_price' => (float)($mt5['sl'] ?? 0),
            ':tp_price' => isset($mt5['tp']) && $mt5['tp'] !== null ? (float)$mt5['tp'] : null,
            ':actual_entry' => (float)($mt5['price'] ?? 0),
            ':actual_exit' => isset($mt5['close_price']) && $mt5['close_price'] !== null ? (float)$mt5['close_price'] : null,
            ':actual_lots' => (float)($mt5['volume'] ?? 0), ':lots' => (float)($mt5['volume'] ?? 0),
            ':broker_pnl' => $netted, ':open_time' => $mt5['time'] ?? null, ':close_time' => $mt5['close_time'] ?? null,
            ':lot_size' => (float)($mt5['volume'] ?? 0),
            ':b_entry' => (float)($mt5['price'] ?? 0),
            ':b_exit' => isset($mt5['close_price']) && $mt5['close_price'] !== null ? (float)$mt5['close_price'] : null,
            ':b_sl' => isset($mt5['sl']) && $mt5['sl'] !== null ? (float)$mt5['sl'] : null,
            ':commission' => $mt5['commission'] ?? null, ':swap' => $mt5['swap'] ?? null,
            ':position_id' => (string)($mt5['ticket'] ?? ''),
            ':captured_at' => $mt5['time'] ?? date('Y-m-d H:i:s'), ':opened_at' => $mt5['time'] ?? null, ':closed_at' => $closeTime,
        ]);

        $pdo->prepare("UPDATE unmatched_broker_trades SET resolution = 'linked_manually', resolved_trade_id = :tid, resolved_at = NOW() WHERE id = :id AND user_id = :uid")
            ->execute([':tid' => $tradeId, ':id' => $unmatchedId, ':uid' => $userId]);

        $pdo->commit();
    } catch (\Throwable $e) {
        $pdo->rollBack();
        error_log('mt5-resolve create_trade failed: ' . $e->getMessage());
        return [false, 'A database error occurred.'];
    }

    try {
        TradeClassificationEngine::classifyOneTrade($tradeId, $pdo);
    } catch (\Throwable $e) {
        error_log('TradeClassificationEngine failed for new broker trade: ' . $e->getMessage());
    }

    return [true, null];
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>MT5 Resolution - TraderAlign</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet">
<link rel="stylesheet" href="/traderalign/assets/tokens.css">
<link rel="icon" type="image/png" sizes="32x32" href="/traderalign/assets/favicon/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/traderalign/assets/favicon/favicon-16.png">
<link rel="apple-touch-icon" sizes="180x180" href="/traderalign/assets/favicon/apple-touch-icon.png">
<link rel="shortcut icon" href="/traderalign/assets/favicon/favicon.ico">
<link rel="stylesheet" href="/traderalign/assets/css/brand.css">
<style>
.dash-layout{display:flex;min-height:100vh}
.sidebar{width:4rem;background:var(--sidebar);border-right:1px solid var(--sidebar-border);display:flex;flex-direction:column;align-items:center;padding-top:1rem;gap:.25rem;position:fixed;top:0;left:0;bottom:0;z-index:40}
.sidebar a{display:flex;align-items:center;justify-content:center;width:2.75rem;height:2.75rem;border-radius:var(--radius-md);color:var(--foreground-dim);transition:background var(--t-fast),color var(--t-fast);position:relative}
.sidebar a:hover{background:var(--background-surface);color:var(--foreground)}
.sidebar a.active{background:var(--background-surface);color:var(--sidebar-primary)}
.sidebar a .tt{position:absolute;left:3.5rem;background:var(--popover);color:var(--foreground);font-size:.75rem;padding:.25rem .625rem;border-radius:var(--radius-sm);white-space:nowrap;pointer-events:none;opacity:0;transition:opacity var(--t-fast)}
.sidebar a:hover .tt{opacity:1}
.main{margin-left:4rem;flex:1;padding:2rem;max-width:calc(100vw - 4rem)}
.page-header{display:flex;align-items:flex-start;justify-content:space-between;margin-bottom:1.5rem;flex-wrap:wrap;gap:.75rem}
.page-header-left{display:flex;flex-direction:column;gap:.2rem}
.page-title{font-size:1.5rem;font-weight:700;color:var(--foreground);display:flex;align-items:center;gap:.5rem}
.page-sub{color:var(--foreground-muted);font-size:.875rem}
.message{padding:.75rem 1rem;border-radius:var(--radius-md);font-size:.85rem;margin-bottom:1.25rem;line-height:1.5}
.message.success{background:color-mix(in srgb,var(--positive) 10%,transparent);border:1px solid color-mix(in srgb,var(--positive) 22%,transparent);color:var(--positive)}
.message.error{background:color-mix(in srgb,var(--negative) 10%,transparent);border:1px solid color-mix(in srgb,var(--negative) 22%,transparent);color:var(--negative)}
.message.warning{background:color-mix(in srgb,var(--warning) 10%,transparent);border:1px solid color-mix(in srgb,var(--warning) 22%,transparent);color:var(--warning)}
.tier-badge{display:inline-block;font-size:.63rem;font-weight:700;padding:.18rem .55rem;border-radius:var(--radius-full);text-transform:uppercase;letter-spacing:.04em}
.tier-badge.pro{background:color-mix(in srgb,var(--warning) 15%,transparent);color:var(--warning);border:1px solid color-mix(in srgb,var(--warning) 30%,transparent)}
.tier-badge.elite{background:color-mix(in srgb,var(--positive) 15%,transparent);color:var(--positive);border:1px solid color-mix(in srgb,var(--positive) 30%,transparent)}
.tier-badge.ultimate{background:linear-gradient(135deg,var(--primary),var(--positive));color:#fff;border:1px solid transparent}
.tier-badge.free{background:var(--background-surface);color:var(--foreground-dim);border:1px solid var(--border)}
.account-filter{display:flex;gap:.5rem;align-items:center;margin-bottom:1.25rem;flex-wrap:wrap}
.account-filter select{height:2.1rem;padding:0 .6rem;background:var(--background-surface);border:1px solid var(--border);border-radius:var(--radius-sm);color:var(--foreground);font-size:.8rem}
.resolution-container{display:grid;grid-template-columns:1fr 60px 1fr;gap:1rem;align-items:start}
.resolution-column{background:var(--background-elevated);border:1px solid var(--border);border-radius:var(--radius-xl);overflow:hidden}
.column-header{padding:1rem 1.25rem;border-bottom:1px solid var(--border);display:flex;align-items:center;justify-content:space-between;background:var(--background-surface)}
.column-title{font-size:.9rem;font-weight:700;color:var(--foreground)}
.column-count{font-size:.7rem;color:var(--foreground-dim);background:var(--background);padding:.15rem .55rem;border-radius:var(--radius-full);font-family:var(--font-mono)}
.column-body{max-height:600px;overflow-y:auto;padding:.5rem}
.trade-card{background:var(--background);border:2px solid var(--border);border-radius:var(--radius-md);padding:.75rem 1rem;margin-bottom:.4rem;cursor:pointer;transition:all var(--t-fast);position:relative}
.trade-card:hover{border-color:var(--foreground-dim)}
.trade-card.mt5-selected{border-color:#60A5FA !important;background:color-mix(in srgb,#60A5FA 8%,transparent)}
.trade-card.ta-selected{border-color:#34D399 !important;background:color-mix(in srgb,#34D399 8%,transparent)}
.tc-main{display:flex;justify-content:space-between;align-items:baseline;margin-bottom:.35rem;gap:.5rem}
.tc-ticket{font-family:var(--font-mono);font-size:.75rem;color:var(--foreground-dim)}
.tc-symbol{font-size:.9rem;font-weight:700;color:var(--foreground)}
.tc-type{font-size:.7rem;font-weight:600;padding:.1rem .45rem;border-radius:var(--radius-full)}
.tc-type.long{background:color-mix(in srgb,var(--positive) 15%,transparent);color:var(--positive)}
.tc-type.short{background:color-mix(in srgb,var(--negative) 15%,transparent);color:var(--negative)}
.tc-details{display:flex;gap:.75rem;flex-wrap:wrap;font-size:.7rem;color:var(--foreground-muted);margin-bottom:.3rem}
.tc-detail-label{color:var(--foreground-dim)}
.tc-detail-value{font-family:var(--font-mono);color:var(--foreground)}
.tc-pnl{font-family:var(--font-mono);font-size:.85rem;font-weight:700;text-align:right}
.tc-time{font-size:.65rem;color:var(--foreground-dim);margin-top:.2rem}
.tc-account{font-size:.65rem;color:var(--foreground-dim)}
.center-actions{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.75rem;padding-top:3rem;position:sticky;top:2rem}
.btn{display:inline-flex;align-items:center;gap:.4rem;padding:.55rem 1rem;font-size:.78rem;font-weight:600;border-radius:var(--radius-md);border:none;cursor:pointer;transition:all var(--t-fast);font-family:inherit;white-space:nowrap;width:100%;justify-content:center}
.btn-primary{background:var(--primary);color:#fff}
.btn-primary:hover:not(:disabled){filter:brightness(1.1)}
.btn-primary:disabled{opacity:.4;cursor:not-allowed}
.btn-success{background:var(--positive);color:#fff}
.btn-success:hover:not(:disabled){filter:brightness(1.1)}
.btn-warning{background:var(--warning);color:#000}
.btn-secondary{background:var(--background-surface);color:var(--foreground);border:1px solid var(--border)}
.btn-ghost{background:transparent;color:var(--foreground-muted);border:1px solid var(--border)}
.btn-danger{background:var(--negative);color:#fff}
.btn-sm{padding:.35rem .7rem;font-size:.7rem;width:auto}
.action-bar{display:flex;gap:.5rem;align-items:center;margin-top:1.5rem;flex-wrap:wrap;padding:1rem;background:var(--background-elevated);border:1px solid var(--border);border-radius:var(--radius-lg)}
.action-bar-label{font-size:.72rem;font-weight:600;color:var(--foreground-dim);text-transform:uppercase;letter-spacing:.03em;margin-right:.5rem}
.modal-overlay{display:none;position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(0,0,0,.6);z-index:100;align-items:center;justify-content:center}
.modal-overlay.show{display:flex}
.modal{background:var(--background-elevated);border:1px solid var(--border);border-radius:var(--radius-xl);padding:1.5rem;max-width:500px;width:90%;max-height:80vh;overflow-y:auto}
.modal-title{font-size:1rem;font-weight:700;color:var(--foreground);margin-bottom:1rem}
.modal-body{margin-bottom:1.25rem}
.modal-actions{display:flex;gap:.5rem;justify-content:flex-end}
.form-group{margin-bottom:1rem}
.form-group label{display:block;font-size:.72rem;font-weight:600;color:var(--foreground-dim);text-transform:uppercase;letter-spacing:.03em;margin-bottom:.3rem}
.form-group select,.form-group input{width:100%;height:2.25rem;padding:0 .6rem;background:var(--background);border:1px solid var(--border);border-radius:var(--radius-sm);color:var(--foreground);font-size:.8rem;font-family:inherit}
.empty-state{text-align:center;padding:3rem 1rem;color:var(--foreground-dim)}
.empty-state-icon{font-size:2.5rem;margin-bottom:.75rem}
.empty-state h3{font-size:1rem;color:var(--foreground);margin-bottom:.5rem}
.empty-state p{font-size:.8rem;line-height:1.5}
.positive{color:var(--positive)}
.negative{color:var(--negative)}
.ghost-note{font-size:.68rem;color:var(--foreground-dim);margin-top:.2rem;font-style:italic}
@media(max-width:1024px){.resolution-container{grid-template-columns:1fr}.center-actions{flex-direction:row;padding-top:0;order:-1;flex-wrap:wrap;position:static}.center-actions .btn{width:auto;flex:1;min-width:120px}}
@media(max-width:768px){.main{padding:1rem}.column-body{max-height:350px}.btn{font-size:.72rem}}
</style>
</head>
<body class="dash-layout">

<?php require __DIR__ . '/sidebar.php'; ?>

<main class="main">
    <div class="page-header">
        <div class="page-header-left">
            <h1 class="page-title">MT5 Resolution <span class="tier-badge <?= htmlspecialchars($tier) ?>"><?= ucfirst($tier) ?></span></h1>
            <p class="page-sub">Trades your broker executed but you never journaled, and trades you journaled that your broker never confirms.</p>
        </div>
        <a href="/traderalign/mt5-upload" class="btn btn-secondary btn-sm" style="align-self:flex-start">← Back to Upload</a>
    </div>

    <?php if (!$hasAccess): ?>
    <div class="empty-state">
        <div class="empty-state-icon">🔒</div>
        <h3>Pro Tier Required</h3>
        <p>MT5 reconciliation requires a Pro subscription or higher.</p>
        <a href="/traderalign/pricing" class="btn btn-primary" style="margin-top:1rem;width:auto">View Plans →</a>
    </div>
    <?php else: ?>

    <?php if ($message): ?>
    <div class="message <?= $messageType ?>"><?= htmlspecialchars($message) ?></div>
    <?php endif; ?>

    <?php if (!empty($accounts)): ?>
    <form method="GET" class="account-filter">
        <label style="font-size:.75rem;color:var(--foreground-dim)">Account:</label>
        <select name="account_id" onchange="this.form.submit()">
            <option value="">All accounts with unresolved items</option>
            <?php foreach ($accounts as $a): ?>
            <option value="<?= htmlspecialchars($a['id']) ?>" <?= $selectedAccountId === $a['id'] ? 'selected' : '' ?>>
                <?= htmlspecialchars($a['label']) ?> (<?= htmlspecialchars(ucfirst($a['account_type'] ?? 'personal')) ?>)
            </option>
            <?php endforeach; ?>
        </select>
    </form>
    <?php endif; ?>

    <?php if (empty($unmatchedBroker) && empty($unmatchedTa)): ?>
    <div class="empty-state">
        <div class="empty-state-icon">✅</div>
        <h3>Nothing Left to Resolve</h3>
        <p>Every broker execution and journaled trade for this view is either matched, dismissed, or has no counterpart to review.</p>
        <a href="/traderalign/mt5-upload" class="btn btn-primary" style="margin-top:1rem;width:auto">Upload Another Report →</a>
    </div>
    <?php else: ?>

    <div class="resolution-container" id="resolutionContainer">
        <div class="resolution-column">
            <div class="column-header">
                <span class="column-title">🔴 Broker Executions Never Journaled</span>
                <span class="column-count"><?= count($unmatchedBroker) ?></span>
            </div>
            <div class="column-body" id="mt5TradeList">
                <?php foreach ($unmatchedBroker as $row):
                    $mt5 = $row['mt5'];
                    $netted = (float)($mt5['profit'] ?? 0) + (float)($mt5['commission'] ?? 0) + (float)($mt5['swap'] ?? 0);
                    $acctLabel = $accountsById[$row['account_id']]['label'] ?? 'Unknown account';
                ?>
                <div class="trade-card mt5-card"
                     data-unmatched-id="<?= htmlspecialchars($row['id']) ?>"
                     data-account-id="<?= htmlspecialchars($row['account_id']) ?>"
                     onclick="selectMT5Trade(this)">
                    <div class="tc-main">
                        <span class="tc-ticket">#<?= htmlspecialchars($mt5['ticket'] ?? '-') ?></span>
                        <span class="tc-symbol"><?= htmlspecialchars($mt5['symbol'] ?? '-') ?></span>
                        <span class="tc-type <?= ($mt5['type'] ?? 'long') === 'long' ? 'long' : 'short' ?>"><?= ucfirst($mt5['type'] ?? 'long') ?></span>
                    </div>
                    <div class="tc-details">
                        <span class="tc-detail-label">Vol:</span> <span class="tc-detail-value"><?= number_format($mt5['volume'] ?? 0, 2) ?></span>
                        <span class="tc-detail-label">Entry:</span> <span class="tc-detail-value"><?= number_format($mt5['price'] ?? 0, 5) ?></span>
                    </div>
                    <div class="tc-pnl <?= pnlClass($netted) ?>"><?= pnlFormat($netted) ?></div>
                    <div class="tc-time"><?= htmlspecialchars($mt5['time'] ?? '') ?></div>
                    <div class="tc-account"><?= htmlspecialchars($acctLabel) ?></div>
                    <div class="ghost-note">⚠ Your broker executed this - TraderAlign has no matching journal entry.</div>
                </div>
                <?php endforeach; ?>
                <?php if (empty($unmatchedBroker)): ?><div class="empty-state"><p style="font-size:.8rem">No unmatched broker executions</p></div><?php endif; ?>
            </div>
        </div>

        <div class="center-actions">
            <button class="btn btn-primary" id="matchBtn" disabled onclick="matchSelected()">↔ Match Selected</button>
            <button class="btn btn-success btn-sm" onclick="openCreateModal()">+ Journal This Execution</button>
            <button class="btn btn-warning btn-sm" onclick="dismissSelected('dismissed_ghost')">Dismiss (never happened here)</button>
            <button class="btn btn-ghost btn-sm" onclick="dismissSelected('dismissed_other_account')">Wrong Account</button>
        </div>

        <div class="resolution-column">
            <div class="column-header">
                <span class="column-title">🟡 Journaled Trades Never Confirmed By Broker</span>
                <span class="column-count"><?= count($unmatchedTa) ?></span>
            </div>
            <div class="column-body" id="taTradeList">
                <?php foreach ($unmatchedTa as $trade): ?>
                <div class="trade-card ta-card" data-ta-id="<?= htmlspecialchars($trade['id']) ?>" onclick="selectTATrade(this)">
                    <div class="tc-main">
                        <span class="tc-symbol"><?= htmlspecialchars($trade['instrument'] ?? '-') ?></span>
                        <span class="tc-type <?= ($trade['direction'] ?? 'long') === 'long' ? 'long' : 'short' ?>"><?= ucfirst($trade['direction'] ?? 'long') ?></span>
                    </div>
                    <div class="tc-details">
                        <span class="tc-detail-label">Lots:</span> <span class="tc-detail-value"><?= number_format($trade['lots_per_position'] ?? 0, 2) ?></span>
                        <span class="tc-detail-label">Entry:</span> <span class="tc-detail-value"><?= number_format($trade['entry_price'] ?? 0, 5) ?></span>
                    </div>
                    <div class="tc-pnl <?= pnlClass($trade['challenge_pnl'] ?? $trade['broker_pnl'] ?? $trade['projected_pnl'] ?? 0) ?>">
                        <?= pnlFormat($trade['challenge_pnl'] ?? $trade['broker_pnl'] ?? $trade['projected_pnl'] ?? 0) ?>
                    </div>
                    <div class="tc-time"><?= htmlspecialchars(date('Y-m-d H:i', strtotime($trade['captured_at'] ?? ''))) ?></div>
                    <div class="tc-account"><?= htmlspecialchars($trade['account_label'] ?? '') ?></div>
                    <div class="ghost-note">⚠ Journaled in TraderAlign - no matching execution found in this broker statement.</div>
                </div>
                <?php endforeach; ?>
                <?php if (empty($unmatchedTa)): ?><div class="empty-state"><p style="font-size:.8rem">No unconfirmed journal entries</p></div><?php endif; ?>
            </div>
        </div>
    </div>

    <div class="action-bar">
        <span class="action-bar-label">Bulk:</span>
        <form method="POST" style="display:contents" onsubmit="return confirm('Dismiss every unresolved broker execution in this view? This does not delete any TraderAlign trade.')">
            <?= Csrf::field() ?>
            <input type="hidden" name="account_id" value="<?= htmlspecialchars($selectedAccountId) ?>">
            <button type="submit" name="action" value="dismiss_all" class="btn btn-warning btn-sm">Dismiss All Unmatched Broker Executions</button>
        </form>
    </div>

    <?php endif; ?>
    <?php endif; ?>
</main>

<form method="POST" id="matchForm" style="display:none">
    <?= Csrf::field() ?>
    <input type="hidden" name="action" value="match_pair">
    <input type="hidden" name="unmatched_id" id="matchUnmatchedId">
    <input type="hidden" name="ta_id" id="matchTaId">
    <input type="hidden" name="account_id" id="matchAccountId">
</form>

<form method="POST" id="dismissForm" style="display:none">
    <?= Csrf::field() ?>
    <input type="hidden" name="action" value="dismiss">
    <input type="hidden" name="unmatched_id" id="dismissUnmatchedId">
    <input type="hidden" name="resolution" id="dismissResolution">
</form>

<div class="modal-overlay" id="createModal">
    <div class="modal">
        <div class="modal-title">Journal This Broker Execution</div>
        <div class="modal-body">
            <p style="font-size:.78rem;color:var(--foreground-dim);margin-bottom:1rem">
                This creates a real TraderAlign trade from broker data alone - no calculator plan, no checklist. Use this only to recover a trade you genuinely forgot to log.
            </p>
            <form method="POST" id="createForm">
                <?= Csrf::field() ?>
                <input type="hidden" name="action" value="create_trade">
                <input type="hidden" name="unmatched_id" id="createUnmatchedId">
                <div class="form-group">
                    <label for="createAccount">Trading Account</label>
                    <select name="account_id" id="createAccount" required>
                        <option value="">Select Account</option>
                        <?php foreach ($accounts as $acc): ?>
                        <option value="<?= htmlspecialchars($acc['id']) ?>"><?= htmlspecialchars($acc['label']) ?></option>
                        <?php endforeach; ?>
                    </select>
                </div>
                <div class="form-group">
                    <label for="createStrategy">Strategy (required)</label>
                    <select name="strategy_version_id" id="createStrategy" required>
                        <option value="">Select Strategy</option>
                        <?php foreach ($strategies as $strat): ?>
                        <option value="<?= htmlspecialchars($strat['current_version_id']) ?>"><?= htmlspecialchars($strat['name']) ?></option>
                        <?php endforeach; ?>
                    </select>
                </div>
            </form>
        </div>
        <div class="modal-actions">
            <button class="btn btn-secondary btn-sm" onclick="closeCreateModal()">Cancel</button>
            <button class="btn btn-primary btn-sm" onclick="submitCreateTrade()">Create Trade</button>
        </div>
    </div>
</div>

<script>
var selectedUnmatchedId = null, selectedAccountId = null, selectedTAId = null;

function selectMT5Trade(card) {
    document.querySelectorAll('.mt5-card').forEach(c => c.classList.remove('mt5-selected'));
    card.classList.add('mt5-selected');
    selectedUnmatchedId = card.getAttribute('data-unmatched-id');
    selectedAccountId = card.getAttribute('data-account-id');
    updateMatchButton();
}
function selectTATrade(card) {
    document.querySelectorAll('.ta-card').forEach(c => c.classList.remove('ta-selected'));
    card.classList.add('ta-selected');
    selectedTAId = card.getAttribute('data-ta-id');
    updateMatchButton();
}
function updateMatchButton() {
    document.getElementById('matchBtn').disabled = !(selectedUnmatchedId && selectedTAId);
}
function matchSelected() {
    if (!selectedUnmatchedId || !selectedTAId) return;
    document.getElementById('matchUnmatchedId').value = selectedUnmatchedId;
    document.getElementById('matchTaId').value = selectedTAId;
    document.getElementById('matchAccountId').value = selectedAccountId;
    document.getElementById('matchForm').submit();
}
function dismissSelected(resolution) {
    if (!selectedUnmatchedId) { alert('Select a broker execution first.'); return; }
    var label = resolution === 'dismissed_other_account' ? 'mark as belonging to a different account' : 'dismiss this execution';
    if (!confirm('Are you sure you want to ' + label + '? This does not create or delete any trade.')) return;
    document.getElementById('dismissUnmatchedId').value = selectedUnmatchedId;
    document.getElementById('dismissResolution').value = resolution;
    document.getElementById('dismissForm').submit();
}
function openCreateModal() {
    if (!selectedUnmatchedId) { alert('Select a broker execution first.'); return; }
    document.getElementById('createUnmatchedId').value = selectedUnmatchedId;
    if (selectedAccountId) document.getElementById('createAccount').value = selectedAccountId;
    document.getElementById('createModal').classList.add('show');
}
function closeCreateModal() { document.getElementById('createModal').classList.remove('show'); }
function submitCreateTrade() {
    var f = document.getElementById('createForm');
    if (!f.account_id.value || !f.strategy_version_id.value) { alert('Select both an account and a strategy.'); return; }
    if (!confirm('Create a real TraderAlign trade from this broker execution alone?')) return;
    f.submit();
}
document.getElementById('createModal').addEventListener('click', function(e) { if (e.target === this) closeCreateModal(); });
</script>
</body>
</html>
