<?php

require_once __DIR__ . '/whatsapp.php';
require_once __DIR__ . '/bayarvip.php';
require_once __DIR__ . '/agent_identity.php';

function topup_ensure_agent_rate_column(mysqli $db): bool
{
    static $checked = false;

    if ($checked) {
        return true;
    }

    $checked = true;
    $columnQuery = mysqli_query($db, "SHOW COLUMNS FROM tb_agent LIKE 'rate_coin'");

    if ($columnQuery && mysqli_num_rows($columnQuery) > 0) {
        return true;
    }

    return (bool)mysqli_query(
        $db,
        "ALTER TABLE tb_agent ADD COLUMN rate_coin DECIMAL(12,4) NULL DEFAULT NULL AFTER agent_balance"
    );
}

function topup_qris_method_value(): string
{
    return 'BAYARVIP_QRIS';
}

function topup_is_qris_method(string $paymentMethod): bool
{
    $method = strtoupper(trim($paymentMethod));
    return in_array($method, ['BAYARVIP_QRIS', 'QRIS'], true);
}

function topup_get_settings(mysqli $db): array
{
    topup_ensure_agent_rate_column($db);

    $defaults = [
        'min_topup' => 0,
        'rate_coin' => 7.5,
    ];

    $query = mysqli_query($db, "SELECT min_topup, rate_coin FROM tb_settings LIMIT 1");

    if (!$query || mysqli_num_rows($query) === 0) {
        return $defaults;
    }

    $row = mysqli_fetch_assoc($query) ?: [];

    return [
        'min_topup' => (float)($row['min_topup'] ?? 0),
        'rate_coin' => (float)($row['rate_coin'] ?? 7.5),
    ];
}

function topup_get_global_rate(mysqli $db): float
{
    $settings = topup_get_settings($db);
    $rate = (float)($settings['rate_coin'] ?? 7.5);

    return $rate > 0 ? $rate : 7.5;
}

function topup_get_agent_rate(mysqli $db, string $agentCode): float
{
    topup_ensure_agent_rate_column($db);

    $fallback = topup_get_global_rate($db);
    $agentCode = mysqli_real_escape_string($db, trim($agentCode));

    if ($agentCode === '') {
        return $fallback;
    }

    $agent = agent_find_by_identifier($db, $agentCode);
    if ($agent === null) {
        return $fallback;
    }

    $rate = (float)($agent['rate_coin'] ?? 0);

    return $rate > 0 ? $rate : $fallback;
}

function topup_calculate_coin_amount(mysqli $db, float $amount, string $agentCode = ''): float
{
    $rate = topup_get_agent_rate($db, $agentCode);

    return $rate > 0 ? floor($amount / ($rate / 100)) : 0;
}

