<?php
header('Content-Type: application/json');

require_once __DIR__ . '/../../config/config.php';

$dsn = "mysql:host=" . DB_HOST . ";port=" . DB_PORT . ";dbname=" . DB_NAME . ";charset=utf8mb4";
$pdo = new PDO($dsn, DB_USER, DB_PASS, [
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
]);

require_once __DIR__ . '/../../src/Auth.php';
require_once __DIR__ . '/../../src/ScopedDb.php';
require_once __DIR__ . '/../../src/JourneySegmentation.php';
require_once __DIR__ . '/../../src/PropFirmRuleEngine.php';

if (session_status() === PHP_SESSION_NONE) {
    if (defined('SESSION_NAME')) session_name(SESSION_NAME);
    session_start();
}

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

$accountId = $_GET['account_id'] ?? '';
if (!$accountId) {
    echo json_encode(['error' => 'account_id required']);
    exit;
}

$account = $db->selectById('trading_accounts', $accountId);
if (!$account || $account['user_id'] !== $userId) {
    echo json_encode(['error' => 'account not found']);
    exit;
}

$challenge = null;
try {
    $stmt = $pdo->prepare("SELECT * FROM challenge_accounts WHERE account_id = :aid ORDER BY created_at DESC LIMIT 1");
    $stmt->execute([':aid' => $accountId]);
    $challenge = $stmt->fetch(PDO::FETCH_ASSOC);
} catch (\Throwable $e) {}

// PropFirmRuleEngine is the single source of truth for phase-aware
// balance/drawdown/rules-cascade as of 2026-08-08 — see
// docs/architecture/SINGLE_SOURCE_OF_TRUTH_AUDIT.md §1c/§2c/§6 (cascade
// #5) and the PROPOSAL/MIGRATION_PLAN docs. This file's own former inline
// JourneySegmentation computation (a real, correct 2026-08-07 fix in its
// own right — see git history) was architecturally a SEPARATE copy of the
// exact same formula PropFirmRuleEngine::compute() now owns; a second,
// independently-maintained implementation of the phase-reset-aware
// balance rule is exactly the failure mode the multi-session balance
// incident (CLAUDE.md's "Single Source of Truth Rule") documents. Two
// real bugs this repoint additionally closes that the prior fix never
// touched: (a) this endpoint's own drawdown_pct was unclamped/signed —
// an in-profit account showed a NEGATIVE drawdown% here while every
// other page (getChallengeMetrics(), Reports, Journal) showed a flat,
// clamped-at-zero 0%; (b) this endpoint's own rules display
// (max_dd_pct/daily_dd_pct/profit_target_pct below) read ONLY flat
// rules[...] keys, with profit_target_pct falling back to phase_1's key
// at best — so a Phase-2/Phase-3 account with a genuinely different
// declared target than Phase 1 showed the WRONG number in the
// Calculator's breach/pass popups (openBreachPopup/openPassedPopup, see
// calculator-source.html).
//
// Personal/live accounts have no phase concept and no challenge_accounts
// row — trading_accounts.current_balance (continuous, never reset) stays
// the correct, real balance for them, unchanged.
$propFirmMetrics = null;
if ($account['account_type'] === 'prop_firm' && $challenge) {
    $pfr = PropFirmRuleEngine::compute($accountId);
    if (!isset($pfr['error'])) {
        $propFirmMetrics = $pfr;
    }
}

if ($propFirmMetrics) {
    $currentBalance = $propFirmMetrics['phase_balance'];
} else {
    $currentBalance = (float)$account['current_balance'];
}

$startingBalance = (float)$account['starting_balance'];
if ($propFirmMetrics) {
    // Canonical, phase-anchored, clamped-at-zero — matches
    // getChallengeMetrics()['overall_drawdown']['current_percentage'].
    $drawdownPct = $propFirmMetrics['overall_drawdown']['current_percentage'];
} else {
    // Personal accounts: unchanged, unclamped/signed whole-ledger
    // drawdown — out of PropFirmRuleEngine's scope (no phase/breach
    // boundary concept applies to a live account).
    $drawdownPct = $startingBalance > 0 ? round(($startingBalance - $currentBalance) / $startingBalance * 100, 2) : 0;
}

$rules = $challenge ? json_decode($challenge['rules'] ?? '{}', true) : [];

