<?php
/**
 * MT5 Report Parser API
 * POST /api/mt5/parse
 *
 * Rebuilt 2026-08-19 against Kevin's own real, downloaded MT5 statements
 * (Maven Trade + HFM, both HTML and XLSX). The old implementation here
 * never handled MT5's real UTF-16LE encoding at all - it silently
 * returned 0 trades with no error for every genuine MT5 export - and
 * never accepted .xlsx uploads in the first place. See
 * src/Mt5ReportParser.php's own header comment for the full account of
 * what was actually wrong and how it was confirmed.
 *
 * This endpoint now:
 *   - Accepts real .xlsx exports, not just .html/.htm/.csv.
 *   - Requires an account_id up front (not optional) - a statement with
 *     no account context to reconcile against, and no durable record of
 *     who it belongs to, is exactly the kind of "imported nothing was
 *     ever saved against" gap this whole pass exists to close.
 *   - Cross-checks the statement's OWN embedded MT5 account number/
 *     currency against the selected TraderAlign account's saved
 *     account_number/currency, and reports the mismatch plainly rather
 *     than silently reconciling the wrong account's history.
 *   - Persists a real broker_reconciliations row (and saves the actual
 *     uploaded file to disk, outside the webroot's servable area - see
 *     data/.htaccess) the moment a statement is successfully parsed, so
 *     "what was uploaded, when, against which account" survives even if
 *     the trader never clicks through to reconcile.
 */

error_reporting(E_ALL);
ini_set('display_errors', 0);

