<?php
// Include database configuration
require_once './includes/config.php';

// Enable PDO error reporting
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

// Get the raw POST data
$input = file_get_contents('php://input');
error_log("Raw USSD Input: " . $input); // Log raw input for debugging

// Detect content type
$contentType = $_SERVER['CONTENT_TYPE'] ?? 'unknown';
error_log("Content-Type: " . $contentType);

// Attempt to parse JSON first
$data = json_decode($input, true);

// If JSON decoding fails, try parsing URL-encoded data
if (!$data) {
    parse_str($input, $data);
}

error_log("Parsed Data: " . print_r($data, true)); // Log parsed data

// Extract USSD session data
$sessionId = $data['sessionId'] ?? null;
$phoneNumber = $data['phoneNumber'] ?? null;
$text = $data['text'] ?? '';
$serviceCode = $data['serviceCode'] ?? null;

// Decode URL-encoded fields (if needed)
$phoneNumber = urldecode($phoneNumber);
$serviceCode = urldecode($serviceCode);

// Validate required fields
if (!$sessionId || !$phoneNumber || !$serviceCode) {
    error_log("Invalid USSD request: sessionId=$sessionId, phoneNumber=$phoneNumber, serviceCode=$serviceCode, text=$text");
    echo "END System error. Please try again later.";
    exit;
}

// Normalize the phone number to local format
$phoneNumber = normalizePhoneNumber($phoneNumber, 'local');

// Debugging logs
error_log("USSD Request: sessionId=$sessionId, phoneNumber=$phoneNumber, text=$text, serviceCode=$serviceCode");

// Get session data from database
$session = getSession($pdo, $sessionId, $phoneNumber);
$step = $session ? $session['step'] : 'main_menu';
$tempData = $session ? json_decode($session['temp_data'], true) : [];

// Handle user input
$inputArray = explode('*', $text);
$lastInput = end($inputArray);
$response = '';

switch ($step) {
    case 'main_menu':
        $response = "CON Welcome to MyBank\n1. Check Balance\n2. Transfer Funds\n3. Exit";
        saveSession($pdo, $sessionId, $phoneNumber, 'awaiting_selection');
        break;

    case 'awaiting_selection':
        if ($lastInput == '1') {
            $response = getAccountBalance($pdo, $phoneNumber);
            if (strpos($response, 'CON') === 0) {
                saveSession($pdo, $sessionId, $phoneNumber, 'viewing_balances');
            } else {
                deleteSession($pdo, $sessionId);
            }
        } elseif ($lastInput == '2') {
            // Fetch accounts for transfer with full naming
            $accounts = getAccounts($pdo, $phoneNumber);
            if (empty($accounts)) {
                $response = "END No accounts found.";
                deleteSession($pdo, $sessionId);
            } else {
                $response = "CON Select account to transfer from:\n";
                foreach ($accounts as $index => $account) {
                    $accountLabel = "{$account['account_type_name']} - {$account['sub_account_name']}";
                    $response .= ($index + 1) . ". {$accountLabel} ({$account['account_number']})\n";
                }
                $response .= "0. Back";
                saveSession($pdo, $sessionId, $phoneNumber, 'transfer_select_account', ['accounts' => $accounts]);
            }
        } elseif ($lastInput == '3') {
            $response = "END Thank you for using MyBank!";
            deleteSession($pdo, $sessionId);
        } else {
            $response = "END Invalid option. Try again.";
            deleteSession($pdo, $sessionId);
        }
        break;

    case 'transfer_select_account':
        if ($lastInput == '0') {
            $response = "CON Welcome to MyBank\n1. Check Balance\n2. Transfer Funds\n3. Exit";
            saveSession($pdo, $sessionId, $phoneNumber, 'awaiting_selection');
        } else {
            $accounts = $tempData['accounts'];
            $selectedIndex = (int)$lastInput - 1;

            if (isset($accounts[$selectedIndex])) {
                $selectedAccount = $accounts[$selectedIndex];
                $accountLabel = "{$selectedAccount['account_type_name']} - {$selectedAccount['sub_account_name']}";
                $tempData['from_account'] = $selectedAccount['account_number'];
                $tempData['from_account_label'] = $accountLabel;
                saveSession($pdo, $sessionId, $phoneNumber, 'transfer_enter_phone', $tempData);
                $response = "CON Transfer from {$accountLabel}\nEnter recipient's phone number:";
            } else {
                $response = "END Invalid option. Try again.";
                deleteSession($pdo, $sessionId);
            }
        }
        break;

    case 'transfer_enter_phone':
        $recipient = normalizePhoneNumber($lastInput, 'local');
        $tempData['recipient'] = $recipient;
        saveSession($pdo, $sessionId, $phoneNumber, 'transfer_enter_amount', $tempData);
        $response = "CON Enter amount to transfer:";
        break;

    case 'transfer_enter_amount':
        $amount = (int)$lastInput;
        if ($amount <= 0) {
            $response = "END Invalid amount. Try again.";
            deleteSession($pdo, $sessionId);
        } else {
            $fromAccount = $tempData['from_account'];
            $fromAccountLabel = $tempData['from_account_label'];
            $recipient = $tempData['recipient'];
            $success = transferFunds($pdo, $fromAccount, $recipient, $amount);
            $response = $success 
                ? "END Transfer of KES $amount from {$fromAccountLabel} ({$fromAccount}) to $recipient successful." 
                : "END Transfer failed. Please try again later.";
            deleteSession($pdo, $sessionId);
        }
        break;

    case 'viewing_balances':
        if ($lastInput == '0') {
            $response = "CON Welcome to MyBank\n1. Check Balance\n2. Transfer Funds\n3. Exit";
            saveSession($pdo, $sessionId, $phoneNumber, 'awaiting_selection');
        } else {
            $response = "END Invalid option. Try again.";
            deleteSession($pdo, $sessionId);
        }
        break;

    default:
        $response = "END Invalid input. Try again.";
        deleteSession($pdo, $sessionId);
        break;
}

