<?php
declare(strict_types=1);

header('Content-Type: application/json');
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Headers: Content-Type, Authorization, X-User-Id');
header('Access-Control-Allow-Methods: GET, POST, OPTIONS');

if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
    http_response_code(204);
    exit;
}

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

$authHelper = __DIR__ . '/../../includes/auth_helper.php';
if (file_exists($authHelper)) {
    require_once $authHelper;
}

function ld_json(array $data, int $code = 200): void {
    http_response_code($code);
    echo json_encode($data, JSON_UNESCAPED_SLASHES);
    exit;
}

function ld_pdo(): PDO {
    global $pdo, $conn, $db;

    if (isset($pdo) && $pdo instanceof PDO) return $pdo;
    if (isset($conn) && $conn instanceof PDO) return $conn;
    if (isset($db) && $db instanceof PDO) return $db;

    ld_json(['success' => false, 'message' => 'Database connection not found.'], 500);
}

function ld_body(): array {
    $raw = file_get_contents('php://input');
    $json = json_decode($raw ?: '', true);
    if (is_array($json)) return $json;
    return $_POST ?: [];
}

function ld_current_user_id(): int {
    $possibleFns = [
        'getAuthenticatedUserId',
        'getCurrentUserId',
        'current_user_id',
        'require_auth_user_id',
    ];

    foreach ($possibleFns as $fn) {
        if (function_exists($fn)) {
            try {
                $ref = new ReflectionFunction($fn);
                if ($ref->getNumberOfRequiredParameters() === 0) {
                    $id = $fn();
                    if (is_numeric($id) && (int)$id > 0) return (int)$id;
                }
            } catch (Throwable $e) {
                // Fall through to test header.
            }
        }
    }

    // TEMP DEV/TEST fallback. Replace with real JWT auth before production.
    $headerId = $_SERVER['HTTP_X_USER_ID'] ?? '';
    if (is_numeric($headerId) && (int)$headerId > 0) {
        return (int)$headerId;
    }

    ld_json(['success' => false, 'message' => 'Unauthorized. Missing valid user session.'], 401);
}

function ld_columns(PDO $pdo, string $table): array {
    static $cache = [];
    if (isset($cache[$table])) return $cache[$table];

    try {
        $stmt = $pdo->query("SHOW COLUMNS FROM `$table`");
        $cols = [];
        foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
            $cols[] = $row['Field'];
        }
        return $cache[$table] = $cols;
    } catch (Throwable $e) {
        return $cache[$table] = [];
    }
}

function ld_table_exists(PDO $pdo, string $table): bool {
    try {
        $stmt = $pdo->prepare("SHOW TABLES LIKE ?");
        $stmt->execute([$table]);
        return (bool)$stmt->fetchColumn();
    } catch (Throwable $e) {
        return false;
    }
}

function ld_paystack_secret(): string {
    $secret = getenv('PAYSTACK_SECRET_KEY');
    if (!$secret) {
        ld_json(['success' => false, 'message' => 'PAYSTACK_SECRET_KEY is missing on server.'], 500);
    }
    return $secret;
}

function ld_paystack_request(string $method, string $path, ?array $payload = null): array {
    $secret = ld_paystack_secret();
    $url = 'https://api.paystack.co' . $path;

    $ch = curl_init($url);
    $headers = [
        'Authorization: Bearer ' . $secret,
        'Content-Type: application/json',
        'Accept: application/json',
    ];

    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_CUSTOMREQUEST => strtoupper($method),
        CURLOPT_HTTPHEADER => $headers,
        CURLOPT_TIMEOUT => 30,
    ]);

    if ($payload !== null) {
        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload));
    }

    $response = curl_exec($ch);
    $err = curl_error($ch);
    $http = (int)curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);

    if ($response === false) {
        return ['status' => false, 'message' => 'Curl error: ' . $err, 'http_code' => $http];
    }

    $json = json_decode($response, true);
    if (!is_array($json)) {
        return ['status' => false, 'message' => 'Invalid Paystack response', 'raw' => $response, 'http_code' => $http];
    }

    $json['http_code'] = $http;
    return $json;
}

function ld_get_user(PDO $pdo, int $userId): array {
    $cols = ld_columns($pdo, 'users');

    $select = ['id'];
    $select[] = in_array('email', $cols, true) ? 'email' : "NULL AS email";
    $select[] = in_array('country_code', $cols, true) ? 'country_code' : "NULL AS country_code";

    $sql = "SELECT " . implode(',', $select) . " FROM users WHERE id = ? LIMIT 1";
    $stmt = $pdo->prepare($sql);
    $stmt->execute([$userId]);
    $user = $stmt->fetch(PDO::FETCH_ASSOC);

    if (!$user) {
        ld_json(['success' => false, 'message' => 'User not found.'], 404);
    }

    if (empty($user['email'])) {
        $user['email'] = 'player' . $userId . '@ludodragon.local';
    }

    return $user;
}