// Phase-cascaded thresholds (PropFirmRuleEngine::resolveRules()'s same
// cascade getChallengeMetrics()/validate.php now use) replace this
// endpoint's former flat-key-only reads — was the audit's confirmed
// cascade-#5 divergence: profit_target_pct only ever checked the flat
// key or phase_1's, so a Phase-2/Phase-3 account's real declared target
// never reached openPassedPopup()'s displayed text. max_dd_pct/
// daily_dd_pct are read here purely for display (this endpoint performs
// no breach/pass decision of its own — see calculator-source.html's own
// comment: "the calculator never decides breach/pass status itself").
// leverage is unrelated to this cascade (an account setting, not a
// boundary threshold) and is left reading the flat rules key unchanged.
$maxDdPct = $propFirmMetrics ? $propFirmMetrics['phase']['max_overall_loss_pct'] : ($rules['max_dd_pct'] ?? null);
$dailyDdPct = $propFirmMetrics ? $propFirmMetrics['phase']['max_daily_loss_pct'] : ($rules['daily_dd_pct'] ?? null);
$profitTargetPct = $propFirmMetrics
    ? $propFirmMetrics['phase']['profit_target_pct']
    : ($rules['profit_target_pct'] ?? $rules['phase_1_target_pct'] ?? null);

echo json_encode([
    'current_balance' => $currentBalance,
    'starting_balance' => $startingBalance,
    'drawdown_pct' => $drawdownPct,
    'phase' => $challenge['lifecycle_state'] ?? $account['lifecycle_state'] ?? null,
    'account_status' => $challenge['lifecycle_state'] ?? $account['lifecycle_state'] ?? null,
    'current_outcome' => $challenge['current_outcome'] ?? $account['current_outcome'] ?? null,
    'boundary_event' => $challenge['boundary_event'] ?? $account['boundary_event'] ?? null,
    'breached_at' => $challenge['breached_at'] ?? null,
    'passed_at' => $challenge['passed_at'] ?? null,
    'max_dd_pct' => $maxDdPct,
    'daily_dd_pct' => $dailyDdPct,
    'profit_target_pct' => $profitTargetPct,
    // Single Source of Truth consolidation — the real dollar breach floor,
    // straight from PropFirmRuleEngine::compute(). calculator-source.html
    // used to re-derive this itself (startBal * (1 - maxDDPct/100)) purely
    // to log it in openBreachPopup()'s console.info() line — a duplicate
    // of the exact formula this endpoint already computes internally to
    // derive max_dd_pct above, and one that can only ever be correct for
    // a Fixed drawdown model (a Trailing/Smart floor isn't derivable from
    // starting_balance + a flat percentage in the browser). Exposing the
    // real, already-computed figure here removes that duplicate outright.
    // null for a non-prop-firm account or one with no challenge_accounts
    // row — same null-safety as max_dd_pct/daily_dd_pct above.
    'breach_level_amount' => $propFirmMetrics['overall_drawdown']['breach_level_amount'] ?? null,
    // Maximum Loss Model (2026-08-17) — 'fixed'|'trailing'|null (personal
    // account / no challenge data). breach_level_amount above is already
    // fully model-aware via PropFirmRuleEngine — this field is purely
    // disclosure, so a UI can label the figure correctly.
    'max_loss_model' => $propFirmMetrics['overall_drawdown']['max_loss_model'] ?? null,
    // The real dollar drawdown BUDGET (as opposed to breach_level_amount,
    // the floor balance itself) — ddReferenceBalance * max_dd_pct / 100,
    // already correctly anchored to starting_balance for Fixed or
    // peak_balance for Trailing by PropFirmRuleEngine. Added alongside
    // peak_balance below so calculator-source.html's offline fallback
    // (renderPropFirmFallback(), used only when a per-trade /api/trades/
    // validate call fails but this endpoint's own earlier page-load fetch
    // already succeeded) never has to re-derive it — deriving a Trailing
    // account's real limit from peak_balance/breach_level_amount alone
    // would be wrong for a Fixed account, since peak_balance isn't the
    // Fixed model's anchor.
    'max_dd_limit_amount' => $propFirmMetrics['overall_drawdown']['limit_amount'] ?? null,
    'peak_balance' => $propFirmMetrics['overall_drawdown']['peak_balance'] ?? null,
    'leverage' => $rules['leverage'] ?? '1:30',
    'account_label' => $account['label'] ?? null,
    // Account Currency / FX Single Source of Truth (2026-08-11) — the
    // account's own real currency (trading_accounts.currency), so the
    // Calculator can label the balance it just fetched correctly. This
    // endpoint does no pip-value/lot-size math (that's CalculatorEngine's
    // job, still USD-only for now — see CLAUDE.md's Currency/FX Domain
    // section), so labeling this balance display is safe regardless of
    // that deferred piece: it's a real, currency-native passthrough value.
    'account_currency' => $account['currency'] ?? 'USD',
]);