<?php
// ==========================================================
// ACCRA DIGITAL RESET (ADR) - USSD CALLBACK (FULL INTEGRATED)
// ==========================================================

error_reporting(E_ALL);
ini_set('display_errors', 1);
header('Content-Type: application/json');

include(__DIR__ . "/includes/db_connect.php");
date_default_timezone_set('Africa/Accra');

// ----------------------------------------------------------
// READ INPUT
// ----------------------------------------------------------
$rawInput = file_get_contents("php://input");
$data = json_decode($rawInput, true);
if (empty($data)) $data = $_POST;

$sessionID  = $data['sessionId'] ?? $data['sessionID'] ?? '';
$msisdn     = trim($data['msisdn'] ?? '');
$userData   = trim($data['text'] ?? $data['userData'] ?? '');
$newSession = $data['newSession'] ?? ($userData === "");

// Normalize Ghana MSISDN
if (substr($msisdn, 0, 3) === "233") {
    $msisdn = "0" . substr($msisdn, 3);
}


// ----------------------------------------------------------
// GET USER COUNTRY (for country-specific kill switch)
// ----------------------------------------------------------
$originCountry = substr($msisdn, 0, 1) === "0" ? "GH" : "UNKNOWN"; // simple mapping

// ----------------------------------------------------------
// KILL SWITCH CHECK WITH FRIENDLY MESSAGES
// ----------------------------------------------------------

// 1. Global kill switch
$globalKill = $conn->query("SELECT kill_switch, reason FROM country_kill_switch WHERE country_code='ALL' LIMIT 1")->fetch_assoc();
if (($globalKill['kill_switch'] ?? '0') === '1') {
    $msg = "⚠️ Service Temporarily Unavailable Globally.";
    if (!empty($globalKill['reason'])) $msg .= "\nReason: {$globalKill['reason']}";
    $msg .= "\nPlease try again later or contact support.";
    echo json_encode([
        "sessionID" => '',
        "msisdn" => $msisdn,
        "message" => $msg,
        "continueSession" => false
    ]);
    exit;
}

// 2. Country-specific kill switch
$countryKill = $conn->query("SELECT kill_switch, reason FROM country_kill_switch WHERE country_code='$originCountry' LIMIT 1")->fetch_assoc();
if (($countryKill['kill_switch'] ?? '0') === '1') {
    $msg = "⚠️ Service Temporarily Unavailable in your country ({$originCountry}).";
    if (!empty($countryKill['reason'])) $msg .= "\nReason: {$countryKill['reason']}";
    $msg .= "\nPlease try again later or contact support.";
    echo json_encode([
        "sessionID" => '',
        "msisdn" => $msisdn,
        "message" => $msg,
        "continueSession" => false
    ]);
    exit;
}

// ----------------------------------------------------------
// HELPERS
// ----------------------------------------------------------
function respond($sessionID, $msisdn, $message, $continue = true) {
    echo json_encode([
        "sessionID" => $sessionID,
        "msisdn" => $msisdn,
        "message" => $message,
        "continueSession" => $continue
    ]);
    exit;
}

