<?php
if (session_status() === PHP_SESSION_NONE) { session_start(); }
if (!defined('BASE_PATH')) { define('BASE_PATH', dirname(dirname(__DIR__))); }
require_once BASE_PATH . '/database/config.php';
require_once BASE_PATH . '/database/connection.php';
require_once BASE_PATH . '/modules/shared/helpers.php';

function isLoggedIn(){ return isset($_SESSION['user_id']) && !empty($_SESSION['user_id']); }
if (!isLoggedIn()) { header('Location: ' . route_url(['module'=>'auth','action'=>'login'])); exit; }

$db = Database::getInstance();
$pdo = $db->getConnection();

function userHasPermissionByName(PDO $pdo, string $permName, int $userId): bool {
    $st = $pdo->prepare("SELECT 1 FROM role_permissions rp INNER JOIN permissions p ON rp.permission_id = p.id INNER JOIN user_roles ur ON rp.role_id = ur.role_id WHERE ur.user_id = ? AND p.name = ? LIMIT 1");
    $st->execute([$userId, $permName]);
    return (bool)$st->fetchColumn();
}
function isAdminRole(PDO $pdo, int $userId): bool {
    if ($userId <= 0) return false;
    $stmt = $pdo->prepare("SELECT 1 FROM user_roles ur INNER JOIN roles r ON ur.role_id = r.id WHERE ur.user_id = ? AND r.name = 'admin' LIMIT 1");
    $stmt->execute([$userId]);
    return (bool)$stmt->fetchColumn();
}
function requirePermissionName(PDO $pdo, string $permName) {
    $uid = (int)($_SESSION['user_id'] ?? 0);
    if (!$uid) {
        $loc = route_url(['module'=>'clients']);
        if (strpos($loc, '?') === false) { $loc .= '?module=clients&error=forbidden'; }
        else { $loc .= '&error=forbidden'; }
        header('Location: ' . $loc);
        exit;
    }
    if (!isAdminRole($pdo, $uid) && !userHasPermissionByName($pdo, $permName, $uid)) {
        $loc = route_url(['module'=>'clients']);
        if (strpos($loc, '?') === false) { $loc .= '?module=clients&error=forbidden'; }
        else { $loc .= '&error=forbidden'; }
        header('Location: ' . $loc);
        exit;
    }
}

$action = $_POST['action'] ?? '';
if ($action === 'change_password') {
    requirePermissionName($pdo, 'clients.change_password');
    $client_id = (int)($_POST['client_id'] ?? 0);
    $new_password = (string)($_POST['new_password'] ?? '');
    $confirm_password = (string)($_POST['confirm_password'] ?? '');
    $redirect = $_POST['redirect'] ?? module_url('clients/view.php') . '?id=' . $client_id;

    if ($client_id <= 0 || strlen($new_password) < 8 || $new_password !== $confirm_password) {
        header('Location: ' . $redirect . '&error=invalid_input');
        exit;
    }
    try {
        $hash = password_hash($new_password, PASSWORD_DEFAULT);
        $stmt = $pdo->prepare('UPDATE clients SET password_hash = ?, updated_at = NOW() WHERE id = ?');
        $stmt->execute([$hash, $client_id]);
        header('Location: ' . $redirect . '&message=password_changed');
        exit;
    } catch (Exception $e) {
        header('Location: ' . $redirect . '&error=db_error');
        exit;
    }
}

