<?php
declare(strict_types=1);
require_once __DIR__ . '/../config/database.php';
require_once __DIR__ . '/../app/helpers/rbac.php';
require_once __DIR__ . '/../app/helpers/audit.php';
require_once __DIR__ . '/../app/helpers/api_security.php';
require_once __DIR__ . '/../app/helpers/soft_delete.php';

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

requireApiLogin();
enforceCsrfForUnsafeRequest();

if (!isAdmin() && !can('fuel_card.view')) {
    respond(['status' => 'error', 'message' => 'Unauthorized']);
}

$action = $_GET['action'] ?? '';

try {
    switch ($action) {
        case 'providers': handleProviders($pdo); break;
        case 'save_provider': handleSaveProvider($pdo); break;
        case 'delete_provider': handleDeleteProvider($pdo); break;
        case 'list': handleList($pdo); break;
        case 'save': handleSave($pdo); break;
        case 'card': handleCard($pdo); break;
        case 'delete': handleDelete($pdo); break;
        case 'transactions': handleTransactions($pdo); break;
        case 'log_transaction': handleLogTransaction($pdo); break;
        case 'reference': handleReference($pdo); break;
        case 'assign_options': handleAssignOptions($pdo); break;
        default: respond(['status' => 'error', 'message' => 'Unknown action']);
    }
} catch (Exception $e) {
    respond(['status' => 'error', 'message' => $e->getMessage()]);
}

function respond(array $payload): void { apiRespond($payload); }

function doAudit(PDO $pdo, string $action, string $description, ?int $recordId = null): void {
    audit($pdo, (int)($_SESSION['user_id'] ?? 0), $action, 'fuel_card', $recordId ?? 0, $description, null, null);
}

function enforceFuelCardWritePermission(): void {
    if (!isAdmin() && !can('fuel_card.create')) {
        respond(['status' => 'error', 'message' => 'Insufficient permissions']);
    }
}

function handleReference(PDO $pdo): void
{
    $providers = $pdo->query("SELECT id, name, code FROM fuel_card_providers WHERE is_active = 1 AND deleted_at IS NULL ORDER BY name")->fetchAll(PDO::FETCH_ASSOC);
    $statuses = ['active', 'suspended', 'lost', 'cancelled', 'expired'];
    $types = ['physical', 'virtual'];
    $assignTypes = ['vehicle', 'driver', 'none'];
    respond(['status' => 'success', 'data' => [
        'providers' => $providers,
        'statuses' => $statuses,
        'card_types' => $types,
        'assign_types' => $assignTypes
    ]]);
}

function handleAssignOptions(PDO $pdo): void
{
    $assignType = $_GET['assign_type'] ?? 'none';
    $options = [];
    if ($assignType === 'vehicle') {
        $stmt = $pdo->query("SELECT id, plate_number, vehicle_model FROM vehicles WHERE deleted_at IS NULL ORDER BY plate_number");
        while ($r = $stmt->fetch(PDO::FETCH_ASSOC)) {
            $label = $r['plate_number'];
            if (!empty($r['vehicle_model'])) $label .= ' - ' . $r['vehicle_model'];
            $options[] = ['id' => $r['id'], 'label' => $label];
        }
    } elseif ($assignType === 'driver') {
        $stmt = $pdo->query("SELECT id, COALESCE(full_name, CONCAT_WS(' ', first_name, surname)) AS label FROM drivers WHERE deleted_at IS NULL ORDER BY full_name");
        while ($r = $stmt->fetch(PDO::FETCH_ASSOC)) {
            $options[] = ['id' => $r['id'], 'label' => $r['label']];
        }
    }
    respond(['status' => 'success', 'data' => $options]);
}

function handleProviders(PDO $pdo): void
{
    $stmt = $pdo->query("SELECT * FROM fuel_card_providers WHERE deleted_at IS NULL ORDER BY name");
    respond(['status' => 'success', 'data' => $stmt->fetchAll(PDO::FETCH_ASSOC)]);
}