function ld_get_gateway_config(PDO $pdo, string $countryCode): array {
    $stmt = $pdo->prepare("
        SELECT *
        FROM payment_gateway_configs
        WHERE country_code = ?
          AND provider = 'paystack'
          AND status = 'active'
          AND is_deposit_enabled = 1
        LIMIT 1
    ");
    $stmt->execute([strtoupper($countryCode)]);
    $config = $stmt->fetch(PDO::FETCH_ASSOC);

    if (!$config) {
        ld_json(['success' => false, 'message' => 'Paystack is not enabled for this country.'], 400);
    }

    return $config;
}

function ld_reference(int $userId): string {
    return 'LDDEP_' . $userId . '_' . time() . '_' . bin2hex(random_bytes(4));
}

function ld_to_minor_units(float $amount): int {
    return (int)round($amount * 100);
}

function ld_from_minor_units(int $amountMinor): float {
    return round($amountMinor / 100, 2);
}

function ld_insert_wallet_transaction(PDO $pdo, int $userId, float $amount, string $currency, string $reference, string $description): void {
    $cols = ld_columns($pdo, 'wallet_transactions');

    if (!$cols) {
        throw new RuntimeException('wallet_transactions table/columns not found.');
    }

    $required = ['user_id', 'wallet_type', 'amount', 'transaction_type', 'txn_ref', 'description'];
    foreach ($required as $col) {
        if (!in_array($col, $cols, true)) {
            throw new RuntimeException("wallet_transactions.$col column not found.");
        }
    }

    $candidate = [
        'user_id' => $userId,
        'wallet_type' => 'play_balance',
        'amount' => $amount,
        'currency_code' => $currency,
        'transaction_type' => 'deposit',
        'txn_ref' => $reference,
        'description' => $description,
        'reference' => $reference,
        'transaction_ref' => $reference,
        'gateway_reference' => $reference,
        'provider' => 'paystack',
        'created_at' => date('Y-m-d H:i:s'),
        'updated_at' => date('Y-m-d H:i:s'),
    ];

    $data = [];
    foreach ($candidate as $col => $value) {
        if (in_array($col, $cols, true)) {
            $data[$col] = $value;
        }
    }

    $fields = array_keys($data);
    $placeholders = array_fill(0, count($fields), '?');

    $sql = "INSERT INTO wallet_transactions (`" . implode('`,`', $fields) . "`) VALUES (" . implode(',', $placeholders) . ")";
    $stmt = $pdo->prepare($sql);
    $stmt->execute(array_values($data));
}

function ld_credit_play_balance(PDO $pdo, int $userId, float $amount): void {
    $cols = ld_columns($pdo, 'users');

    if (!in_array('play_balance', $cols, true)) {
        throw new RuntimeException('users.play_balance column not found.');
    }

    $stmt = $pdo->prepare("UPDATE users SET play_balance = play_balance + ? WHERE id = ?");
    $stmt->execute([$amount, $userId]);
}

function ld_process_successful_deposit(PDO $pdo, string $reference, array $verifyResponse): array {
    $data = $verifyResponse['data'] ?? [];

    if (($data['status'] ?? '') !== 'success') {
        return [
            'success' => false,
            'status' => $data['status'] ?? 'unknown',
            'message' => 'Transaction is not successful yet.',
        ];
    }

    $paystackAmountMinor = (int)($data['amount'] ?? 0);
    $paystackCurrency = strtoupper((string)($data['currency'] ?? ''));
    $paystackFeesMinor = (int)($data['fees'] ?? 0);

    $pdo->beginTransaction();

    try {
        $stmt = $pdo->prepare("
            SELECT *
            FROM payment_deposit_intents
            WHERE internal_reference = ? OR gateway_reference = ?
            LIMIT 1
            FOR UPDATE
        ");
        $stmt->execute([$reference, $reference]);
        $intent = $stmt->fetch(PDO::FETCH_ASSOC);

        if (!$intent) {
            throw new RuntimeException('Deposit intent not found.');
        }

        if ((int)$intent['credited_wallet'] === 1 && $intent['status'] === 'paid') {
            $pdo->commit();
            return [
                'success' => true,
                'status' => 'paid',
                'already_credited' => true,
                'amount' => $intent['amount'],
                'currency_code' => $intent['currency_code'],
                'reference' => $intent['internal_reference'],
            ];
        }

        if ((int)$intent['amount_minor'] !== $paystackAmountMinor) {
            throw new RuntimeException('Amount mismatch.');
        }

        if (strtoupper($intent['currency_code']) !== $paystackCurrency) {
            throw new RuntimeException('Currency mismatch.');
        }

        $userId = (int)$intent['user_id'];
        $amount = (float)$intent['amount'];
        $fee = ld_from_minor_units($paystackFeesMinor);
        $net = max(0, round($amount - $fee, 2));
        $currency = strtoupper($intent['currency_code']);

        ld_credit_play_balance($pdo, $userId, $amount);

        ld_insert_wallet_transaction(
            $pdo,
            $userId,
            $amount,
            $currency,
            $intent['internal_reference'],
            'Paystack deposit credited: ' . $intent['internal_reference']
        );

        $update = $pdo->prepare("
            UPDATE payment_deposit_intents
            SET status = 'paid',
                credited_wallet = 1,
                gateway_fee = ?,
                wallet_credit_amount = ?,
                net_settlement_amount = ?,
                raw_response = ?,
                paid_at = NOW()
            WHERE id = ?
        ");
        $update->execute([
            $fee,
            $amount,
            $net,
            json_encode($verifyResponse, JSON_UNESCAPED_SLASHES),
            $intent['id'],
        ]);

        $pdo->commit();

        return [
            'success' => true,
            'status' => 'paid',
            'already_credited' => false,
            'amount' => number_format($amount, 2, '.', ''),
            'currency_code' => $currency,
            'gateway_fee_absorbed_by_benaplay' => number_format($fee, 2, '.', ''),
            'wallet_credit_amount' => number_format($amount, 2, '.', ''),
            'reference' => $intent['internal_reference'],
        ];
    } catch (Throwable $e) {
        if ($pdo->inTransaction()) $pdo->rollBack();
        throw $e;
    }
}