if ($action === 'manual_deposit') {
    requirePermissionName($pdo, 'clients.manual_deposit');
    $client_id = (int)($_POST['client_id'] ?? 0);
    $account_id = (int)($_POST['account_id'] ?? 0);
    $amount = (float)($_POST['amount'] ?? 0);
    $currency = trim($_POST['currency'] ?? 'USD');
    $method = trim($_POST['method'] ?? 'manual');
    $reference = trim($_POST['reference'] ?? '');
    $redirect = $_POST['redirect'] ?? (module_url('clients/view.php') . '?id=' . $client_id);

    if ($client_id <= 0 || $amount <= 0 || $currency === '') {
        header('Location: ' . $redirect . '&error=invalid_deposit');
        exit;
    }
    try {
        $acc = null;
        if ($account_id > 0) {
            $stAcc = $pdo->prepare('SELECT id, account_number, balance, currency FROM client_accounts WHERE id = ? AND client_id = ? AND status = "active"');
            $stAcc->execute([$account_id, $client_id]);
            $acc = $stAcc->fetch(PDO::FETCH_ASSOC);
        }
        if (!$acc) {
            $stAcc2 = $pdo->prepare('SELECT id, account_number, balance, currency FROM client_accounts WHERE client_id = ? AND status = "active" ORDER BY created_at ASC LIMIT 1');
            $stAcc2->execute([$client_id]);
            $acc = $stAcc2->fetch(PDO::FETCH_ASSOC);
        }
        if (!$acc) { header('Location: ' . $redirect . '&error=no_account'); exit; }

        $pdo->prepare('CREATE TABLE IF NOT EXISTS client_deposits (
            id INT AUTO_INCREMENT PRIMARY KEY,
            client_id INT NOT NULL,
            amount DECIMAL(12,2) NOT NULL,
            currency VARCHAR(10) NOT NULL,
            method VARCHAR(50) NULL,
            reference VARCHAR(100) NULL,
            status VARCHAR(20) DEFAULT "confirmed",
            created_at DATETIME DEFAULT NOW()
        ) ENGINE=InnoDB')->execute();

        $stmt = $pdo->prepare('INSERT INTO client_deposits (client_id, amount, currency, method, reference, status, created_at) VALUES (?,?,?,?,?,"confirmed", NOW())');
        $stmt->execute([$client_id, $amount, $currency, $method, $reference]);

        // Registrar transacción
        $pdo->prepare('CREATE TABLE IF NOT EXISTS client_transactions (
            id INT AUTO_INCREMENT PRIMARY KEY,
            client_id INT NOT NULL,
            type VARCHAR(20) NOT NULL,
            amount DECIMAL(12,2) NOT NULL,
            currency VARCHAR(10) NOT NULL,
            reference VARCHAR(100) NULL,
            notes TEXT NULL,
            created_at DATETIME DEFAULT NOW()
        ) ENGINE=InnoDB')->execute();

        $stmt2 = $pdo->prepare('INSERT INTO client_transactions (client_id, type, amount, currency, reference, notes, created_at) VALUES (?,?,?,?,?,NULL, NOW())');
        $stmt2->execute([$client_id, 'deposit', $amount, $currency, $reference]);

        $stUpAcc = $pdo->prepare('UPDATE client_accounts SET balance = balance + ? WHERE id = ?');
        $stUpAcc->execute([$amount, (int)$acc['id']]);

        $stTa = $pdo->prepare('UPDATE trading_accounts SET balance = balance + ?, equity = equity + ?, free_margin = free_margin + ? WHERE account_number = ?');
        $stTa->execute([$amount, $amount, $amount, $acc['account_number']] );

        $stAgg = $pdo->prepare('UPDATE clients c SET c.balance = (SELECT IFNULL(SUM(balance),0) FROM client_accounts WHERE client_id = c.id AND status = "active"), c.equity = (SELECT IFNULL(SUM(balance),0) FROM client_accounts WHERE client_id = c.id AND status = "active"), c.updated_at = NOW() WHERE c.id = ?');
        $stAgg->execute([$client_id]);

        $loc = $redirect;
        $sep = (strpos($loc, '?') === false) ? '?' : '&';
        $loc .= $sep . 'message=deposit_recorded'
              . '&amount=' . urlencode(number_format($amount, 2, '.', ''))
              . '&currency=' . urlencode($currency)
              . '&account=' . urlencode($acc['account_number'] ?? '')
              . '&method=' . urlencode($method);
        header('Location: ' . $loc);
        exit;
    } catch (Exception $e) {
        header('Location: ' . $redirect . '&error=db_error');
        exit;
    }
}

if ($action === 'change_status') {
    requirePermissionName($pdo, 'clients.change_status');
    $client_id = (int)($_POST['client_id'] ?? 0);
    $new_status = trim($_POST['status'] ?? '');
    $redirect = $_POST['redirect'] ?? (module_url('clients/view.php') . '?id=' . $client_id);
    if ($client_id <= 0 || $new_status === '') { header('Location: ' . $redirect . '&error=invalid_status'); exit; }
    try {
        $stmt = $pdo->prepare('UPDATE clients SET status = ?, updated_at = NOW() WHERE id = ?');
        $stmt->execute([$new_status, $client_id]);
        header('Location: ' . $redirect . '&message=status_changed');
        exit;
    } catch (Exception $e) {
        header('Location: ' . $redirect . '&error=db_error');
        exit;
    }
}