try {
    require_once __DIR__ . '/../../config/config.php';
    require_once __DIR__ . '/../../src/ScopedDb.php';
    require_once __DIR__ . '/../../src/Auth.php';
    require_once __DIR__ . '/../../src/PropFirmHelpers.php';
    require_once __DIR__ . '/../../src/Mt5ReportParser.php';
    require_once __DIR__ . '/../../src/Csrf.php';

    $auth = new Auth($pdo);
    $userId = $auth->requireAuth();

    $tier = 'free';
    try {
        $stmt = $pdo->prepare('SELECT tier FROM user_profiles WHERE user_id = :uid LIMIT 1');
        $stmt->execute([':uid' => $userId]);
        $row = $stmt->fetch(PDO::FETCH_ASSOC);
        if ($row && !empty($row['tier'])) $tier = $row['tier'];
    } catch (\Throwable $e) {}

    if (!in_array($tier, ['pro', 'elite', 'ultimate'], true)) {
        sendJson(403, ['success' => false, 'error' => 'Pro tier required.']);
    }

    if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
        sendJson(405, ['success' => false, 'error' => 'Use POST.']);
    }

    if (!Csrf::verify()) {
        sendJson(403, ['success' => false, 'error' => 'Your session expired - please refresh the page and try again.']);
    }

    if (!isset($_FILES['file']) || $_FILES['file']['error'] !== UPLOAD_ERR_OK) {
        sendJson(400, ['success' => false, 'error' => 'Upload failed.']);
    }

    $accountId = trim((string)($_POST['account_id'] ?? ''));
    if ($accountId === '') {
        sendJson(400, ['success' => false, 'error' => 'Select which TraderAlign account this statement belongs to before uploading.']);
    }

    $stmt = $pdo->prepare('SELECT id, label, account_type, currency, account_number, broker_login, broker_server FROM trading_accounts WHERE id = :id AND user_id = :uid AND deleted_at IS NULL LIMIT 1');
    $stmt->execute([':id' => $accountId, ':uid' => $userId]);
    $account = $stmt->fetch(PDO::FETCH_ASSOC);
    if (!$account) {
        sendJson(404, ['success' => false, 'error' => 'That account was not found.']);
    }

    $file = $_FILES['file'];
    $ext = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));

    if (!in_array($ext, ['html', 'htm', 'csv', 'xlsx'], true)) {
        sendJson(400, ['success' => false, 'error' => 'Invalid file type: .' . $ext . ' - upload the .html, .htm, .csv, or .xlsx report exported from MT5.']);
    }

    if ($file['size'] > MT5_MAX_FILE_SIZE) {
        sendJson(400, ['success' => false, 'error' => 'File too large (max ' . round(MT5_MAX_FILE_SIZE / 1024 / 1024) . 'MB).']);
    }

    // Content-inspection allowlist (same discipline as the screenshot
    // upload path - never trust the filename's extension alone). A real
    // .xlsx is a ZIP container, which finfo correctly reports as either
    // the OOXML spreadsheet MIME type or, on some libmagic builds, the
    // generic application/zip - both are accepted here since both are
    // genuinely produced by real Office/MT5-generated .xlsx files.
    $finfo = finfo_open(FILEINFO_MIME_TYPE);
    $detectedMime = finfo_file($finfo, $file['tmp_name']);
    finfo_close($finfo);
    $allowedMimes = [
        'text/html', 'text/csv', 'text/plain', 'application/csv', 'text/xml', 'application/xml',
        'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'application/zip',
    ];
    if (!in_array($detectedMime, $allowedMimes, true)) {
        sendJson(400, ['success' => false, 'error' => 'This file does not look like a valid MT5 report.']);
    }
    if ($ext === 'xlsx' && !in_array($detectedMime, ['application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'application/zip'], true)) {
        sendJson(400, ['success' => false, 'error' => 'This .xlsx file does not look like a real Excel file.']);
    }

    $content = file_get_contents($file['tmp_name']);
    unlink($file['tmp_name']);

    if (empty(trim($content))) {
        sendJson(400, ['success' => false, 'error' => 'File is empty.']);
    }

    $result = Mt5ReportParser::parse($content, $ext);

    if (!$result['success']) {
        // Audit trail for rejected uploads - never anything about the
        // file's actual content, only who/what/when, so this is safe to
        // keep even if the rejected content was something inappropriate.
        // Lets a real "someone keeps trying to upload the wrong thing" or
        // "someone is probing this endpoint" pattern actually be noticed.
        error_log(sprintf(
            'mt5/parse.php: rejected upload (not a genuine MT5 report) - user=%s account=%s ext=%s size=%d reason=%s',
            $userId, $accountId, $ext, strlen($content), $result['error']
        ));
        sendJson(422, ['success' => false, 'error' => $result['error']]);
    }

    // ── Cross-check statement identity against the selected account ──
    // See Mt5ReportParser::matchAccountIdentity()'s own docblock for why
    // the old currency-only fallback here was a real, confirmed-live bug
    // (a genuine cross-account upload was reported as "matches: true").
    // This is only the first, fast opinion shown to the trader right
    // after upload - api/mt5/reconcile.php independently re-derives the
    // same check from the SAVED FILE (never trusts this response) before
    // it will actually reconcile anything.
    $accountMatch = Mt5ReportParser::matchAccountIdentity($result['account'], $account['account_number'], $account['broker_server'], $account['broker_login']);
    $accountMatch['statement_currency'] = $result['account']['currency'] ?? null;
    $accountMatch['saved_currency'] = $account['currency'];

    // ── Determine statement period from the actual position data ──
    $times = [];
    foreach ($result['positions'] as $p) {
        if (!empty($p['time'])) $times[] = $p['time'];
        if (!empty($p['close_time'])) $times[] = $p['close_time'];
    }
    sort($times);
    $periodStart = $times[0] ?? null;
    $periodEnd = end($times) ?: null;

    // ── Persist the upload itself (audit trail - survives even if the
    // trader never clicks "Reconcile") ──
    $reconciliationId = null;
    try {
        $uploadDir = __DIR__ . '/../../data/mt5-uploads/' . $userId;
        if (!is_dir($uploadDir)) @mkdir($uploadDir, 0755, true);
        $reconciliationId = bin2hex(random_bytes(16));
        $reconciliationId = sprintf('%s-%s-%s-%s-%s',
            substr($reconciliationId, 0, 8), substr($reconciliationId, 8, 4),
            substr($reconciliationId, 12, 4), substr($reconciliationId, 16, 4), substr($reconciliationId, 20, 12));
        $savedFile = $uploadDir . '/' . $reconciliationId . '.' . $ext;
        @file_put_contents($savedFile, $content);

        $insert = $pdo->prepare('
            INSERT INTO broker_reconciliations (
                id, user_id, account_id, source_file_url, source_file_format,
                broker_rows_parsed, rows_matched_a, rows_matched_b, rows_unmatched, journal_unmatched,
                statement_period_start, statement_period_end, uploaded_at
            ) VALUES (
                :id, :uid, :account_id, :src, :fmt,
                :parsed, 0, 0, 0, 0,
                :pstart, :pend, NOW()
            )
        ');
        $insert->execute([
            ':id' => $reconciliationId,
            ':uid' => $userId,
            ':account_id' => $accountId,
            ':src' => 'data/mt5-uploads/' . $userId . '/' . $reconciliationId . '.' . $ext,
            ':fmt' => $ext === 'xlsx' ? 'mt5_html' : ($ext === 'csv' ? 'mt5_csv' : 'mt5_html'),
            ':parsed' => count($result['positions']),
            ':pstart' => $periodStart,
            ':pend' => $periodEnd,
        ]);
    } catch (\Throwable $e) {
        error_log('mt5/parse.php: failed to persist broker_reconciliations row: ' . $e->getMessage());
        // Non-fatal - the trader can still review/reconcile this upload in
        // this session even if the durable audit record failed to write.
    }

    sendJson(200, [
        'success' => true,
        'reconciliation_id' => $reconciliationId,
        'account_id' => $accountId,
        'account_label' => $account['label'],
        'statement_account' => $result['account'],
        'account_match' => $accountMatch,
        'positions' => $result['positions'],
        'deals_count' => count($result['deals']),
        'balance_events' => $result['balance_events'],
        'orders_count' => count($result['orders']),
        'report_summary' => $result['report_summary'],
        'warnings' => $result['warnings'],
        'is_empty_statement' => $result['is_empty_statement'],
        'count' => count($result['positions']),
    ]);

} catch (\Throwable $e) {
    error_log('mt5/parse.php failed: ' . $e->getMessage() . ' at line ' . $e->getLine());
    sendJson(500, ['success' => false, 'error' => 'Failed to parse the MT5 report. Please check the file and try again.']);
}

function sendJson(int $code, array $data): void {
    http_response_code($code);
    header('Content-Type: application/json');
    echo json_encode($data, JSON_PARTIAL_OUTPUT_ON_ERROR | JSON_UNESCAPED_UNICODE);
    exit;
}
