/home/devscfvi/AblePro/api.php
<?php
header('Content-Type: application/json');
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type');

// Handle preflight
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(200); exit; }

require_once 'config.php';
require_once 'auth_check.php';   // session start + requireAuth() + ensureAuthTables()

$pdo = getDBConnection();

// ── Bootstrap auth tables on first load ────────────────────
ensureAuthTables($pdo);

// ── Resolve current user (returns 0 for public actions) ────
$currentUserId = requireAuth();

// getInput() with body caching so it can be read twice
function getInput(): array {
    static $cached = null;
    if ($cached === null) {
        // Use the body cached by auth_check.php (stream already consumed there)
        $raw    = $GLOBALS['_request_body'] ?? file_get_contents('php://input');
        $cached = json_decode($raw, true) ?? [];
    }
    return $cached;
}

function sendJSON($data): void {
    echo json_encode($data);
    exit;
}

// ============================================
// GET REQUESTS
// ============================================

if ($_SERVER['REQUEST_METHOD'] === 'GET') {
    $action = $_GET['action'] ?? '';
    
    switch($action) {
        case 'getTrades':
            $mode = $_GET['mode'] ?? 'crypto';
            $stmt = $pdo->prepare("SELECT * FROM crypto_trades WHERE trade_mode = ? AND (user_id = ? OR user_id IS NULL) ORDER BY created_at DESC");
            $stmt->execute([$mode, $currentUserId ?: 0]);
            $trades = $stmt->fetchAll();
            // Decode screenshots JSON array for each trade
            foreach ($trades as &$t) {
                if (!empty($t['screenshots'])) {
                    $decoded = json_decode($t['screenshots'], true);
                    $t['screenshots'] = is_array($decoded) ? $decoded : [];
                } else {
                    $t['screenshots'] = [];
                }
            }
            unset($t);
            sendJSON(['success' => true, 'trades' => $trades]);

        case 'getStats':
            $mode = $_GET['mode'] ?? 'crypto';
            $stmt = $pdo->prepare("
                SELECT
                    COUNT(*) as total_trades,
                    SUM(CASE WHEN status = 'win' THEN 1 ELSE 0 END) as wins,
                    SUM(CASE WHEN status = 'loss' THEN 1 ELSE 0 END) as losses,
                    SUM(CASE WHEN status = 'pending' THEN 1 ELSE 0 END) as pending_trades,
                    SUM(CASE WHEN status = 'win' THEN profit_amount WHEN status = 'loss' THEN -loss_amount ELSE 0 END) as total_pnl,
                    AVG(reward_risk_ratio) as avg_rr,
                    ROUND(SUM(CASE WHEN status = 'win' THEN 1 ELSE 0 END) * 100.0 / NULLIF(SUM(CASE WHEN status IN ('win', 'loss') THEN 1 ELSE 0 END), 0), 2) as win_rate,
                    MAX(CASE WHEN status = 'win' THEN profit_amount ELSE 0 END) as best_win,
                    MAX(CASE WHEN status = 'loss' THEN loss_amount ELSE 0 END) as worst_loss
                FROM crypto_trades
                WHERE trade_mode = ? AND (user_id = ? OR user_id IS NULL)
            ");
            $stmt->execute([$mode, $currentUserId ?: 0]);
            $stats = $stmt->fetch();
            sendJSON(['success' => true, 'stats' => $stats]);

        case 'getAdvancedAnalytics':
            $mode = $_GET['mode'] ?? 'crypto';

            // Performance by category (mode-filtered inline query)
            $stmt = $pdo->prepare("
                SELECT
                    trade_category as category,
                    COUNT(*) as total,
                    SUM(CASE WHEN status = 'win' THEN 1 ELSE 0 END) as wins,
                    SUM(CASE WHEN status = 'loss' THEN 1 ELSE 0 END) as losses,
                    ROUND(SUM(CASE WHEN status = 'win' THEN 1 ELSE 0 END) * 100.0 /
                          NULLIF(SUM(CASE WHEN status IN ('win', 'loss') THEN 1 ELSE 0 END), 0), 2) as win_rate,
                    SUM(CASE WHEN status = 'win' THEN profit_amount WHEN status = 'loss' THEN -loss_amount ELSE 0 END) as net_pnl
                FROM crypto_trades
                WHERE trade_category IS NOT NULL AND trade_mode = ?
                GROUP BY trade_category
            ");
            $stmt->execute([$mode]);
            $byCategory = $stmt->fetchAll();

            // Performance by coin/asset (mode-filtered)
            $stmt = $pdo->prepare("
                SELECT
                    coin,
                    COUNT(*) as total,
                    SUM(CASE WHEN status = 'win' THEN 1 ELSE 0 END) as wins,
                    SUM(CASE WHEN status = 'loss' THEN 1 ELSE 0 END) as losses,
                    ROUND(SUM(CASE WHEN status = 'win' THEN 1 ELSE 0 END) * 100.0 /
                          NULLIF(SUM(CASE WHEN status IN ('win', 'loss') THEN 1 ELSE 0 END), 0), 2) as win_rate,
                    SUM(CASE WHEN status = 'win' THEN profit_amount WHEN status = 'loss' THEN -loss_amount ELSE 0 END) as net_pnl
                FROM crypto_trades
                WHERE trade_mode = ?
                GROUP BY coin
                ORDER BY net_pnl DESC
            ");
            $stmt->execute([$mode]);
            $byCoin = $stmt->fetchAll();

            // Emotion analysis
            $stmt = $pdo->prepare("
                SELECT
                    emotion,
                    COUNT(*) as count,
                    SUM(CASE WHEN status = 'win' THEN 1 ELSE 0 END) as wins,
                    ROUND(SUM(CASE WHEN status = 'win' THEN 1 ELSE 0 END) * 100.0 / COUNT(*), 2) as win_rate
                FROM crypto_trades
                WHERE emotion IS NOT NULL AND status IN ('win', 'loss') AND trade_mode = ?
                GROUP BY emotion
            ");
            $stmt->execute([$mode]);
            $byEmotion = $stmt->fetchAll();

            // Time-based analysis (by hour)
            $stmt = $pdo->prepare("
                SELECT
                    HOUR(created_at) as hour,
                    COUNT(*) as trades,
                    SUM(CASE WHEN status = 'win' THEN 1 ELSE 0 END) as wins,
                    ROUND(SUM(CASE WHEN status = 'win' THEN 1 ELSE 0 END) * 100.0 /
                          NULLIF(SUM(CASE WHEN status IN ('win', 'loss') THEN 1 ELSE 0 END), 0), 2) as win_rate
                FROM crypto_trades
                WHERE status IN ('win', 'loss') AND trade_mode = ?
                GROUP BY HOUR(created_at)
                ORDER BY hour
            ");
            $stmt->execute([$mode]);
            $byHour = $stmt->fetchAll();

            // Consecutive wins/losses (streaks)
            $stmt = $pdo->prepare("
                SELECT status, created_at
                FROM crypto_trades
                WHERE status IN ('win', 'loss') AND trade_mode = ?
                ORDER BY created_at DESC
                LIMIT 50
            ");
            $stmt->execute([$mode]);
            $recentTrades = $stmt->fetchAll();
            
            $currentStreak = 0;
            $streakType = null;
            $maxWinStreak = 0;
            $maxLossStreak = 0;
            $currentWinStreak = 0;
            $currentLossStreak = 0;
            
            foreach ($recentTrades as $trade) {
                if ($streakType === null) {
                    $streakType = $trade['status'];
                    $currentStreak = 1;
                } elseif ($trade['status'] === $streakType) {
                    $currentStreak++;
                } else {
                    if ($streakType === 'win') {
                        $maxWinStreak = max($maxWinStreak, $currentStreak);
                    } else {
                        $maxLossStreak = max($maxLossStreak, $currentStreak);
                    }
                    $streakType = $trade['status'];
                    $currentStreak = 1;
                }
            }
            
            if ($streakType === 'win') {
                $maxWinStreak = max($maxWinStreak, $currentStreak);
                $currentWinStreak = $currentStreak;
            } else {
                $maxLossStreak = max($maxLossStreak, $currentStreak);
                $currentLossStreak = $currentStreak;
            }
            
            sendJSON([
                'success' => true,
                'analytics' => [
                    'byCategory' => $byCategory,
                    'byCoin' => $byCoin,
                    'byEmotion' => $byEmotion,
                    'byHour' => $byHour,
                    'streaks' => [
                        'current_win_streak' => $currentWinStreak,
                        'current_loss_streak' => $currentLossStreak,
                        'max_win_streak' => $maxWinStreak,
                        'max_loss_streak' => $maxLossStreak
                    ]
                ]
            ]);
            
        case 'getMistakes':
            $stmt = $pdo->query("SELECT * FROM v_mistake_analysis");
            $mistakes = $stmt->fetchAll();
            
            $stmt = $pdo->query("SELECT * FROM trade_mistakes WHERE is_active = 1 ORDER BY category, mistake_name");
            $mistakeTypes = $stmt->fetchAll();
            
            sendJSON(['success' => true, 'mistakes' => $mistakes, 'mistakeTypes' => $mistakeTypes]);
            
        case 'getGoals':
            $stmt = $pdo->prepare("SELECT * FROM trading_goals WHERE period_end >= CURDATE() AND (user_id = ? OR user_id IS NULL) ORDER BY period_start DESC");
            $stmt->execute([$currentUserId ?: 0]);
            $goals = $stmt->fetchAll();
            sendJSON(['success' => true, 'goals' => $goals]);
            
        case 'getGoalProgress':
            $goalId = $_GET['goalId'] ?? null;
            if (!$goalId) {
                sendJSON(['success' => false, 'error' => 'Goal ID required']);
            }
            
            $stmt = $pdo->prepare("SELECT * FROM trading_goals WHERE id = ?");
            $stmt->execute([$goalId]);
            $goal = $stmt->fetch();
            
            if (!$goal) {
                sendJSON(['success' => false, 'error' => 'Goal not found']);
            }
            
            // Get trades in this period
            $stmt = $pdo->prepare("
                SELECT 
                    COUNT(*) as total_trades,
                    SUM(CASE WHEN status = 'win' THEN 1 ELSE 0 END) as wins,
                    SUM(CASE WHEN status = 'loss' THEN 1 ELSE 0 END) as losses,
                    SUM(CASE WHEN status = 'win' THEN profit_amount WHEN status = 'loss' THEN -loss_amount ELSE 0 END) as total_pnl,
                    ROUND(SUM(CASE WHEN status = 'win' THEN 1 ELSE 0 END) * 100.0 / 
                          NULLIF(SUM(CASE WHEN status IN ('win', 'loss') THEN 1 ELSE 0 END), 0), 2) as win_rate,
                    AVG(reward_risk_ratio) as avg_rr
                FROM crypto_trades
                WHERE DATE(created_at) BETWEEN ? AND ?
            ");
            $stmt->execute([$goal['period_start'], $goal['period_end']]);
            $progress = $stmt->fetch();
            
            sendJSON(['success' => true, 'goal' => $goal, 'progress' => $progress]);
            
        case 'getJournalEntries':
            $limit = $_GET['limit'] ?? 30;
            $stmt = $pdo->prepare("
                SELECT * FROM trading_journal_entries 
                ORDER BY entry_date DESC 
                LIMIT ?
            ");
            $stmt->execute([$limit]);
            $entries = $stmt->fetchAll();
            sendJSON(['success' => true, 'entries' => $entries]);
            break;
            
        case 'getBudget':
            $stmt = $pdo->prepare("SELECT budget FROM user_budget WHERE (user_id = ? OR user_id IS NULL) ORDER BY id DESC LIMIT 1");
            $stmt->execute([$currentUserId ?: 0]);
            $result = $stmt->fetch();
            sendJSON(['success' => true, 'budget' => $result ? $result['budget'] : null]);
            break;
            
        case 'getBudgetTransactions':
            $stmt = $pdo->query("
                SELECT * FROM budget_transactions 
                ORDER BY created_at DESC 
                LIMIT 50
            ");
            $transactions = $stmt->fetchAll();
            sendJSON(['success' => true, 'transactions' => $transactions]);
            break;
            
        case 'getFavoriteCoins':
            $stmt = $pdo->prepare("SELECT coins FROM favorite_coins WHERE (user_id = ? OR user_id IS NULL) ORDER BY id DESC LIMIT 1");
            $stmt->execute([$currentUserId ?: 0]);
            $result = $stmt->fetch();
            $coins = $result ? json_decode($result['coins']) : ['BTC', 'ETH', 'SOL', 'SUI', 'XRP', 'ADA', 'LINK'];
            sendJSON(['success' => true, 'coins' => $coins]);
            break;
            
        default:
            sendJSON(['success' => false, 'error' => 'Invalid action']);
    }
}

// ============================================
// POST REQUESTS
// ============================================

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $input = getInput();
    $action = $input['action'] ?? '';
    
    switch($action) {
        case 'saveTrade':
            $trade = $input['trade'];

            $stmt = $pdo->prepare("
                INSERT INTO crypto_trades
                (coin, position_size, entry_price, stop_loss_percent, take_profit_percent,
                 quantity, sl_price, tp_price, loss_amount, profit_amount, reward_risk_ratio,
                 fees, order_type, comment, trade_category, emotion, discipline_score,
                 mistake_type, lesson_learned, pre_trade_plan, entry_screenshot, trade_mode, screenshots, user_id)
                VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
            ");

            $screenshotsJson = isset($trade['screenshots']) && is_array($trade['screenshots'])
                ? json_encode($trade['screenshots'])
                : null;

            $stmt->execute([
                $trade['coin'],
                $trade['positionSize'],
                $trade['entryPrice'],
                $trade['stopLossPercent'],
                $trade['takeProfitPercent'],
                $trade['quantity'],
                $trade['slPrice'],
                $trade['tpPrice'],
                $trade['lossAmount'],
                $trade['profitAmount'],
                $trade['rewardRiskRatio'],
                $trade['fees'],
                $trade['orderType'] ?? 'market',
                $trade['comment'] ?? '',
                $trade['category'] ?? null,
                $trade['emotion'] ?? null,
                $trade['disciplineScore'] ?? null,
                $trade['mistakeType'] ?? null,
                $trade['lessonLearned'] ?? null,
                $trade['preTradePlan'] ?? null,
                $trade['entryScreenshot'] ?? null,
                $trade['tradeMode'] ?? 'crypto',
                $screenshotsJson,
                $currentUserId ?: null
            ]);
            
            $tradeId = $pdo->lastInsertId();
            
            // Save tags if provided
            if (!empty($trade['tags'])) {
                $stmt = $pdo->prepare("INSERT INTO trade_tags (trade_id, tag) VALUES (?, ?)");
                foreach ($trade['tags'] as $tag) {
                    $stmt->execute([$tradeId, $tag]);
                }
            }
            
            sendJSON(['success' => true, 'tradeId' => $tradeId]);
            
        case 'updateTradeStatus':
            $stmt = $pdo->prepare("UPDATE crypto_trades SET status = ?, comment = ? WHERE id = ? AND (user_id = ? OR user_id IS NULL)");
            $stmt->execute([$input['status'], $input['comment'] ?? '', $input['id'], $currentUserId ?: 0]);
            sendJSON(['success' => true]);
            
        case 'updateTradePrices':
            $id = $input['id'];
            $slPrice = $input['slPrice'];
            $tpPrice = $input['tpPrice'];
            
            // Get the trade to recalculate values
            $stmt = $pdo->prepare("SELECT * FROM crypto_trades WHERE id = ?");
            $stmt->execute([$id]);
            $trade = $stmt->fetch();
            
            if ($trade) {
                $entry = floatval($trade['entry_price']);
                $position = floatval($trade['position_size']);
                $quantity = floatval($trade['quantity']);
                
                // Recalculate percentages
                $slPercent = (($entry - floatval($slPrice)) / $entry) * 100;
                $tpPercent = ((floatval($tpPrice) - $entry) / $entry) * 100;
                
                // Recalculate loss and profit amounts
                $slSellValue = $quantity * floatval($slPrice);
                $slSellFee = $slSellValue * 0.001;
                $lossAmount = $position - ($slSellValue - $slSellFee);
                
                $tpSellValue = $quantity * floatval($tpPrice);
                $tpSellFee = $tpSellValue * 0.001;
                $profitAmount = ($tpSellValue - $tpSellFee) - $position;
                
                $rewardRiskRatio = $profitAmount / $lossAmount;
                
                $stmt = $pdo->prepare("
                    UPDATE crypto_trades 
                    SET sl_price = ?, tp_price = ?, 
                        stop_loss_percent = ?, take_profit_percent = ?,
                        loss_amount = ?, profit_amount = ?,
                        reward_risk_ratio = ?
                    WHERE id = ?
                ");
                $stmt->execute([
                    $slPrice, 
                    $tpPrice, 
                    round($slPercent, 2), 
                    round($tpPercent, 2),
                    round($lossAmount, 2),
                    round($profitAmount, 2),
                    round($rewardRiskRatio, 2),
                    $id
                ]);
            }
            
            sendJSON(['success' => true]);
            
        case 'updateTradeReview':
            $reviewScreenshotsJson = isset($input['screenshots']) && is_array($input['screenshots'])
                ? json_encode($input['screenshots'])
                : null;
            $stmt = $pdo->prepare("
                UPDATE crypto_trades
                SET post_trade_review = ?, emotion = ?, discipline_score = ?,
                    mistake_type = ?, lesson_learned = ?, exit_screenshot = ?,
                    screenshots = COALESCE(?, screenshots)
                WHERE id = ?
            ");
            $stmt->execute([
                $input['review'] ?? '',
                $input['emotion'] ?? null,
                $input['disciplineScore'] ?? null,
                $input['mistakeType'] ?? null,
                $input['lessonLearned'] ?? '',
                $input['exitScreenshot'] ?? null,
                $reviewScreenshotsJson,
                $input['id']
            ]);
            sendJSON(['success' => true]);
            break;
            
        case 'closeTradeWithPnL':
            $tradeId = $input['id'];
            $status = $input['status']; // 'win' or 'loss'
            $actualExitPrice = $input['actualExitPrice'];
            $actualPnl = $input['actualPnl'];
            
            // 1. Get trade details
            $stmt = $pdo->prepare("SELECT coin FROM crypto_trades WHERE id = ?");
            $stmt->execute([$tradeId]);
            $trade = $stmt->fetch();
            
            if (!$trade) {
                sendJSON(['success' => false, 'error' => 'Trade not found']);
                break;
            }
            
            // 2. Update trade with result
            $stmt = $pdo->prepare("
                UPDATE crypto_trades 
                SET status = ?, 
                    actual_exit_price = ?, 
                    actual_pnl = ?
                WHERE id = ?
            ");
            $stmt->execute([$status, $actualExitPrice, $actualPnl, $tradeId]);
            
            // 3. Create budget transaction
            $description = "Trade P&L: {$trade['coin']} - " . strtoupper($status);
            $transType = ($actualPnl >= 0) ? 'deposit' : 'withdrawal';
            $transAmount = abs($actualPnl);
            
            $stmt = $pdo->prepare("
                INSERT INTO budget_transactions (transaction_type, amount, description) 
                VALUES (?, ?, ?)
            ");
            $stmt->execute([$transType, $transAmount, $description]);
            
            // 4. Update budget
            $budgetStmt = $pdo->prepare("SELECT budget FROM user_budget WHERE (user_id = ? OR user_id IS NULL) ORDER BY id DESC LIMIT 1");
            $budgetStmt->execute([$currentUserId ?: 0]);
            $budgetResult = $budgetStmt->fetch();
            $currentBudget = $budgetResult ? floatval($budgetResult['budget']) : 0;
            
            $newBudget = $currentBudget + floatval($actualPnl);
            
            $pdo->prepare("DELETE FROM user_budget WHERE user_id = ?")->execute([$currentUserId ?: 0]);
            $updateStmt = $pdo->prepare("INSERT INTO user_budget (budget, user_id) VALUES (?, ?)");
            $updateStmt->execute([$newBudget, $currentUserId ?: null]);
            
            sendJSON(['success' => true, 'newBudget' => $newBudget]);
            break;
            
        case 'addTradeScreenshot':
            // Append a screenshot URL to the trade's screenshots JSON array
            $stmt = $pdo->prepare("SELECT screenshots FROM crypto_trades WHERE id = ?");
            $stmt->execute([$input['id']]);
            $row = $stmt->fetch();
            $existing = ($row && $row['screenshots']) ? json_decode($row['screenshots'], true) : [];
            if (!is_array($existing)) $existing = [];
            $existing[] = $input['url'];
            $stmt = $pdo->prepare("UPDATE crypto_trades SET screenshots = ? WHERE id = ?");
            $stmt->execute([json_encode($existing), $input['id']]);
            sendJSON(['success' => true, 'screenshots' => $existing]);

        case 'removeTradeScreenshot':
            // Remove a screenshot URL from the trade's screenshots JSON array
            $stmt = $pdo->prepare("SELECT screenshots FROM crypto_trades WHERE id = ?");
            $stmt->execute([$input['id']]);
            $row = $stmt->fetch();
            $existing = ($row && $row['screenshots']) ? json_decode($row['screenshots'], true) : [];
            if (!is_array($existing)) $existing = [];
            $existing = array_values(array_filter($existing, fn($u) => $u !== $input['url']));
            $stmt = $pdo->prepare("UPDATE crypto_trades SET screenshots = ? WHERE id = ?");
            $stmt->execute([json_encode($existing), $input['id']]);
            sendJSON(['success' => true, 'screenshots' => $existing]);

        case 'deleteTrade':
            $stmt = $pdo->prepare("DELETE FROM crypto_trades WHERE id = ? AND (user_id = ? OR user_id IS NULL)");
            $stmt->execute([$input['id'], $currentUserId ?: 0]);
            sendJSON(['success' => true]);
            
        case 'saveGoal':
            $stmt = $pdo->prepare("
                INSERT INTO trading_goals 
                (goal_type, target_profit, target_win_rate, max_daily_loss, 
                 min_risk_reward, period_start, period_end, notes, user_id)
                VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
            ");
            $stmt->execute([
                $input['goalType'],
                $input['targetProfit'] ?? null,
                $input['targetWinRate'] ?? null,
                $input['maxDailyLoss'] ?? null,
                $input['minRiskReward'] ?? null,
                $input['periodStart'],
                $input['periodEnd'],
                $input['notes'] ?? '',
                $currentUserId ?: null
            ]);
            sendJSON(['success' => true, 'goalId' => $pdo->lastInsertId()]);
            
        case 'deleteGoal':
            $stmt = $pdo->prepare("DELETE FROM trading_goals WHERE id = ?");
            $stmt->execute([$input['id']]);
            sendJSON(['success' => true]);
            
        case 'saveJournalEntry':
            $stmt = $pdo->prepare("
                INSERT INTO trading_journal_entries 
                (entry_date, market_condition, overall_emotion, what_went_well, 
                 what_went_wrong, lessons_learned, tomorrow_focus, energy_level, user_id)
                VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
                ON DUPLICATE KEY UPDATE
                market_condition = VALUES(market_condition),
                overall_emotion = VALUES(overall_emotion),
                what_went_well = VALUES(what_went_well),
                what_went_wrong = VALUES(what_went_wrong),
                lessons_learned = VALUES(lessons_learned),
                tomorrow_focus = VALUES(tomorrow_focus),
                energy_level = VALUES(energy_level)
            ");
            $stmt->execute([
                $input['entryDate'],
                $input['marketCondition'] ?? null,
                $input['overallEmotion'] ?? null,
                $input['whatWentWell'] ?? '',
                $input['whatWentWrong'] ?? '',
                $input['lessonsLearned'] ?? '',
                $input['tomorrowFocus'] ?? '',
                $input['energyLevel'] ?? null,
                $currentUserId ?: null
            ]);
            sendJSON(['success' => true]);
            
        case 'saveBudget':
            $pdo->query("DELETE FROM user_budget");
            $stmt = $pdo->prepare("INSERT INTO user_budget (budget) VALUES (?)");
            $stmt->execute([$input['budget']]);
            sendJSON(['success' => true]);
            
        case 'addBudgetTransaction':
            // Add transaction
            $stmt = $pdo->prepare("
                INSERT INTO budget_transactions (transaction_type, amount, description, user_id) 
                VALUES (?, ?, ?, ?)
            ");
            $stmt->execute([
                $input['type'],
                $input['amount'],
                $input['description'] ?? null,
                $currentUserId ?: null
            ]);
            
            // Update budget
            $currentBudget = 0;
            $budgetStmt = $pdo->prepare("SELECT budget FROM user_budget WHERE (user_id = ? OR user_id IS NULL) ORDER BY id DESC LIMIT 1");
            $budgetStmt->execute([$currentUserId ?: 0]);
            $budgetResult = $budgetStmt->fetch();
            if ($budgetResult) {
                $currentBudget = floatval($budgetResult['budget']);
            }
            
            $newBudget = $input['type'] === 'deposit' 
                ? $currentBudget + floatval($input['amount'])
                : $currentBudget - floatval($input['amount']);
            
            $pdo->prepare("DELETE FROM user_budget WHERE user_id = ?")->execute([$currentUserId ?: 0]);
            $updateStmt = $pdo->prepare("INSERT INTO user_budget (budget, user_id) VALUES (?, ?)");
            $updateStmt->execute([$newBudget, $currentUserId ?: null]);
            
            sendJSON(['success' => true, 'newBudget' => $newBudget]);
            break;
            
        case 'saveFavoriteCoins':
            $coins = json_encode($input['coins']);
            $pdo->query("DELETE FROM favorite_coins");
            $stmt = $pdo->prepare("INSERT INTO favorite_coins (coins) VALUES (?)");
            $stmt->execute([$coins]);
            sendJSON(['success' => true]);
            break;

        case 'bulkImportTrades':
            $trades  = $input['trades'] ?? [];
            $mode    = $input['mode'] ?? 'crypto';
            $imported = 0;
            $errors   = [];

            $stmt = $pdo->prepare("
                INSERT INTO crypto_trades
                (coin, position_size, entry_price, stop_loss_percent, take_profit_percent,
                 quantity, sl_price, tp_price, loss_amount, profit_amount, reward_risk_ratio,
                 fees, order_type, comment, trade_category, emotion, discipline_score,
                 mistake_type, lesson_learned, status, trade_mode, trade_date, actual_exit_price)
                VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
            ");

            foreach ($trades as $i => $t) {
                try {
                    // Validate trade_date format (YYYY-MM-DD); fallback to NULL
                    $tradeDate = null;
                    if (!empty($t['tradeDate'])) {
                        $d = \DateTime::createFromFormat('Y-m-d', $t['tradeDate']);
                        if ($d && $d->format('Y-m-d') === $t['tradeDate']) {
                            $tradeDate = $t['tradeDate'];
                        }
                    }
                    $stmt->execute([
                        $t['coin']             ?? '',
                        $t['positionSize']     ?? 0,
                        $t['entryPrice']       ?? 0,
                        $t['stopLossPercent']  ?? 0,
                        $t['takeProfitPercent'] ?? 0,
                        $t['quantity']         ?? 0,
                        $t['slPrice']          ?? 0,
                        $t['tpPrice']          ?? 0,
                        $t['lossAmount']       ?? 0,
                        $t['profitAmount']     ?? 0,
                        $t['rewardRiskRatio']  ?? 0,
                        $t['fees']             ?? 0,
                        $t['orderType']        ?? 'market',
                        $t['comment']          ?? '',
                        $t['category']         ?? null,
                        $t['emotion']          ?? null,
                        $t['disciplineScore']  ?? null,
                        $t['mistakeType']      ?? null,
                        $t['lessonLearned']    ?? null,
                        $t['status']           ?? 'pending',
                        $mode,
                        $tradeDate,
                        isset($t['actualExitPrice']) && $t['actualExitPrice'] > 0 ? $t['actualExitPrice'] : null
                    ]);
                    $imported++;
                } catch (\PDOException $e) {
                    $errors[] = "Row $i: " . $e->getMessage();
                }
            }

            sendJSON(['success' => true, 'imported' => $imported, 'errors' => $errors]);
            break;

// ============================================================
// AUTH ACTIONS  (inserted into POST switch before 'default')
// ============================================================

        case 'checkSession':
            $uid = getCurrentUserId();
            if ($uid) {
                $stmt = $pdo->prepare("SELECT id, first_name, last_name, email, trade_mode, trial_ends_at, subscribed FROM users WHERE id = ?");
                $stmt->execute([$uid]);
                $user = $stmt->fetch();
                sendJSON(['success' => true, 'user' => $user]);
            }
            sendJSON(['success' => false, 'error' => 'Not logged in']);

        case 'login':
            $email    = trim($input['email']    ?? '');
            $password = trim($input['password'] ?? '');

            if (!$email || !$password) {
                sendJSON(['success' => false, 'error' => 'Email and password are required']);
            }

            $stmt = $pdo->prepare("SELECT * FROM users WHERE email = ? LIMIT 1");
            $stmt->execute([strtolower($email)]);
            $user = $stmt->fetch();

            if (!$user || !password_verify($password, $user['password_hash'])) {
                sendJSON(['success' => false, 'error' => 'Invalid email or password']);
            }

            // Regenerate session ID on login (session fixation protection)
            session_regenerate_id(true);
            $_SESSION['user_id']    = $user['id'];
            $_SESSION['user_email'] = $user['email'];
            $_SESSION['trade_mode'] = $user['trade_mode'];

            sendJSON([
                'success'   => true,
                'user'      => [
                    'id'         => $user['id'],
                    'first_name' => $user['first_name'],
                    'last_name'  => $user['last_name'],
                    'email'      => $user['email'],
                    'trade_mode' => $user['trade_mode'],
                ]
            ]);

        case 'register':
            $firstName = trim($input['firstName'] ?? '');
            $lastName  = trim($input['lastName']  ?? '');
            $email     = strtolower(trim($input['email']    ?? ''));
            $password  = $input['password']  ?? '';
            $tradeMode = in_array($input['tradeMode'] ?? '', ['crypto','stocks'])
                         ? $input['tradeMode'] : 'crypto';

            // Validate
            if (!$firstName || !$email || !$password) {
                sendJSON(['success' => false, 'error' => 'First name, email and password are required']);
            }
            if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
                sendJSON(['success' => false, 'error' => 'Invalid email address']);
            }
            if (strlen($password) < 8) {
                sendJSON(['success' => false, 'error' => 'Password must be at least 8 characters']);
            }

            // Check duplicate email
            $stmt = $pdo->prepare("SELECT id FROM users WHERE email = ?");
            $stmt->execute([$email]);
            if ($stmt->fetch()) {
                sendJSON(['success' => false, 'error' => 'An account with this email already exists']);
            }

            // Insert user with 7-day trial
            $hash     = password_hash($password, PASSWORD_BCRYPT, ['cost' => 12]);
            $trialEnd = (new \DateTime('+7 days'))->format('Y-m-d H:i:s');

            $stmt = $pdo->prepare("
                INSERT INTO users (first_name, last_name, email, password_hash, trade_mode, trial_ends_at)
                VALUES (?, ?, ?, ?, ?, ?)
            ");
            $stmt->execute([$firstName, $lastName, $email, $hash, $tradeMode, $trialEnd]);
            $newUserId = (int)$pdo->lastInsertId();

            // Auto-login
            session_regenerate_id(true);
            $_SESSION['user_id']    = $newUserId;
            $_SESSION['user_email'] = $email;
            $_SESSION['trade_mode'] = $tradeMode;

            sendJSON([
                'success' => true,
                'user'    => [
                    'id'           => $newUserId,
                    'first_name'   => $firstName,
                    'last_name'    => $lastName,
                    'email'        => $email,
                    'trade_mode'   => $tradeMode,
                    'trial_ends_at'=> $trialEnd,
                ]
            ]);

        case 'logout':
            $_SESSION = [];
            session_destroy();
            sendJSON(['success' => true]);

        case 'requestPasswordReset':
            $email = strtolower(trim($input['email'] ?? ''));
            if (!$email) sendJSON(['success' => false, 'error' => 'Email is required']);

            $stmt = $pdo->prepare("SELECT id FROM users WHERE email = ?");
            $stmt->execute([$email]);
            $user = $stmt->fetch();

            // Always return success to prevent email enumeration
            if ($user) {
                $token     = bin2hex(random_bytes(32));
                $tokenHash = hash('sha256', $token);
                $expires   = (new \DateTime('+1 hour'))->format('Y-m-d H:i:s');

                // Invalidate old tokens for this user
                $pdo->prepare("UPDATE password_resets SET used = 1 WHERE user_id = ?")
                    ->execute([$user['id']]);

                $pdo->prepare("INSERT INTO password_resets (user_id, token_hash, expires_at) VALUES (?, ?, ?)")
                    ->execute([$user['id'], $tokenHash, $expires]);

                // TODO: send email with reset link:
                // $resetUrl = "https://yourdomain.com/pages/reset-password-v1.html?token={$token}";
                // mail($email, 'Reset your TradeJournal password', "Click here: {$resetUrl}");
                //
                // For now, return the token in dev mode so you can test it:
                sendJSON(['success' => true, 'dev_token' => $token]);
            }

            sendJSON(['success' => true]); // don't reveal whether email exists

        case 'resetPassword':
            $token    = $input['token']    ?? '';
            $password = $input['password'] ?? '';

            if (!$token || strlen($password) < 8) {
                sendJSON(['success' => false, 'error' => 'Invalid request']);
            }

            $tokenHash = hash('sha256', $token);
            $stmt = $pdo->prepare("
                SELECT pr.user_id FROM password_resets pr
                WHERE pr.token_hash = ?
                  AND pr.used = 0
                  AND pr.expires_at > NOW()
                LIMIT 1
            ");
            $stmt->execute([$tokenHash]);
            $row = $stmt->fetch();

            if (!$row) {
                sendJSON(['success' => false, 'error' => 'Invalid or expired reset link']);
            }

            // Update password and mark token used
            $newHash = password_hash($password, PASSWORD_BCRYPT, ['cost' => 12]);
            $pdo->prepare("UPDATE users SET password_hash = ? WHERE id = ?")
                ->execute([$newHash, $row['user_id']]);
            $pdo->prepare("UPDATE password_resets SET used = 1 WHERE token_hash = ?")
                ->execute([$tokenHash]);

            sendJSON(['success' => true]);


        default:
            sendJSON(['success' => false, 'error' => 'Invalid action']);
    }
}

sendJSON(['success' => false, 'error' => 'Invalid request method']);
?>