<?php
declare(strict_types=1);
session_start();
ini_set('display_errors', '1');
error_reporting(E_ALL);

require_once __DIR__ . '/../includes/db.php';
require_once __DIR__ . '/../includes/auth.php';
require_once __DIR__ . '/../includes/helpers.php';
require_once __DIR__ . '/../includes/config.php';

if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
    header('Location: dashboard.php');
    exit;
}

// CSRF check
if (empty($_POST['csrf']) || !hash_equals($_SESSION['csrf'] ?? '', $_POST['csrf'])) {
    http_response_code(400);
    exit('Invalid request token');
}

// ✅ Get logged-in user ID early
$from_uid = (int)($_SESSION['uid'] ?? 0);
if ($from_uid <= 0) {
    http_response_code(403);
    exit('Invalid session — please log in again.');
}

// --- Verify Transaction PIN ---
$txPin = trim($_POST['transaction_pin'] ?? '');
if ($txPin === '') {
    http_response_code(400);
    exit('Transaction PIN is required');
}

// Fetch user PIN info
$stmt = $pdo->prepare("SELECT transaction_pin_hash, pin_attempts, is_locked FROM users WHERE id = ?");
$stmt->execute([$from_uid]);
$user = $stmt->fetch(PDO::FETCH_ASSOC);

if (!$user) {
    http_response_code(403);
    exit('User not found');
}

if ((int)$user['is_locked'] === 1) {
    http_response_code(403);
    exit('Your account is locked due to too many wrong PIN attempts. Contact support.');
}

if (!password_verify($txPin, $user['transaction_pin_hash'])) {
    $newAttempts = ((int)$user['pin_attempts']) + 1;
    $lock = ($newAttempts >= 3) ? 1 : 0;

    $pdo->prepare("UPDATE users SET pin_attempts = ?, is_locked = ? WHERE id = ?")
        ->execute([$newAttempts, $lock, $from_uid]);

    http_response_code(403);
    exit($lock
        ? 'Too many wrong PIN attempts — your account has been locked.'
        : 'Invalid transaction PIN.');
}

// PIN correct — reset attempts
$pdo->prepare("UPDATE users SET pin_attempts = 0 WHERE id = ?")->execute([$from_uid]);

// --- Continue transaction ---
$to_acct  = trim($_POST['to_account'] ?? '');
$amount_s = trim($_POST['amount'] ?? '');
$note     = mb_substr(trim($_POST['note'] ?? ''), 0, 255);

if (!preg_match('/^\d{10}$/', $to_acct)) {
    http_response_code(400);
    exit('Invalid recipient account number');
}

// Normalize amount like "1,000.50" → kobo
$amount_num   = preg_replace('/[^\d.]/', '', $amount_s);
$amount_cents = (int) round((float)$amount_num * 100);
if ($amount_cents <= 0) {
    http_response_code(400);
    exit('Invalid amount');
}

try {
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    $pdo->beginTransaction();

    // Lock sender
    $stmt = $pdo->prepare("SELECT id, account_number, balance_cents FROM users WHERE id = ? FOR UPDATE");
    $stmt->execute([$from_uid]);
    $sender = $stmt->fetch(PDO::FETCH_ASSOC);
    if (!$sender) throw new RuntimeException('Sender not found');

    // Lock recipient
    $stmt = $pdo->prepare("SELECT id, account_number, balance_cents FROM users WHERE account_number = ? FOR UPDATE");
    $stmt->execute([$to_acct]);
    $rec = $stmt->fetch(PDO::FETCH_ASSOC);
    if (!$rec) throw new RuntimeException('Recipient not found');

    if ((int)$rec['id'] === (int)$sender['id']) {
        throw new RuntimeException('Cannot transfer to your own account');
    }

    if ($sender['balance_cents'] < $amount_cents) {
        throw new RuntimeException('Insufficient funds');
    }

    // Instead of updating both balances immediately, only deduct sender for now
$sender_after = $sender['balance_cents'] - $amount_cents;

// Generate unique reference and validation code
$baseRef   = strtoupper(bin2hex(random_bytes(8)));
$refDebit  = $baseRef . '-D';
$refCredit = $baseRef . '-C';
$validationCode = random_int(100000, 999999); // 6-digit code
$expiryTime = date('Y-m-d H:i:s', strtotime('+24 hours')); // expires in 24 hrs

// Deduct sender balance (lock funds)
$pdo->prepare("UPDATE users SET balance_cents = ? WHERE id = ?")
    ->execute([$sender_after, $sender['id']]);

// Record sender DEBIT transaction
$pdo->prepare("
    INSERT INTO transactions
    (user_id, sender_id, kind, amount_cents, balance_before_cents, balance_after_cents, reference, validation_code, validation_status, expiry_time, note, created_at)
    VALUES (?, ?, 'debit', ?, ?, ?, ?, ?, 'pending', ?, ?, NOW())
")->execute([
    $sender['id'],
    $sender['id'],
    $amount_cents,
    $sender['balance_cents'],
    $sender_after,
    $refDebit,
    $validationCode,
    $expiryTime,
    $note !== '' ? $note : ('Transfer to ' . $rec['account_number']),
]);

// Record receiver CREDIT as pending (not yet credited to balance)
$pdo->prepare("
    INSERT INTO transactions
    (user_id, sender_id, kind, amount_cents, balance_before_cents, balance_after_cents, reference, validation_code, validation_status, expiry_time, note, created_at)
    VALUES (?, ?, 'credit', ?, ?, ?, ?, ?, 'pending', ?, ?, NOW())
")->execute([
    $rec['id'],
    $sender['id'],
    $amount_cents,
    $rec['balance_cents'], // unchanged until validation
    $rec['balance_cents'], // same as before
    $refCredit,
    $validationCode,
    $expiryTime,
    $note !== '' ? $note : ('Transfer from ' . $sender['account_number']),
]);

// Option 1: Display validation code on screen (manual exchange)
$_SESSION['flash_success'] = 'Transfer created successfully. Give this code to the receiver to validate: ' . $validationCode;

// Option 2 (optional later): Email code to sender using PHPMailer

$pdo->commit();

header('Location: /public/dashboard.php');
exit;


} catch (Throwable $e) {
    if ($pdo->inTransaction()) $pdo->rollBack();
    http_response_code(500);
    echo 'Transfer failed: ' . htmlspecialchars($e->getMessage());
    exit;
}