function handleSaveProvider(PDO $pdo): void
{
    enforceFuelCardWritePermission();
    $id = (int)($_POST['id'] ?? 0);
    $name = normalizeNullableString($_POST['name'] ?? null);
    $code = normalizeNullableString($_POST['code'] ?? null);
    if ($name === null) respond(['status' => 'error', 'message' => 'Provider name is required']);

    if ($id > 0) {
        $stmt = $pdo->prepare("UPDATE fuel_card_providers SET name = :name, code = :code WHERE id = :id AND deleted_at IS NULL");
        $stmt->execute(['name' => $name, 'code' => $code, 'id' => $id]);
        doAudit($pdo, 'update', "Updated fuel card provider: {$name}", $id);
    } else {
        $stmt = $pdo->prepare("INSERT INTO fuel_card_providers (name, code) VALUES (:name, :code)");
        $stmt->execute(['name' => $name, 'code' => $code]);
        $id = (int)$pdo->lastInsertId();
        doAudit($pdo, 'create', "Created fuel card provider: {$name}", $id);
    }
    respond(['status' => 'success', 'data' => ['id' => $id]]);
}

function handleDeleteProvider(PDO $pdo): void
{
    enforceFuelCardWritePermission();
    $id = (int)($_POST['id'] ?? 0);
    if ($id <= 0) respond(['status' => 'error', 'message' => 'Invalid ID']);
    softDelete($pdo, 'fuel_card_providers', $id);
    doAudit($pdo, 'delete', "Deleted fuel card provider #{$id}", $id);
    respond(['status' => 'success']);
}

function handleList(PDO $pdo): void
{
    $where = ['fc.deleted_at IS NULL'];
    $params = [];

    $status = trim((string)($_GET['status'] ?? ''));
    $providerId = (int)($_GET['provider_id'] ?? 0);
    $search = trim((string)($_GET['search'] ?? ''));

    if ($status !== '') { $where[] = 'fc.status = :status'; $params['status'] = $status; }
    if ($providerId > 0) { $where[] = 'fc.provider_id = :provider_id'; $params['provider_id'] = $providerId; }
    if ($search !== '') { $where[] = '(fc.card_number_masked LIKE :search OR p.name LIKE :search)'; $params['search'] = "%{$search}%"; }

    $whereSql = 'WHERE ' . implode(' AND ', $where);
    $stmt = $pdo->prepare("
        SELECT fc.*, p.name AS provider_name,
               CASE
                   WHEN fc.assigned_to_type = 'vehicle' THEN (SELECT plate_number FROM vehicles WHERE id = fc.assigned_to_id)
                   WHEN fc.assigned_to_type = 'driver' THEN (SELECT COALESCE(full_name, CONCAT_WS(' ', first_name, surname)) FROM drivers WHERE id = fc.assigned_to_id)
                   ELSE NULL
               END AS assigned_to_name
        FROM fuel_cards fc
        LEFT JOIN fuel_card_providers p ON p.id = fc.provider_id
        {$whereSql}
        ORDER BY fc.created_at DESC
        LIMIT 200
    ");
    $stmt->execute($params);
    $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);

    $totalActive = $pdo->query("SELECT COUNT(*) FROM fuel_cards WHERE status = 'active' AND deleted_at IS NULL")->fetchColumn();
    $totalBalance = $pdo->query("SELECT COALESCE(SUM(current_balance),0) FROM fuel_cards WHERE status = 'active' AND deleted_at IS NULL")->fetchColumn();

    respond(['status' => 'success', 'data' => $rows, 'total_active' => (int)$totalActive, 'total_balance' => (float)$totalBalance]);
}