if ($action === 'create_account') {
    requirePermissionName($pdo, 'clients.create_account');
    $client_id = (int)($_POST['client_id'] ?? 0);
    $type = strtolower(trim($_POST['account_type'] ?? 'standard'));
    $currency = strtoupper(trim($_POST['currency'] ?? 'USD'));
    $redirect = $_POST['redirect'] ?? (module_url('clients/view.php') . '?id=' . $client_id);

    if ($client_id <= 0 || $currency === '') { header('Location: ' . $redirect . '&error=invalid_account'); exit; }

    $leverage = ($type === 'vip' ? 500 : ($type === 'premium' ? 200 : ($type === 'standard' ? 100 : 100)));
    $prefix = ($type === 'vip' ? 'VIP' : ($type === 'premium' ? 'PRM' : ($type === 'demo' ? 'DEM' : 'STD')));

    $gen = function(PDO $pdo, string $prefix, string $currency){
        do {
            $num = $prefix . '-' . $currency . '-' . date('Ymd') . '-' . mt_rand(100000, 999999);
            $st = $pdo->prepare('SELECT 1 FROM client_accounts WHERE account_number = ? LIMIT 1');
            $st->execute([$num]);
            $exists = (bool)$st->fetchColumn();
        } while ($exists);
        return $num;
    };

    try {
        // Sincronizar desk y lead de origen
        $stCli = $pdo->prepare('SELECT email, lead_id, desk_id FROM clients WHERE id = ?');
        $stCli->execute([$client_id]);
        $cliRow = $stCli->fetch(PDO::FETCH_ASSOC) ?: [];
        $leadId = (int)($cliRow['lead_id'] ?? 0);
        $deskId = (int)($cliRow['desk_id'] ?? 0);
        if ($leadId > 0) {
            $stLead = $pdo->prepare('SELECT desk_id, assigned_to FROM leads WHERE id = ?');
            $stLead->execute([$leadId]);
            $leadRow = $stLead->fetch(PDO::FETCH_ASSOC) ?: [];
            $deskFromLead = (int)($leadRow['desk_id'] ?? 0);
            $assignedFromLead = (int)($leadRow['assigned_to'] ?? 0);
            if ($deskFromLead > 0 && $deskFromLead !== $deskId) {
                $pdo->prepare('UPDATE clients SET desk_id = ?, updated_at = NOW() WHERE id = ?')->execute([$deskFromLead, $client_id]);
            }
            if ($assignedFromLead > 0) {
                $pdo->prepare('UPDATE clients SET assigned_to = ?, updated_at = NOW() WHERE id = ?')->execute([$assignedFromLead, $client_id]);
            }
        } else {
            if (!empty($cliRow['email'])) {
                $stFindLead = $pdo->prepare('SELECT id, desk_id FROM leads WHERE email = ? ORDER BY created_at DESC LIMIT 1');
                $stFindLead->execute([$cliRow['email']]);
                $lead = $stFindLead->fetch(PDO::FETCH_ASSOC);
                if ($lead && (int)$lead['id'] > 0) {
                    $newLeadId = (int)$lead['id'];
                    $newDeskId = (int)($lead['desk_id'] ?? 0);
                    $pdo->prepare('UPDATE clients SET lead_id = ?, desk_id = ?, updated_at = NOW() WHERE id = ?')->execute([$newLeadId, $newDeskId, $client_id]);
                    // Copiar asignación del lead
                    $stLead2 = $pdo->prepare('SELECT assigned_to FROM leads WHERE id = ?');
                    $stLead2->execute([$newLeadId]);
                    $ass = (int)($stLead2->fetchColumn() ?: 0);
                    if ($ass > 0) { $pdo->prepare('UPDATE clients SET assigned_to = ?, updated_at = NOW() WHERE id = ?')->execute([$ass, $client_id]); }
                }
            }
        }

        $account_number = $gen($pdo, $prefix, $currency);
        $stCa = $pdo->prepare('INSERT INTO client_accounts (client_id, account_type, account_number, currency, balance, provider, status, created_at) VALUES (?,?,?,?,0.00, "internal", "active", NOW())');
        $stCa->execute([$client_id, ucfirst($type), $account_number, $currency]);

        $hasTa = false; try { $pdo->query('SELECT 1 FROM trading_accounts LIMIT 1'); $hasTa = true; } catch (Throwable $__) { $hasTa = false; }
        if ($hasTa) {
            $stTa = $pdo->prepare('INSERT INTO trading_accounts (client_id, account_type, account_number, balance, equity, margin, free_margin, margin_level, leverage, currency, status, created_at) VALUES (?,?,?,?,0.00,0.00,0.00,0.00,?, ?, "active", NOW())');
            $stTa->execute([$client_id, $type, $account_number, 0.00, $leverage, $currency]);
        }

        // Redirigir con detalles para mostrar modal de confirmación
        $loc = $redirect;
        $sep = (strpos($loc, '?') === false) ? '?' : '&';
        $loc .= $sep . 'message=account_created'
              . '&acc=' . urlencode($account_number)
              . '&type=' . urlencode(ucfirst($type))
              . '&currency=' . urlencode($currency)
              . '&leverage=' . urlencode((string)$leverage);
        header('Location: ' . $loc);
        exit;
    } catch (Exception $e) {
        header('Location: ' . $redirect . '&error=db_error');
        exit;
    }
}