function saveSession($conn, $sessionID, $step, $data = [], $lastInput = '') {
    $dataEsc = $conn->real_escape_string(json_encode($data));
    $lastEsc = $conn->real_escape_string($lastInput);
    $conn->query("
        UPDATE ussd_sessions
        SET current_step=$step, data='$dataEsc', last_input='$lastEsc'
        WHERE session_id='$sessionID'
    ");
}

function logAudit($conn, $ref, $action, $payload = []) {
    $p = $conn->real_escape_string(json_encode($payload));
    $conn->query("
        INSERT INTO audit_logs (transaction_ref, action, payload, created_at)
        VALUES ('$ref','$action','$p',NOW())
    ");
}


// ----------------------------------------------------------
// DB-DRIVEN PHONE VALIDATION
// ----------------------------------------------------------
function validateInternationalPhone($conn, $phone, $countryCode) {

    $phone = preg_replace('/\D/', '', $phone);

    $q = $conn->query("
        SELECT prefix, min_length, max_length, example
        FROM country_phone_rules
        WHERE country_code='$countryCode' AND active=1
        LIMIT 1
    ");

    if ($q->num_rows == 0) return false;

    $r = $q->fetch_assoc();

    if (
        str_starts_with($phone, $r['prefix']) &&
        strlen($phone) >= $r['min_length'] &&
        strlen($phone) <= $r['max_length']
    ) {
        return '+' . $phone;
    }

    return false;
}

function resolveLimit($conn, $msisdn, $userType, $limitType) {

    $sql = "
        SELECT max_amount
        FROM msisdn_limits
        WHERE
            (applies_to='MSISDN' AND msisdn='$msisdn')
            OR (applies_to='USER_TYPE' AND msisdn='$userType')
            OR (applies_to='ALL')
        AND limit_type='$limitType'
        ORDER BY FIELD(applies_to,'MSISDN','USER_TYPE','ALL')
        LIMIT 1
    ";

    $res = $conn->query($sql);

    return ($res && $res->num_rows)
        ? (float)$res->fetch_assoc()['max_amount']
        : 0;
}

function autoBlock($conn, $msisdn, $reason) {

    $reasonEsc = $conn->real_escape_string($reason);

    $conn->query("
        INSERT INTO msisdn_kill_switch (msisdn, blocked, reason, updated_at)
        VALUES ('$msisdn',1,'$reasonEsc',NOW())
        ON DUPLICATE KEY UPDATE
            blocked=1,
            reason='$reasonEsc',
            updated_at=NOW()
    ");
}



// ==========================================================
// DAILY + CUMULATIVE LIMIT CHECK (USER_TYPE AWARE)
// ==========================================================
function checkLimits($conn, $msisdn, $amount) {

    $today = date('Y-m-d');

    // --------------------------------------------------
    // 1. CHECK IF MSISDN IS ALREADY BLOCKED
    // --------------------------------------------------
    $blocked = $conn->query("
        SELECT blocked, reason
        FROM msisdn_kill_switch
        WHERE msisdn='$msisdn'
        LIMIT 1
    ")->fetch_assoc();

    if (($blocked['blocked'] ?? 0) == 1) {
        return "⚠️ Your account is temporarily blocked.\nReason: {$blocked['reason']}";
    }

    // --------------------------------------------------
    // 2. GET USER TYPE (SME / INDIVIDUAL)
    // --------------------------------------------------
    $userRow = $conn->query("
        SELECT user_type
        FROM users
        WHERE msisdn='$msisdn'
        LIMIT 1
    ")->fetch_assoc();

    $userType = $userRow['user_type'] ?? 'INDIVIDUAL';

    // --------------------------------------------------
    // 3. DAILY USAGE
    // --------------------------------------------------
    $dailyUsed = $conn->query("
        SELECT COALESCE(SUM(send_amount),0) AS total
        FROM transactions
        WHERE sender_msisdn='$msisdn'
        AND DATE(created_at)='$today'
        AND status IN ('QUEUED','SUCCESS')
    ")->fetch_assoc()['total'];

    // Resolve DAILY limit
    $dailyLimit = resolveLimit($conn, $msisdn, $userType, 'DAILY');

    if ($dailyLimit > 0 && ($dailyUsed + $amount) > $dailyLimit) {

        autoBlock(
            $conn,
            $msisdn,
            "Exceeded DAILY limit (Max GHS $dailyLimit)"
        );

        return "Daily limit exceeded.\nMax: GHS $dailyLimit\nYour account is temporarily blocked.";
    }

    // --------------------------------------------------
    // 4. CUMULATIVE USAGE
    // --------------------------------------------------
    $totalUsed = $conn->query("
        SELECT COALESCE(SUM(send_amount),0) AS total
        FROM transactions
        WHERE sender_msisdn='$msisdn'
        AND status IN ('QUEUED','SUCCESS')
    ")->fetch_assoc()['total'];

    // Resolve CUMULATIVE limit
    $cumLimit = resolveLimit($conn, $msisdn, $userType, 'CUMULATIVE');

    if ($cumLimit > 0 && ($totalUsed + $amount) > $cumLimit) {

        autoBlock(
            $conn,
            $msisdn,
            "Exceeded CUMULATIVE limit (Max GHS $cumLimit)"
        );

        return "Cumulative limit exceeded.\nMax: GHS $cumLimit\nYour account is temporarily blocked.";
    }

    return true;
}

// ----------------------------------------------------------
// SEND SMS FUNCTION
// ----------------------------------------------------------
function send_sms($phone, $message) {
    if (substr($phone, 0, 1) === '0') {
        $phone = '233' . substr($phone, 1);
    }

    $arkeselApiKey = "OmlmMERVeHJOdHhhT3BMUDQ=";
    $arkeselUrl = "https://sms.arkesel.com/sms/api";

    $queryParams = http_build_query([
        "action" => "send-sms",
        "api_key" => $arkeselApiKey,
        "to" => $phone,
        "from" => "Tekpulse",
        "sms" => $message
    ]);

    $ch = curl_init("$arkeselUrl?$queryParams");
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_FOLLOWLOCATION => true,
        CURLOPT_TIMEOUT => 10,
    ]);

    $response = curl_exec($ch);
    $err = curl_error($ch);
    curl_close($ch);

    if ($err) {
        error_log("send_sms error for $phone: $err");
    }
}


function maskNumber($number) {

    $number = preg_replace('/\D/', '', $number);

    $len = strlen($number);

    if ($len <= 7) return $number;

    $start = substr($number, 0, 6);      // first 6 digits
    $end   = substr($number, -3);        // last 3 digits

    return '+' . $start . '****' . $end;
}

function checkRecipientRisk($conn, $recipient) {

    $today = date('Y-m-d');

    // Total transactions today
    $totalToday = $conn->query("
        SELECT COUNT(*) AS total
        FROM transactions
        WHERE receiver_msisdn='$recipient'
        AND DATE(created_at)='$today'
        AND status IN ('QUEUED','SUCCESS')
    ")->fetch_assoc()['total'];

    // Unique senders today
    $uniqueSenders = $conn->query("
        SELECT COUNT(DISTINCT sender_msisdn) AS total
        FROM transactions
        WHERE receiver_msisdn='$recipient'
        AND DATE(created_at)='$today'
        AND status IN ('QUEUED','SUCCESS')
    ")->fetch_assoc()['total'];

    // Risk thresholds (you can tune these)
    if ($totalToday >= 10) {
        return "⚠️ Recipient temporarily restricted (high volume today).";
    }

    if ($uniqueSenders >= 5) {
        return "⚠️ Recipient flagged for unusual activity.";
    }

    return true;
}

function flagHighRiskRecipient($conn, $recipient, $reason, $score = 50, $blockMinutes = 60) {

    $recipient = $conn->real_escape_string($recipient);
    $reason    = $conn->real_escape_string($reason);

    $blockUntil = date('Y-m-d H:i:s', strtotime("+$blockMinutes minutes"));

    $conn->query("
        INSERT INTO high_risk_recipients 
        (msisdn, risk_reason, risk_score, flagged_at, blocked_until, active)
        VALUES 
        ('$recipient', '$reason', $score, NOW(), '$blockUntil', 1)
        ON DUPLICATE KEY UPDATE
            risk_reason='$reason',
            risk_score = risk_score + $score,
            flagged_at=NOW(),
            blocked_until='$blockUntil',
            active=1
    ");
}

function isRecipientBlocked($conn, $recipient) {

    $recipient = $conn->real_escape_string($recipient);

    $row = $conn->query("
        SELECT id, blocked_until
        FROM high_risk_recipients
        WHERE msisdn='$recipient'
        AND active=1
        LIMIT 1
    ")->fetch_assoc();

    if (!$row) return false;

    // If block expired → deactivate automatically
    if (strtotime($row['blocked_until']) <= time()) {

        $conn->query("
            UPDATE high_risk_recipients
            SET active=0
            WHERE id={$row['id']}
        ");

        return false;
    }

    return true;
}

function checkRecipientRisk($conn, $recipient) {

    if (isRecipientBlocked($conn, $recipient)) {
        return "⚠️ Recipient temporarily restricted.";
    }

    $today = date('Y-m-d');

    $totalToday = $conn->query("
        SELECT COUNT(*) total
        FROM transactions
        WHERE receiver_msisdn='$recipient'
        AND DATE(created_at)='$today'
        AND status IN ('QUEUED','SUCCESS')
    ")->fetch_assoc()['total'];

    $uniqueSenders = $conn->query("
        SELECT COUNT(DISTINCT sender_msisdn) total
        FROM transactions
        WHERE receiver_msisdn='$recipient'
        AND DATE(created_at)='$today'
        AND status IN ('QUEUED','SUCCESS')
    ")->fetch_assoc()['total'];

    $score = 0;

    if ($totalToday > 5) $score += 20;
    if ($totalToday > 10) $score += 40;
    if ($uniqueSenders > 3) $score += 30;
    if ($uniqueSenders > 5) $score += 60;

    if ($score >= 70) {

        flagHighRiskRecipient(
            $conn,
            $recipient,
            "Risk Score: $score",
            $score,
            180
        );

        return "⚠️ Recipient restricted (Risk Score: $score).";
    }

    return true;
}

function checkSenderRisk($conn, $msisdn) {

    $today = date('Y-m-d');

    $totalSent = $conn->query("
        SELECT COUNT(*) total
        FROM transactions
        WHERE sender_msisdn='$msisdn'
        AND DATE(created_at)='$today'
    ")->fetch_assoc()['total'];

    if ($totalSent > 15) {

        autoBlock($conn, $msisdn, "High transaction velocity");

        return "⚠️ Account temporarily restricted due to unusual activity.";
    }

    return true;
}

// ----------------------------------------------------------
// LOAD OR CREATE SESSION
// ----------------------------------------------------------
$sess = $conn->query("SELECT * FROM ussd_sessions WHERE session_id='$sessionID'");
if ($sess->num_rows == 0) {
    $conn->query("
        INSERT INTO ussd_sessions (session_id, msisdn, current_step, data, created_at)
        VALUES ('$sessionID','$msisdn',1,'{}',NOW())
    ");
    $step = 1;
    $sessionData = [];
} else {
    $row = $sess->fetch_assoc();
    $step = (int)$row['current_step'];
    $sessionData = json_decode($row['data'], true) ?? [];
}



// Check if user exists
$userExists = $conn->query("SELECT * FROM users WHERE msisdn='$msisdn' LIMIT 1");

if ($userExists->num_rows == 0) {

    // Step 1: user makes a choice
    if ($userData == "1" || $userData == "2") {

        $type = $userData == "1" ? "SME" : "INDIVIDUAL";

        // Insert into users table
        $insert = $conn->query("INSERT INTO users (msisdn, user_type) VALUES ('$msisdn','$type')");

        if ($insert) {
            // Proceed to main menu
            saveSession($conn, $sessionID, 2, []);
            respond($sessionID, $msisdn,
                "Thank you! You are registered as $type.\n\nMain Menu:\n1. Send Money\n2. FX Rates\n3. Help",
                true
            );
            exit();
        } else {
            respond($sessionID, $msisdn,
                "Oops! Something went wrong. Please try again.",
                true
            );
            exit();
        }
    }

    // Step 0: show the menu if userData is empty
    if ($userData == "" || $step == 1) {
        saveSession($conn, $sessionID, 1, []);
        respond($sessionID, $msisdn,
            "Welcome to Mobex ADR!\nAre you a Business/SME or Individual?\n1. Business/SME\n2. Individual",
            true
        );
        // exit();
    }
}


// ==========================================================
// STEP 1: MAIN MENU
// ==========================================================
if ($step == 1 && ($newSession || $userData === "")) {
    saveSession($conn, $sessionID, 2, []);
    respond(
        $sessionID,
        $msisdn,
        "Accra Digital Reset (Sandbox)\n1. Send Money\n2. FX Rates\n3. Help",
        true
    );
}

// ==========================================================
// STEP 2: MENU SELECTION
// ==========================================================
elseif ($step == 2) {

    if ($userData == "1") {
        $res = $conn->query("
            SELECT country_code, country_name
            FROM countries
            WHERE status='SANDBOX' AND country_code!='GH'
            ORDER BY country_name
        ");

        if ($res->num_rows == 0)
            respond($sessionID,$msisdn,"No destination countries available.",false);

        $msg = "Select Destination Country:\n";
        $map = [];
        $i = 1;

        while ($r = $res->fetch_assoc()) {
            $msg .= "$i. {$r['country_name']}\n";
            $map[$i] = $r['country_code'];
            $i++;
        }

        $sessionData['countries'] = $map;
        saveSession($conn, $sessionID, 10, $sessionData);
        respond($sessionID, $msisdn, trim($msg), true);
    }


    // -----------------------------
// FX RATES WITH SMART PAGINATION
// -----------------------------
if ($userData == "2") {

    // Determine current page
    $page     = $sessionData['fx_page'] ?? 1;
    $perPage  = 2;                 // items per page
    $offset   = ($page - 1) * $perPage;

    // Total FX records
    $totalRes = $conn->query("SELECT COUNT(*) AS total FROM fx_rates");
    $totalRow = $totalRes->fetch_assoc();
    $total    = (int)$totalRow['total'];

    // Fetch page data
    $fx = $conn->query("SELECT * FROM fx_rates LIMIT $perPage OFFSET $offset");

    if (!$fx || $fx->num_rows == 0) {
        respond($sessionID, $msisdn, "No more FX rates.\n0. Back", false);
        return;
    }

    // Start building message
    $startNum = $offset + 1;
    $endNum   = min($offset + $perPage, $total);
    $msg      = "FX Rates (Sandbox)\n";

    $count = $startNum;
    while ($r = $fx->fetch_assoc()) {
        $msg .= "{$count}. {$r['from_currency']} → {$r['to_currency']}: {$r['rate']}\n";
        $count++;
    }

    // Add current page info
    $msg .= "{$startNum}–{$endNum} of {$total}\n\n";

    // Menu options
    $msg .= "0. Back";

    // Show NEXT if more data exists
    if ($endNum < $total) {
        $msg .= " | # Next";
        $sessionData['fx_page'] = $page + 1; // increment page
    }

    // Make sure $step is defined before saving
    $step = $step ?? 'MAIN_MENU';
    saveSession($conn, $sessionID, $step, $sessionData);

    // Send response
    respond($sessionID, $msisdn, trim($msg), true);
}



    if ($userData == "3") {
        respond($sessionID, $msisdn, "Mobex ADR enables cross-border mobile money transfers in sandbox mode.\nDial again to restart.", false);
    }

    respond($sessionID, $msisdn, "Invalid option.", true);
}

// ==========================================================
// STEP 10: COUNTRY SELECTED
// ==========================================================
elseif ($step == 10 && isset($sessionData['countries'][$userData])) {

    $toCountry = $sessionData['countries'][$userData];

    // Fetch dial code + prefix rule
    $rule = $conn->query("
        SELECT prefix
        FROM country_phone_rules
        WHERE country_code='$toCountry'
        AND active=1
        LIMIT 1
    ")->fetch_assoc();

    if (!$rule) {
        respond($sessionID, $msisdn, "Phone rule not configured for this country.", false);
    }

    $sessionData['to_country'] = $toCountry;
    $sessionData['dial_prefix'] = $rule['prefix']; // e.g. 234

    saveSession($conn, $sessionID, 11, $sessionData);

    respond(
        $sessionID,
        $msisdn,
        "Enter recipient mobile number (without country code):",
        true
    );
}

// ==========================================================
// STEP 11: ENTER RECIPIENT (DB-VALIDATED)
// ==========================================================
elseif ($step == 11 && $userData != "") {

    $toCountry  = $sessionData['to_country'] ?? '';
    $dialPrefix = $sessionData['dial_prefix'] ?? '';

    // Clean input
    $phone = preg_replace('/\D/', '', $userData);
    $phone = ltrim($phone, '0');

    $fullNumber = $dialPrefix . $phone;

    $validPhone = validateInternationalPhone($conn, $fullNumber, $toCountry);

    if (!$validPhone) {
        respond(
            $sessionID,
            $msisdn,
            "❌ Invalid number.\nPlease re-enter.",
            true
        );
    }

    $sessionData['recipient'] = $validPhone;

    // Move to confirmation step
    saveSession($conn, $sessionID, 12, $sessionData);

   $masked = maskNumber($validPhone);

respond(
    $sessionID,
    $msisdn,
    "Confirm Recipient:\n$masked\n\n1. Confirm\n2. Re-enter",
    true
);
}


//
elseif ($step == 12) {

   if ($userData == "1") {

    $riskCheck = checkRecipientRisk($conn, $sessionData['recipient']);

    if ($riskCheck !== true) {
        respond($sessionID, $msisdn, $riskCheck, false);
    }

    saveSession($conn, $sessionID, 13, $sessionData);

    respond(
        $sessionID,
        $msisdn,
        "Enter amount to send (GHS):",
        true
    );
}

    if ($userData == "2") {

        // User wants to re-enter number
        saveSession($conn, $sessionID, 11, $sessionData);

        respond(
            $sessionID,
            $msisdn,
            "Re-enter recipient mobile number (without country code):",
            true
        );
    }

    respond($sessionID, $msisdn, "Invalid option.\n1. Confirm\n2. Re-enter", true);
}
//
// ==========================================================
// STEP 13: ENTER AMOUNT + LIMIT CHECK
// ==========================================================
elseif ($step == 13 && is_numeric($userData)) {

    $amount = (float)$userData;
    if ($amount <= 0) respond($sessionID, $msisdn, "Invalid amount.", false);

    $limitCheck = checkLimits($conn, $msisdn, $amount);
    if ($limitCheck !== true) {
        respond($sessionID, $msisdn, "⚠️ $limitCheck", true);
    }

    $toCountry = $sessionData['to_country'];

    $currencyRow = $conn->query("
        SELECT currency_code FROM countries
        WHERE country_code='$toCountry' LIMIT 1
    ")->fetch_assoc();

    $fxRow = $conn->query("
        SELECT rate FROM fx_rates
        WHERE from_currency='GHS'
        AND to_currency='{$currencyRow['currency_code']}'
        LIMIT 1
    ")->fetch_assoc();

    $receive = round($amount * $fxRow['rate'], 2);

    $sessionData += [
        'amount' => $amount,
        'rate' => $fxRow['rate'],
        'receive' => $receive,
        'fee' => 2.00,
        'to_currency' => $currencyRow['currency_code']
    ];

    saveSession($conn, $sessionID, 14, $sessionData);

    respond(
        $sessionID,
        $msisdn,
        "Send GHS $amount\nRecipient gets {$currencyRow['currency_code']} $receive\nFee: GHS 2.00\n\n1. Confirm\n2. Cancel\n0. Back",
        true
    );
}

// ==========================================================
// STEP 14: CONFIRM
// ==========================================================
// ==========================================================
// STEP 14: CONFIRM
// ==========================================================
elseif ($step == 14) {

    if ($userData == "1") {

        $ref = "ADR-" . time();
        
        $senderRisk = checkSenderRisk($conn, $msisdn);

if ($senderRisk !== true) {
    respond($sessionID, $msisdn, $senderRisk, false);
}

        // Save transaction
        $conn->query("
            INSERT INTO transactions
            (reference, sender_msisdn, receiver_msisdn, from_country, to_country,
             send_amount, receive_amount, fx_rate, fee, status, sandbox_flag, created_at)
            VALUES
            ('$ref',
             '$msisdn',
             '{$sessionData['recipient']}',
             'GH',
             '{$sessionData['to_country']}',
             {$sessionData['amount']},
             {$sessionData['receive']},
             {$sessionData['rate']},
             {$sessionData['fee']},
             'QUEUED',
             1,
             NOW()
            )
        ");

        logAudit($conn, $ref, "Transaction Queued", $sessionData);

        // --------------------------------------------------
        // SEND SMS NOTIFICATIONS (NON-BLOCKING)
        // --------------------------------------------------

        // Sender SMS
        $senderMsg =
            "MADR\n".
            "GHS {$sessionData['amount']} sent to {$sessionData['recipient']}.\n".
            "Ref: $ref";

        send_sms($msisdn, $senderMsg);

        // Recipient SMS
        $recipientMsg =
            "MADR\n".
            "You will receive {$sessionData['to_currency']} {$sessionData['receive']} ".
            "from $msisdn.\n".
            "Ref: $ref";

        send_sms($sessionData['recipient'], $recipientMsg);

        // USSD response
        respond(
            $sessionID,
            $msisdn,
            "Transaction queued successfully.\nRef: $ref\n\nSMS sent to you and the recipient.",
            false
        );
    }

    respond($sessionID, $msisdn, "Transaction cancelled.", false);
}


// ==========================================================
// FALLBACK
// ==========================================================
respond($sessionID, $msisdn, "Session ended.", false);