function topup_create_request(mysqli $db, array $payload): array
{
    $agentInput = trim((string)($payload['agent_code'] ?? ($payload['agent_name'] ?? '')));
    $agent = agent_find_by_identifier($db, $agentInput);
    $agentCode = $agent !== null ? agent_public_name($agent) : $agentInput;
    $agentCode = mysqli_real_escape_string($db, trim($agentCode));
    $whatsapp = wa_normalize_number((string)($payload['whatsapp'] ?? ''));
    $amount = (float)($payload['amount'] ?? 0);
    $paymentMethod = mysqli_real_escape_string($db, trim((string)($payload['payment_method'] ?? '')));
    $namaRekening = mysqli_real_escape_string($db, trim((string)($payload['nama_rekening'] ?? '')));
    $nomorRekening = mysqli_real_escape_string($db, trim((string)($payload['nomor_rekening'] ?? '')));

    if ($agentCode === '') {
        return ['ok' => false, 'code' => 'agent_not_found'];
    }

    if ($whatsapp === '' || strlen($whatsapp) < 10 || strlen($whatsapp) > 16) {
        return ['ok' => false, 'code' => 'invalid_whatsapp'];
    }

    if ($paymentMethod === '' || $paymentMethod === '0') {
        return ['ok' => false, 'code' => 'payment_method_required'];
    }

    $settings = topup_get_settings($db);
    $rateCoin = topup_get_agent_rate($db, $agentCode);
    $balance = topup_calculate_coin_amount($db, $amount, $agentCode);

    if ($balance <= 0) {
        return ['ok' => false, 'code' => 'invalid_balance'];
    }

    if ($amount <= 0) {
        return ['ok' => false, 'code' => 'invalid_amount'];
    }

    if ($amount < (float)$settings['min_topup']) {
        return ['ok' => false, 'code' => 'below_minimum'];
    }

    $agentBalanceWhere = $agent !== null ? agent_reference_condition($db, 'agent_code', $agent) : "agent_code = '$agentCode'";
    $pendingQuery = mysqli_query($db, "SELECT id FROM tb_balance WHERE $agentBalanceWhere AND status = 'Pending' LIMIT 1");
    if ($pendingQuery && mysqli_num_rows($pendingQuery) > 0) {
        return ['ok' => false, 'code' => 'already_pending'];
    }

    if (topup_is_qris_method($paymentMethod)) {
        $gatewayResult = bayarvip_create_payment($db, $agentCode, (int)$amount);

        if (!$gatewayResult['ok']) {
            return [
                'ok' => false,
                'code' => (string)($gatewayResult['code'] ?? 'bayarvip_failed'),
                'gateway' => $gatewayResult,
            ];
        }

        $gatewayData = is_array($gatewayResult['data'] ?? null) ? $gatewayResult['data'] : [];
        $trxid = mysqli_real_escape_string($db, trim((string)($gatewayData['transaction_id'] ?? '')));
        $paymentId = mysqli_real_escape_string($db, trim((string)(
            $gatewayData['payment_id']
            ?? $gatewayData['order_id']
            ?? $gatewayData['idrpayment_id']
            ?? ''
        )));
        $qrUrl = trim((string)($gatewayData['qr_url'] ?? ''));
        $qrString = trim((string)($gatewayData['qr_string'] ?? ($gatewayData['qr'] ?? '')));

        if ($trxid === '') {
            return ['ok' => false, 'code' => 'bayarvip_invalid_response'];
        }

        $paymentMethod = topup_qris_method_value();
        $namaRekening = 'QRIS Otomatis';
        $nomorRekening = $paymentId !== '' ? $paymentId : $trxid;

        $created = date('Y-m-d H:i:s');
        $dateCr = date('Y-m-d');
        $checkoutUrl = wa_app_base_url() . '/Invoice?trxid=' . urlencode($trxid);

        $query = "INSERT INTO tb_balance (
            id, trxid, agent_code, balance, amount, created, date_cr, metode,
            nama_rekening, nomor_rekening, status, whatsapp, checkout
        ) VALUES (
            NULL, '$trxid', '$agentCode', '$balance', '$amount', '$created', '$dateCr', '$paymentMethod',
            '$namaRekening', '$nomorRekening', 'Pending', '$whatsapp', '$checkoutUrl'
        )";

        if (!mysqli_query($db, $query)) {
            return [
                'ok' => false,
                'code' => 'insert_failed',
                'error' => mysqli_error($db),
            ];
        }

        return [
            'ok' => true,
            'trxid' => $trxid,
            'agent_code' => $agentCode,
            'whatsapp' => $whatsapp,
            'amount' => $amount,
            'balance' => $balance,
            'payment_method' => $paymentMethod,
            'nama_rekening' => $namaRekening,
            'nomor_rekening' => $nomorRekening,
            'created' => $created,
            'checkout_url' => $checkoutUrl,
            'rate_coin' => $rateCoin,
            'min_topup' => (float)$settings['min_topup'],
            'gateway' => [
                'transaction_id' => $trxid,
                'payment_id' => $paymentId,
                'qr_url' => $qrUrl !== '' ? $qrUrl : bayarvip_qr_url($db, $trxid),
                'qr_string' => $qrString,
                'invoice_amount' => (float)($gatewayData['invoice_amount'] ?? $amount),
                'customer_payment_amount' => (float)($gatewayData['customer_payment_amount'] ?? $amount),
                'expire_date' => (string)($gatewayData['expire_date'] ?? ''),
            ],
        ];
    }

    $billingQuery = mysqli_query($db, "SELECT * FROM tb_billing WHERE bank = '$paymentMethod' LIMIT 1");
    if (!$billingQuery || mysqli_num_rows($billingQuery) === 0) {
        return ['ok' => false, 'code' => 'payment_method_not_found'];
    }

    $billing = mysqli_fetch_assoc($billingQuery) ?: [];
    $namaRekening = $namaRekening !== '' ? $namaRekening : mysqli_real_escape_string($db, (string)($billing['nama_rekening'] ?? ''));
    $nomorRekening = $nomorRekening !== '' ? $nomorRekening : mysqli_real_escape_string($db, (string)($billing['nomor_rekening'] ?? ''));

    $created = date('Y-m-d H:i:s');
    $dateCr = date('Y-m-d');
    $trxid = md5($agentCode . '|' . $created . '|' . uniqid('', true));
    $checkoutUrl = wa_app_base_url() . '/Invoice?trxid=' . urlencode($trxid);

    $query = "INSERT INTO tb_balance (
        id, trxid, agent_code, balance, amount, created, date_cr, metode,
        nama_rekening, nomor_rekening, status, whatsapp, checkout
    ) VALUES (
        NULL, '$trxid', '$agentCode', '$balance', '$amount', '$created', '$dateCr', '$paymentMethod',
        '$namaRekening', '$nomorRekening', 'Pending', '$whatsapp', '$checkoutUrl'
    )";

    if (!mysqli_query($db, $query)) {
        return [
            'ok' => false,
            'code' => 'insert_failed',
            'error' => mysqli_error($db),
        ];
    }

    return [
        'ok' => true,
        'trxid' => $trxid,
        'agent_code' => $agentCode,
        'whatsapp' => $whatsapp,
        'amount' => $amount,
        'balance' => $balance,
        'payment_method' => $paymentMethod,
        'nama_rekening' => (string)($billing['nama_rekening'] ?? $namaRekening),
        'nomor_rekening' => (string)($billing['nomor_rekening'] ?? $nomorRekening),
        'created' => $created,
        'checkout_url' => $checkoutUrl,
        'rate_coin' => $rateCoin,
        'min_topup' => (float)$settings['min_topup'],
    ];
}