// Send the response back
header('Content-type: text/plain');
echo $response;

// ====================
// HELPER FUNCTIONS
// ====================

/**
 * Normalize a phone number to a consistent format.
 */
function normalizePhoneNumber($phoneNumber, $format = 'local') {
    $phoneNumber = preg_replace('/[^0-9]/', '', $phoneNumber);

    if ($format === 'local') {
        if (substr($phoneNumber, 0, 3) === '254') {
            return '0' . substr($phoneNumber, 3);
        } elseif (substr($phoneNumber, 0, 4) === '+254') {
            return '0' . substr($phoneNumber, 4);
        }
        return $phoneNumber;
    }

    if ($format === 'international') {
        if (substr($phoneNumber, 0, 1) === '0') {
            return '254' . substr($phoneNumber, 1);
        } elseif (substr($phoneNumber, 0, 3) === '254') {
            return $phoneNumber;
        }
        return $phoneNumber;
    }

    return $phoneNumber;
}

// ====================
// DATABASE FUNCTIONS
// ====================

/**
 * Get or create USSD session.
 */
function getSession($pdo, $sessionId, $phoneNumber) {
    $stmt = $pdo->prepare("SELECT * FROM ussd_sessions WHERE session_id = ? AND phone_number = ?");
    $stmt->execute([$sessionId, $phoneNumber]);
    return $stmt->fetch();
}

/**
 * Save or update USSD session.
 */