if ($action === 'bulk_update') {
    $uid = (int)($_SESSION['user_id'] ?? 0);
    $isAdmin = isAdminRole($pdo, $uid);
    $canEdit = $isAdmin || userHasPermissionByName($pdo, 'clients.edit', $uid);
    $canChangeStatus = $isAdmin || userHasPermissionByName($pdo, 'clients.change_status', $uid);
    $ids = $_POST['client_ids'] ?? [];
    if (is_string($ids)) { $ids = explode(',', $ids); }
    $ids = array_filter(array_map('intval', (array)$ids));
    $new_status = trim($_POST['new_status'] ?? '');
    $new_desk_id = (int)($_POST['new_desk_id'] ?? 0);
    $new_assigned_user_id = (int)($_POST['new_assigned_user_id'] ?? 0);
    $redirect = $_POST['redirect'] ?? route_url(['module'=>'clients']);
    if (empty($ids)) { header('Location: ' . $redirect . '&error=bulk_empty'); exit; }
    // Asegurar columna clients.assigned_to para permitir asignación directa
    try {
        $chk = $pdo->query("SHOW COLUMNS FROM clients LIKE 'assigned_to'");
        $hasAssignedCol = (bool)$chk->fetch();
        if (!$hasAssignedCol) { $pdo->exec("ALTER TABLE clients ADD COLUMN assigned_to INT NULL"); }
    } catch (Throwable $__) {}
    try {
        // Asegurar columna desk_status
        $hasDeskStatus = false;
        try {
            $chk2 = $pdo->query("SHOW COLUMNS FROM clients LIKE 'desk_status'");
            $hasDeskStatus = (bool)$chk2->fetch();
            if (!$hasDeskStatus) { $pdo->exec("ALTER TABLE clients ADD COLUMN desk_status VARCHAR(64) NULL"); }
            $chk3 = $pdo->query("SHOW COLUMNS FROM clients LIKE 'desk_status'");
            $hasDeskStatus = (bool)$chk3->fetch();
        } catch (Throwable $__) { $hasDeskStatus = false; }
        $pdo->beginTransaction();
        $updated_status = 0; $updated_desk = 0; $assigned_ok = 0; $assigned_skip_no_desk = 0; $assigned_skip_no_lead = 0; $assigned_skip_not_in_desk = 0; $status_skip_not_allowed = 0;
        foreach ($ids as $cid) {
            // Contexto del cliente
            $stCtx = $pdo->prepare('SELECT id, email, lead_id, desk_id FROM clients WHERE id = ?');
            $stCtx->execute([$cid]);
            $ctx = $stCtx->fetch(PDO::FETCH_ASSOC) ?: [];
            $leadId = (int)($ctx['lead_id'] ?? 0);
            $deskId = (int)($ctx['desk_id'] ?? 0);

            if ($new_status !== '' && $canChangeStatus) {
                // Validar contra estados permitidos del desk actual o nuevo
                $deskForStatus = ($new_desk_id > 0) ? $new_desk_id : $deskId;
                $allowed = true;
                if ($deskForStatus > 0) {
                    try {
                        $stAllowed = $pdo->prepare('SELECT 1 FROM desk_allowed_statuses WHERE desk_id = ? AND status = ? LIMIT 1');
                        $stAllowed->execute([$deskForStatus, $new_status]);
                        $allowed = (bool)$stAllowed->fetchColumn();
                    } catch (Throwable $__) {
                        // Si la tabla no existe, no bloquear la actualización
                        $allowed = true;
                    }
                }
                if ($allowed) {
                    if ($hasDeskStatus) {
                        $pdo->prepare('UPDATE clients SET desk_status = ?, updated_at = NOW() WHERE id = ?')->execute([$new_status, $cid]);
                    } else {
                        // Fallback: actualizar el estado general si desk_status no está disponible
                        $pdo->prepare('UPDATE clients SET status = ?, updated_at = NOW() WHERE id = ?')->execute([$new_status, $cid]);
                    }
                    $updated_status++;
                } else {
                    $status_skip_not_allowed++;
                }
            }
            if ($new_desk_id > 0 && $canEdit) {
                $st = $pdo->prepare('UPDATE clients SET desk_id = ?, updated_at = NOW() WHERE id = ?');
                $st->execute([$new_desk_id, $cid]);
                $deskId = $new_desk_id; // actualizar contexto
                $updated_desk++;
            }
            if ($new_assigned_user_id > 0 && $canEdit) {
                if ($deskId <= 0) { $assigned_skip_no_desk++; }
                else {
                    // Verificar que el usuario pertenece al desk
                    $stDU = $pdo->prepare('SELECT 1 FROM desk_users WHERE desk_id = ? AND user_id = ? LIMIT 1');
                    $stDU->execute([$deskId, $new_assigned_user_id]);
                    $inDesk = (bool)$stDU->fetchColumn();
                    if (!$inDesk) { $assigned_skip_not_in_desk++; }
                    else {
                        // Asegurar lead_id para reflejar "Asignado a" en listado
                        if ($leadId <= 0) {
                            $email = (string)($ctx['email'] ?? '');
                            if ($email !== '') {
                                $stFind = $pdo->prepare('SELECT id FROM leads WHERE email = ? ORDER BY created_at DESC LIMIT 1');
                                $stFind->execute([$email]);
                                $leadId = (int)($stFind->fetchColumn() ?: 0);
                                if ($leadId > 0) { $pdo->prepare('UPDATE clients SET lead_id = ?, updated_at = NOW() WHERE id = ?')->execute([$leadId, $cid]); }
                            }
                        }
                        if ($leadId > 0) {
                            $pdo->prepare('UPDATE leads SET assigned_to = ? WHERE id = ?')->execute([$new_assigned_user_id, $leadId]);
                            $assigned_ok++;
                        } else {
                            // Sin lead vinculado: asignar directamente al cliente igualmente
                            $assigned_skip_no_lead++; // mantener métrica informativa
                        }
                        // Guardar asignación directa en cliente en ambos casos
                        $pdo->prepare('UPDATE clients SET assigned_to = ?, updated_at = NOW() WHERE id = ?')->execute([$new_assigned_user_id, $cid]);
                    }
                }
            }
        }
        $pdo->commit();
        $sep = strpos($redirect,'?')===false ? '?' : '&';
        $params = http_build_query([
            'count' => count($ids),
            'status' => $updated_status,
            'desk' => $updated_desk,
            'assigned_ok' => $assigned_ok,
            'assigned_skip_no_desk' => $assigned_skip_no_desk,
            'assigned_skip_no_lead' => $assigned_skip_no_lead,
            'assigned_skip_not_in_desk' => $assigned_skip_not_in_desk,
            'status_skip_not_allowed' => $status_skip_not_allowed
        ]);
        header('Location: ' . $redirect . $sep . 'message=bulk_updated&' . $params);
        exit;
    } catch (Throwable $__) {
        $pdo->rollBack();
        header('Location: ' . $redirect . '&error=db_error');
        exit;
    }
}

header('Location: ' . route_url(['module'=>'clients']));
exit;
?>