function topup_error_to_msg_code(string $code): int
{
    $map = [
        'invalid_whatsapp' => 50,
        'payment_method_required' => 23,
        'invalid_balance' => 25,
        'below_minimum' => 27,
        'invalid_amount' => 5,
        'already_pending' => 26,
        'payment_method_not_found' => 28,
        'insert_failed' => 13,
        'agent_not_found' => 8,
        'bayarvip_not_configured' => 72,
        'bayarvip_failed' => 73,
        'bayarvip_invalid_response' => 73,
    ];

    return $map[$code] ?? 13;
}

function topup_find_by_trxid(mysqli $db, string $trxid): ?array
{
    $trxid = mysqli_real_escape_string($db, trim($trxid));

    if ($trxid === '') {
        return null;
    }

    $query = mysqli_query($db, "SELECT * FROM tb_balance WHERE trxid = '$trxid' LIMIT 1");

    if (!$query || mysqli_num_rows($query) === 0) {
        return null;
    }

    return mysqli_fetch_assoc($query) ?: null;
}

function topup_finalize_request(mysqli $db, int $id, string $action): array
{
    if ($id <= 0 || !in_array($action, ['Success', 'Cancel'], true)) {
        return ['ok' => false, 'code' => 'invalid_action'];
    }

    mysqli_begin_transaction($db);

    $topupQuery = mysqli_query($db, "SELECT * FROM tb_balance WHERE id = '$id' LIMIT 1 FOR UPDATE");

    if (!$topupQuery || mysqli_num_rows($topupQuery) === 0) {
        mysqli_rollback($db);
        return ['ok' => false, 'code' => 'not_found'];
    }

    $topup = mysqli_fetch_assoc($topupQuery) ?: [];
    $currentStatus = (string)($topup['status'] ?? '');

    if ($currentStatus !== 'Pending') {
        mysqli_commit($db);
        return [
            'ok' => true,
            'already_processed' => true,
            'status' => $currentStatus,
            'topup' => $topup,
        ];
    }

    $agentInput = (string)($topup['agent_code'] ?? '');
    $agent = agent_find_by_identifier($db, $agentInput);
    $agentCode = mysqli_real_escape_string($db, $agent !== null ? (string)($agent['agent_code'] ?? agent_public_name($agent)) : $agentInput);
    $agentName = mysqli_real_escape_string($db, $agent !== null ? agent_public_name($agent) : $agentInput);
    $balance = (float)($topup['balance'] ?? 0);
    $price = (float)($topup['amount'] ?? 0);
    $metode = mysqli_real_escape_string($db, (string)($topup['metode'] ?? ''));
    $namaRekening = mysqli_real_escape_string($db, (string)($topup['nama_rekening'] ?? ''));
    $nomorRekening = mysqli_real_escape_string($db, (string)($topup['nomor_rekening'] ?? ''));

    $updateBalance = mysqli_query(
        $db,
        "UPDATE tb_balance SET status = '$action' WHERE id = '$id' AND status = 'Pending'"
    );

    if (!$updateBalance || mysqli_affected_rows($db) !== 1) {
        mysqli_rollback($db);
        return ['ok' => false, 'code' => 'update_failed'];
    }

    if ($action === 'Success') {
        $updateAgent = mysqli_query(
            $db,
            "UPDATE tb_agent SET agent_balance = agent_balance + '$balance' WHERE agent_code = '$agentCode'"
        );

        if (!$updateAgent || mysqli_affected_rows($db) !== 1) {
            mysqli_rollback($db);
            return ['ok' => false, 'code' => 'balance_update_failed'];
        }
    }

    if (topup_is_qris_method($metode) || $action === 'Success') {
        $insertTransaksi = mysqli_query(
            $db,
            "INSERT INTO tb_topup (agent_code, amount, harga, metode, nama_rekening, nomor_rekening, tanggal, status)
             VALUES ('$agentName', '$balance', '$price', '$metode', '$namaRekening', '$nomorRekening', NOW(), '$action')"
        );

        if (!$insertTransaksi) {
            mysqli_rollback($db);
            return ['ok' => false, 'code' => 'history_insert_failed'];
        }
    }

    if (!mysqli_commit($db)) {
        mysqli_rollback($db);
        return ['ok' => false, 'code' => 'commit_failed'];
    }

    $topup['status'] = $action;

    return [
        'ok' => true,
        'already_processed' => false,
        'status' => $action,
        'topup' => $topup,
    ];
}

function topup_agent_name(mysqli $db, string $agentCode): string
{
    $agent = agent_find_by_identifier($db, $agentCode);
    if ($agent === null) {
        $agentCode = trim($agentCode);
        return $agentCode !== '' ? $agentCode : '-';
    }

    return agent_public_name($agent);
}