function saveSession($pdo, $sessionId, $phoneNumber, $step, $tempData = []) {
    $tempDataJson = json_encode($tempData);
    error_log("Saving Session: sessionId=$sessionId, phoneNumber=$phoneNumber, step=$step, tempData=$tempDataJson");

    try {
        $stmt = $pdo->prepare("
            INSERT INTO ussd_sessions (session_id, phone_number, step, temp_data) 
            VALUES (?, ?, ?, ?) 
            ON DUPLICATE KEY UPDATE step = VALUES(step), temp_data = VALUES(temp_data)
        ");
        $stmt->execute([$sessionId, $phoneNumber, $step, $tempDataJson]);

        error_log("Session saved/updated successfully.");
    } catch (PDOException $e) {
        error_log("Database Error: " . $e->getMessage());
    }
}

/**
 * Delete USSD session.
 */
function deleteSession($pdo, $sessionId) {
    $stmt = $pdo->prepare("DELETE FROM ussd_sessions WHERE session_id = ?");
    $stmt->execute([$sessionId]);
    error_log("Session deleted: sessionId=$sessionId");
}

/**
 * Get all accounts for a phone number with complete naming
 */
function getAccounts($pdo, $phoneNumber) {
    $phoneNumber = normalizePhoneNumber($phoneNumber, 'local');
    error_log("Fetching accounts for phoneNumber: $phoneNumber");

    try {
        $stmt = $pdo->prepare("
            SELECT 
                ma.account_number,
                ma.sub_account_code,
                ma.sub_account_name,
                at.account_name AS account_type_name,
                ma.available_balance
            FROM member_accounts ma
            JOIN account_types at ON ma.account_type_id = at.id
            JOIN members m ON ma.member_id = m.id
            WHERE m.phone_number = ?
            ORDER BY at.account_name, ma.sub_account_code
        ");
        $stmt->execute([$phoneNumber]);
        return $stmt->fetchAll(PDO::FETCH_ASSOC);
    } catch (PDOException $e) {
        error_log("Database Error in getAccounts: " . $e->getMessage());
        return [];
    }
}

/**
 * Get individual account balances with full naming
 */
function getAccountBalance($pdo, $phoneNumber) {
    $phoneNumber = normalizePhoneNumber($phoneNumber, 'local');
    error_log("Fetching balances for phoneNumber: $phoneNumber");

    try {
        $stmt = $pdo->prepare("
            SELECT 
                ma.account_number,
                at.account_name AS account_type_name,
                ma.sub_account_name,
                ma.available_balance
            FROM member_accounts ma
            JOIN account_types at ON ma.account_type_id = at.id
            JOIN members m ON ma.member_id = m.id
            WHERE m.phone_number = ?
            ORDER BY at.account_name, ma.sub_account_code
        ");
        $stmt->execute([$phoneNumber]);
        $accounts = $stmt->fetchAll(PDO::FETCH_ASSOC);

        if (empty($accounts)) {
            error_log("No accounts found for phoneNumber: $phoneNumber");
            return "END No accounts found.";
        }

        $response = "CON Your account balances:\n";
        foreach ($accounts as $account) {
            $response .= "{$account['account_type_name']} - {$account['sub_account_name']} ({$account['account_number']}): KES {$account['available_balance']}\n";
        }
        $response .= "0. Back";

        error_log("Balances found: " . print_r($accounts, true));
        return $response;
    } catch (PDOException $e) {
        error_log("Database Error in getAccountBalance: " . $e->getMessage());
        return "END System error. Please try again later.";
    }
}

/**
 * Transfer funds between accounts.
 */
function transferFunds($pdo, $fromAccount, $toPhoneNumber, $amount) {
    try {
        $pdo->beginTransaction();
        $toPhoneNumber = normalizePhoneNumber($toPhoneNumber, 'local');

        // Fetch from account details with balance check
        $stmt = $pdo->prepare("
            SELECT ma.id, ma.available_balance, at.account_name, ma.sub_account_name 
            FROM member_accounts ma
            JOIN account_types at ON ma.account_type_id = at.id
            WHERE ma.account_number = ?
            FOR UPDATE
        ");
        $stmt->execute([$fromAccount]);
        $fromAccountDetails = $stmt->fetch();

        if (!$fromAccountDetails || $fromAccountDetails['available_balance'] < $amount) {
            $pdo->rollBack();
            error_log("Insufficient funds or invalid account: {$fromAccount}");
            return false;
        }

        // Fetch to account details
        $stmt = $pdo->prepare("
            SELECT ma.id 
            FROM member_accounts ma
            JOIN members m ON ma.member_id = m.id
            WHERE m.phone_number = ?
            AND ma.sub_account_code = 1  // Assuming we only transfer to principal accounts
            FOR UPDATE
        ");
        $stmt->execute([$toPhoneNumber]);
        $toAccountDetails = $stmt->fetch();

        if (!$toAccountDetails) {
            $pdo->rollBack();
            error_log("Recipient account not found for phone: {$toPhoneNumber}");
            return false;
        }

        // Deduct from sender's account
        $stmt = $pdo->prepare("
            UPDATE member_accounts 
            SET available_balance = available_balance - ? 
            WHERE id = ?
        ");
        $stmt->execute([$amount, $fromAccountDetails['id']]);

        // Add to recipient's account
        $stmt = $pdo->prepare("
            UPDATE member_accounts 
            SET available_balance = available_balance + ? 
            WHERE id = ?
        ");
        $stmt->execute([$amount, $toAccountDetails['id']]);

        // Record transaction
        $stmt = $pdo->prepare("
            INSERT INTO transactions (
                from_account, to_account, amount, 
                transaction_type, status, description
            ) VALUES (?, ?, ?, 'transfer', 'completed', ?)
        ");
        $description = "Transfer from {$fromAccountDetails['account_name']} - {$fromAccountDetails['sub_account_name']}";
        $stmt->execute([
            $fromAccount, 
            $toAccountDetails['id'], 
            $amount,
            $description
        ]);

        $pdo->commit();
        return true;
    } catch (Exception $e) {
        $pdo->rollBack();
        error_log("Transfer Error: " . $e->getMessage());
        return false;
    }
}