function handleSave(PDO $pdo): void
{
    enforceFuelCardWritePermission();
    $id = (int)($_POST['id'] ?? 0);
    $cardNumber = normalizeNullableString($_POST['card_number'] ?? null);
    if ($cardNumber === null) respond(['status' => 'error', 'message' => 'Card number is required']);

    $cardNumberMasked = substr($cardNumber, 0, 6) . '****' . substr($cardNumber, -4);
    $cardType = normalizeNullableString($_POST['card_type'] ?? null) ?: 'physical';
    $providerId = normalizeNullableInt($_POST['provider_id'] ?? null);
    $assignedToType = normalizeNullableString($_POST['assigned_to_type'] ?? null) ?: 'none';
    $assignedToId = normalizeNullableInt($_POST['assigned_to_id'] ?? null);
    $monthlyLimit = normalizeNullableDecimal($_POST['monthly_limit'] ?? null);
    $perTransactionLimit = normalizeNullableDecimal($_POST['per_transaction_limit'] ?? null);
    $currentBalance = normalizeNullableDecimal($_POST['current_balance'] ?? null) ?? 0;
    $status = normalizeNullableString($_POST['status'] ?? null) ?: 'active';
    $issuedDate = normalizeNullableDate($_POST['issued_date'] ?? null);
    $expiryDate = normalizeNullableDate($_POST['expiry_date'] ?? null);
    $notes = normalizeNullableString($_POST['notes'] ?? null);

    if ($id > 0) {
        $stmt = $pdo->prepare("
            UPDATE fuel_cards SET card_number = :card_number, card_number_masked = :card_number_masked,
                card_type = :card_type, provider_id = :provider_id,
                assigned_to_type = :assigned_to_type, assigned_to_id = :assigned_to_id,
                monthly_limit = :monthly_limit, per_transaction_limit = :per_transaction_limit,
                current_balance = :current_balance, status = :status,
                issued_date = :issued_date, expiry_date = :expiry_date, notes = :notes
            WHERE id = :id AND deleted_at IS NULL
        ");
        $stmt->execute([
            'card_number' => $cardNumber, 'card_number_masked' => $cardNumberMasked,
            'card_type' => $cardType, 'provider_id' => $providerId,
            'assigned_to_type' => $assignedToType, 'assigned_to_id' => $assignedToId,
            'monthly_limit' => $monthlyLimit, 'per_transaction_limit' => $perTransactionLimit,
            'current_balance' => $currentBalance, 'status' => $status,
            'issued_date' => $issuedDate, 'expiry_date' => $expiryDate, 'notes' => $notes,
            'id' => $id
        ]);
        doAudit($pdo, 'update', "Updated fuel card: {$cardNumberMasked}", $id);
    } else {
        $stmt = $pdo->prepare("
            INSERT INTO fuel_cards (card_number, card_number_masked, card_type, provider_id,
                assigned_to_type, assigned_to_id, monthly_limit, per_transaction_limit,
                current_balance, status, issued_date, expiry_date, notes)
            VALUES (:card_number, :card_number_masked, :card_type, :provider_id,
                :assigned_to_type, :assigned_to_id, :monthly_limit, :per_transaction_limit,
                :current_balance, :status, :issued_date, :expiry_date, :notes)
        ");
        $stmt->execute([
            'card_number' => $cardNumber, 'card_number_masked' => $cardNumberMasked,
            'card_type' => $cardType, 'provider_id' => $providerId,
            'assigned_to_type' => $assignedToType, 'assigned_to_id' => $assignedToId,
            'monthly_limit' => $monthlyLimit, 'per_transaction_limit' => $perTransactionLimit,
            'current_balance' => $currentBalance, 'status' => $status,
            'issued_date' => $issuedDate, 'expiry_date' => $expiryDate, 'notes' => $notes
        ]);
        $id = (int)$pdo->lastInsertId();
        doAudit($pdo, 'create', "Created fuel card: {$cardNumberMasked}", $id);
    }
    respond(['status' => 'success', 'data' => ['id' => $id]]);
}

function handleCard(PDO $pdo): void
{
    $id = (int)($_GET['id'] ?? 0);
    if ($id <= 0) respond(['status' => 'error', 'message' => 'Invalid card ID']);
    $stmt = $pdo->prepare("
        SELECT fc.*, p.name AS provider_name
        FROM fuel_cards fc
        LEFT JOIN fuel_card_providers p ON p.id = fc.provider_id
        WHERE fc.id = ? AND fc.deleted_at IS NULL
    ");
    $stmt->execute([$id]);
    $row = $stmt->fetch(PDO::FETCH_ASSOC);
    if (!$row) respond(['status' => 'error', 'message' => 'Card not found']);
    respond(['status' => 'success', 'data' => $row]);
}

function handleDelete(PDO $pdo): void
{
    enforceFuelCardWritePermission();
    $id = (int)($_POST['id'] ?? 0);
    if ($id <= 0) respond(['status' => 'error', 'message' => 'Invalid ID']);
    softDelete($pdo, 'fuel_cards', $id);
    doAudit($pdo, 'delete', "Deleted fuel card #{$id}", $id);
    respond(['status' => 'success']);
}

function handleTransactions(PDO $pdo): void
{
    $cardId = (int)($_GET['card_id'] ?? 0);
    $where = ['fct.id > 0'];
    $params = [];

    if ($cardId > 0) { $where[] = 'fct.fuel_card_id = :card_id'; $params['card_id'] = $cardId; }

    $whereSql = 'WHERE ' . implode(' AND ', $where);
    $stmt = $pdo->prepare("
        SELECT fct.*, fc.card_number_masked, u.name AS created_by_name
        FROM fuel_card_transactions fct
        LEFT JOIN fuel_cards fc ON fc.id = fct.fuel_card_id
        LEFT JOIN users u ON u.id = fct.created_by_user_id
        {$whereSql}
        ORDER BY fct.created_at DESC
        LIMIT 200
    ");
    $stmt->execute($params);
    respond(['status' => 'success', 'data' => $stmt->fetchAll(PDO::FETCH_ASSOC)]);
}

function handleLogTransaction(PDO $pdo): void
{
    enforceFuelCardWritePermission();
    $cardId = (int)($_POST['fuel_card_id'] ?? 0);
    $type = normalizeNullableString($_POST['transaction_type'] ?? null) ?: 'purchase';
    $amount = normalizeNullableDecimal($_POST['amount'] ?? null);
    $notes = normalizeNullableString($_POST['notes'] ?? null);
    $entryId = normalizeNullableInt($_POST['vehicle_fuel_entry_id'] ?? null);

    if ($cardId <= 0 || $amount === null) respond(['status' => 'error', 'message' => 'Card ID and amount are required']);

    $stmt = $pdo->prepare("SELECT current_balance FROM fuel_cards WHERE id = ? AND deleted_at IS NULL");
    $stmt->execute([$cardId]);
    $card = $stmt->fetch(PDO::FETCH_ASSOC);
    if (!$card) respond(['status' => 'error', 'message' => 'Card not found']);

    $balanceBefore = (float)($card['current_balance'] ?? 0);
    $balanceAfter = $type === 'purchase' || $type === 'fee'
        ? $balanceBefore - abs((float)$amount)
        : $balanceBefore + abs((float)$amount);

    $pdo->prepare("
        INSERT INTO fuel_card_transactions (fuel_card_id, transaction_type, amount, balance_before, balance_after, reference, vehicle_fuel_entry_id, notes, created_by_user_id)
        VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
    ")->execute([
        $cardId, $type, $amount, $balanceBefore, $balanceAfter,
        normalizeNullableString($_POST['reference'] ?? null),
        $entryId, $notes, (int)($_SESSION['user_id'] ?? 0)
    ]);

    $pdo->prepare("UPDATE fuel_cards SET current_balance = ? WHERE id = ?")->execute([$balanceAfter, $cardId]);

    doAudit($pdo, 'create', "Logged {$type} transaction on card #{$cardId}: {$amount}", $cardId);
    respond(['status' => 'success']);
}

function normalizeNullableString(?string $value): ?string
{
    if ($value === null || $value === '') return null;
    return trim($value);
}

function normalizeNullableInt(?string $value): ?int
{
    if ($value === null || $value === '' || $value === '0') return null;
    $v = (int)$value;
    return $v > 0 ? $v : null;
}

function normalizeNullableDecimal(?string $value): ?float
{
    if ($value === null || $value === '') return null;
    $v = (float)str_replace(',', '', $value);
    return $v;
}

function normalizeNullableDate(?string $value): ?string
{
    if ($value === null || $value === '') return null;
    $d = date_parse($value);
    if ($d['error_count'] > 0 || $d['warning_count'] > 0) return null;
    return date('Y-m-d', strtotime($value));
}
