<?php
//Developer: core tech web designTechnology
//Whatsapp: +2349162671360
//Telegram: @jeditech
// user/ajax/vcard-handler.php

if (session_status() === PHP_SESSION_NONE) session_start();
header('Content-Type: application/json');

// ── Bootstrap ─────────────────────────────────────────────────
$config_path = dirname(__DIR__, 2) . '/include/config.php';
if (!file_exists($config_path)) { echo json_encode(array('status'=>'0','msg'=>'Configuration error')); exit; }
include($config_path);

$strowallet_path = dirname(__DIR__, 2) . '/include/StroWallet.php';
if (!file_exists($strowallet_path)) { echo json_encode(array('status'=>'0','msg'=>'StroWallet class not found')); exit; }
require_once $strowallet_path;

// ── Auth ──────────────────────────────────────────────────────
if (!isset($_SESSION['user_id'])) { echo json_encode(array('status'=>'0','msg'=>'Unauthorized')); exit; }
if ($_SERVER['REQUEST_METHOD'] !== 'POST') { echo json_encode(array('status'=>'0','msg'=>'Invalid method')); exit; }

$user_id = (int)$_SESSION['user_id'];
$action  = isset($_POST['action']) ? trim($_POST['action']) : '';

// ── Settings ──────────────────────────────────────────────────
try {
    $cfg = $pdo->query("SELECT * FROM settings WHERE id = 1 LIMIT 1")->fetch(PDO::FETCH_ASSOC);
} catch (PDOException $e) { echo json_encode(array('status'=>'0','msg'=>'Settings error')); exit; }

if (empty($cfg['strowallet_enabled'])) {
    echo json_encode(array('status'=>'0','msg'=>'Virtual card service is currently disabled.')); exit;
}

// ── Init API ──────────────────────────────────────────────────
$sandbox_val  = isset($cfg['strowallet_sandbox']) ? $cfg['strowallet_sandbox'] : 1;
$is_sandbox   = ($sandbox_val == 1 || $sandbox_val === '1' || $sandbox_val === true);
$pub_key      = isset($cfg['strowallet_public_key']) ? $cfg['strowallet_public_key'] : '';
$api          = new StroWallet($pub_key, $is_sandbox);

// ── Rate / fee settings ───────────────────────────────────────
$fund_rate    = (float)(isset($cfg['vcard_fund_rate'])     ? $cfg['vcard_fund_rate']     : 1600);
$wd_rate      = (float)(isset($cfg['vcard_withdraw_rate']) ? $cfg['vcard_withdraw_rate'] : 1550);
$creation_fee = (float)(isset($cfg['vcard_creation_fee'])  ? $cfg['vcard_creation_fee']  : 0);
$min_fund     = (float)(isset($cfg['vcard_min_fund'])      ? $cfg['vcard_min_fund']      : 5);
$min_balance  = (float)(isset($cfg['vcard_min_balance'])   ? $cfg['vcard_min_balance']   : 1);
$max_cards    = (int)(isset($cfg['vcard_max_per_user'])    ? $cfg['vcard_max_per_user']  : 3);
if ($min_fund < 5) $min_fund = 5;

// ── Helpers ───────────────────────────────────────────────────
function vcGetUser($pdo, $uid)
{
    $s = $pdo->prepare("SELECT * FROM users WHERE id = :id LIMIT 1");
    $s->execute(array('id' => $uid));
    $r = $s->fetch(PDO::FETCH_ASSOC);
    return $r ? $r : null;
}

function vcLogTxn($pdo, $uid, $cid, $type, $usd, $ngn, $rate, $desc, $ref)
{
    try {
        $pdo->prepare("INSERT INTO virtual_card_transactions
            (user_id,card_id,type,amount_usd,amount_ngn,rate_used,description,reference,status)
            VALUES(:uid,:cid,:type,:usd,:ngn,:rate,:desc,:ref,'completed')")
            ->execute(array('uid'=>$uid,'cid'=>$cid,'type'=>$type,'usd'=>$usd,'ngn'=>$ngn,'rate'=>$rate,'desc'=>$desc,'ref'=>$ref));
    } catch (PDOException $e) {
        error_log('[vcard-handler] logTxn error: ' . $e->getMessage());
    }
}

// ════════════════════════════════════════════════════════════════
// ACTION: create_card
// NFC endpoint: POST create-nfc-card/
// Required: name, first_name, last_name, dob (mm/dd/yyyy), id_type,
//           id_number, email, line1, city, state, postal_code,
//           country (3-letter), amount_usd, phone
// ════════════════════════════════════════════════════════════════
if ($action === 'create_card') {

    // ── Read inputs ───────────────────────────────────────────
    $name        = htmlspecialchars(trim(isset($_POST['name'])        ? $_POST['name']        : ''), ENT_QUOTES);
    $first_name  = htmlspecialchars(trim(isset($_POST['first_name'])  ? $_POST['first_name']  : ''), ENT_QUOTES);
    $last_name   = htmlspecialchars(trim(isset($_POST['last_name'])   ? $_POST['last_name']   : ''), ENT_QUOTES);
    $dob         = trim(isset($_POST['dob'])         ? $_POST['dob']         : ''); // mm/dd/yyyy
    $id_type     = trim(isset($_POST['id_type'])     ? $_POST['id_type']     : '');
    $id_number   = trim(isset($_POST['id_number'])   ? $_POST['id_number']   : '');
    $line1       = htmlspecialchars(trim(isset($_POST['line1'])       ? $_POST['line1']       : ''), ENT_QUOTES);
    $city        = htmlspecialchars(trim(isset($_POST['city'])        ? $_POST['city']        : ''), ENT_QUOTES);
    $state       = htmlspecialchars(trim(isset($_POST['state'])       ? $_POST['state']       : ''), ENT_QUOTES);
    $postal_code = trim(isset($_POST['postal_code']) ? $_POST['postal_code'] : '');
    $country     = strtoupper(trim(isset($_POST['country'])  ? $_POST['country']  : ''));
    $phone       = trim(isset($_POST['phone'])       ? $_POST['phone']       : '');
    $amount      = (float)(isset($_POST['amount'])   ? $_POST['amount']      : 0);

    // ── Validate ──────────────────────────────────────────────
    $errors = array();
    if (strlen($name)       < 2) $errors[] = 'Card name is required.';
    if (strlen($first_name) < 1) $errors[] = 'First name is required.';
    if (strlen($last_name)  < 1) $errors[] = 'Last name is required.';
    if (!$dob)                   $errors[] = 'Date of birth is required.';
    if (!$id_type || !in_array($id_type, array('national_id','passport','drivers_license')))
                                 $errors[] = 'Select a valid ID type.';
    if (!$id_number)             $errors[] = 'ID number is required.';
    if (!$line1)                 $errors[] = 'Address line 1 is required.';
    if (!$city)                  $errors[] = 'City is required.';
    if (!$state)                 $errors[] = 'State is required.';
    if (!$postal_code)           $errors[] = 'Postal code is required.';
    if (!$country || strlen($country) !== 3) $errors[] = 'Select your country.';
    if (!$phone)                 $errors[] = 'Phone number is required.';
    if ($amount < $min_fund)     $errors[] = 'Minimum funding amount is $' . number_format($min_fund, 2) . '.';

    if (!empty($errors)) {
        echo json_encode(array('status'=>'0','msg'=>implode(' ', $errors))); exit;
    }

    // ── Card limit ────────────────────────────────────────────
    try {
        $cnt = $pdo->prepare("SELECT COUNT(*) FROM virtual_cards WHERE user_id = :uid AND status != 'terminated'");
        $cnt->execute(array('uid' => $user_id));
        if ((int)$cnt->fetchColumn() >= $max_cards) {
            echo json_encode(array('status'=>'0','msg'=>"You can have at most {$max_cards} virtual cards.")); exit;
        }
    } catch (PDOException $e) { /* allow through */ }

    // ── Load user ─────────────────────────────────────────────
    $full_user = vcGetUser($pdo, $user_id);
    if (!$full_user) { echo json_encode(array('status'=>'0','msg'=>'User not found.')); exit; }

    // ── Total NGN cost ────────────────────────────────────────
    $total_ngn = ($amount * $fund_rate) + $creation_fee;

    // ── Deduct wallet (atomic) ────────────────────────────────
    $pdo->beginTransaction();
    try {
        $u = $pdo->prepare("SELECT main_balance FROM users WHERE id = :id FOR UPDATE");
        $u->execute(array('id' => $user_id));
        $row = $u->fetch(PDO::FETCH_ASSOC);

        if (!$row || (float)$row['main_balance'] < $total_ngn) {
            $pdo->rollBack();
            echo json_encode(array('status'=>'0','msg'=>'Insufficient wallet balance. You need ₦'.number_format($total_ngn,2).'.')); exit;
        }
        $pdo->prepare("UPDATE users SET main_balance = main_balance - :amt WHERE id = :uid AND main_balance >= :amt")
            ->execute(array('amt' => $total_ngn, 'uid' => $user_id));
        $pdo->commit();
    } catch (PDOException $e) {
        $pdo->rollBack();
        echo json_encode(array('status'=>'0','msg'=>'DB error: '.$e->getMessage())); exit;
    }

    // ── Validate and format dob to mm/dd/yyyy if given as yyyy-mm-dd ─
    // HTML date inputs return yyyy-mm-dd, API needs mm/dd/yyyy
    $dob_api = $dob;
    if (preg_match('/^(\d{4})-(\d{2})-(\d{2})$/', $dob, $m)) {
        $dob_api = $m[2] . '/' . $m[3] . '/' . $m[1]; // mm/dd/yyyy
    }

    // ── Call NFC create-card API ──────────────────────────────
    $api_params = array(
        'name'        => $name,
        'first_name'  => $first_name,
        'last_name'   => $last_name,
        'dob'         => $dob_api,
        'id_type'     => $id_type,
        'id_number'   => $id_number,
        'email'       => $full_user['email'],
        'line1'       => $line1,
        'city'        => $city,
        'state'       => $state,
        'postal_code' => $postal_code,
        'country'     => $country,
        'amount_usd'  => (string)$amount,
        'phone'       => $phone,
    );

    try {
        $result = $api->createCard($api_params);
    } catch (Exception $e) {
        $result = array('success'=>false,'error'=>$e->getMessage(),'raw'=>null,'data'=>null);
    }

    $debug_log = $api->getDebugLog();
    error_log('[StroWallet][create_nfc_card] ' . $debug_log);

    if ($result['success'] && !empty($result['data'])) {
        $d = $result['data'];

        // Extract fields — NFC response keys
        $card_id = '';
        foreach (array('card_id','id','cardId') as $k) {
            if (!empty($d[$k])) { $card_id = $d[$k]; break; }
        }
        $pan = '';
        foreach (array('card_number','cardNumber','maskedPan','pan') as $k) {
            if (!empty($d[$k])) { $pan = $d[$k]; break; }
        }
        $expiry = '';
        foreach (array('expiry','expiration','exp_date','expiryDate') as $k) {
            if (!empty($d[$k])) { $expiry = $d[$k]; break; }
        }
        $cvv     = !empty($d['cvv']) ? $d['cvv'] : (!empty($d['cvv2']) ? $d['cvv2'] : '');
        $balance = (float)(isset($d['balance']) ? $d['balance'] : $amount);

        // ── Save to DB ────────────────────────────────────────
        try {
            $pdo->prepare("INSERT INTO virtual_cards
                (user_id, card_id, customer_id, card_pan, card_type, name_on_card,
                 expiry, cvv, billing_address, billing_city, billing_state,
                 billing_zip, billing_country, balance, status,
                 creation_fee_ngn, initial_fund_usd, api_response)
                VALUES
                (:uid, :cid, :custid, :pan, 'visa', :name,
                 :exp, :cvv, :addr, :city, :state,
                 :zip, :country, :bal, 'active',
                 :fee, :init, :resp)")
                ->execute(array(
                    'uid'     => $user_id,
                    'cid'     => $card_id,
                    'custid'  => $full_user['email'],
                    'pan'     => $pan,
                    'name'    => $name,
                    'exp'     => $expiry,
                    'cvv'     => $cvv,
                    'addr'    => $line1,
                    'city'    => $city,
                    'state'   => $state,
                    'zip'     => $postal_code,
                    'country' => $country,
                    'bal'     => $balance,
                    'fee'     => $creation_fee,
                    'init'    => $amount,
                    'resp'    => json_encode($result['raw']),
                ));

            $db_id = (int)$pdo->lastInsertId();

            vcLogTxn($pdo, $user_id, $card_id, 'fund',
                $amount, round($amount * $fund_rate, 2), $fund_rate,
                'Initial card funding', 'CARD_CREATE_' . $db_id);

            if ($creation_fee > 0) {
                vcLogTxn($pdo, $user_id, $card_id, 'fee',
                    0, $creation_fee, 0,
                    'Card creation fee', 'FEE_CREATE_' . $db_id);
            }
        } catch (PDOException $e) {
            error_log('[vcard-handler] DB insert error: ' . $e->getMessage());
        }

        echo json_encode(array('status'=>'1','msg'=>'Virtual card created successfully!','card_id'=>$card_id));

    } else {
        // Refund
        try {
            $pdo->prepare("UPDATE users SET main_balance = main_balance + :amt WHERE id = :uid")
                ->execute(array('amt'=>$total_ngn,'uid'=>$user_id));
        } catch (PDOException $e) { error_log('[vcard] refund error: '.$e->getMessage()); }

        $err = !empty($result['error']) ? $result['error'] : 'Unknown error';
        echo json_encode(array(
            'status'    => '0',
            'msg'       => 'Card creation failed: ' . $err . '. Your wallet has been refunded.',
            'debug_log' => $debug_log,
            'debug_raw' => isset($result['raw']) ? $result['raw'] : null,
        ));
    }
    exit;
}

// ════════════════════════════════════════════════════════════════
// ACTION: get_card_details
// NFC endpoint: GET fetch-nfccard-detail/
// ════════════════════════════════════════════════════════════════
if ($action === 'get_card_details') {
    $card_id = isset($_POST['card_id']) ? trim($_POST['card_id']) : '';
    if (!$card_id) { echo json_encode(array('status'=>'0','msg'=>'Invalid card.')); exit; }

    // Verify ownership
    try {
        $chk = $pdo->prepare("SELECT * FROM virtual_cards WHERE card_id = :cid AND user_id = :uid LIMIT 1");
        $chk->execute(array('cid'=>$card_id,'uid'=>$user_id));
        $local_card = $chk->fetch(PDO::FETCH_ASSOC);
        if (!$local_card) { echo json_encode(array('status'=>'0','msg'=>'Unauthorized.')); exit; }
    } catch (PDOException $e) { echo json_encode(array('status'=>'0','msg'=>'DB error.')); exit; }

    try {
        $result = $api->getCardDetails($card_id);
    } catch (Exception $e) {
        $result = array('success'=>false,'error'=>$e->getMessage(),'data'=>null,'raw'=>null);
    }

    error_log('[StroWallet][get_nfc_detail] ' . $api->getDebugLog());

    // Build a normalized card object from whatever the API returns
    $normalized = array(
        'card_id'     => $card_id,
        'card_status' => 'processing',
        'card_number' => '',
        'cvv'         => '',
        'expiry'      => '',
        'balance'     => (float)$local_card['balance'],
        'name_on_card'=> $local_card['name_on_card'],
    );

    if ($result['success'] && !empty($result['data'])) {
        $d = $result['data'];

        // NFC fetch-nfccard-detail nests details under response.card_detail:
        // { "response": { "card_detail": { card_number, cvv, expiry, ... } } }
        // parse() already extracted 'response', so $d = { "card_detail": {...} }
        // Drill one level deeper when card_detail sub-key exists
        if (isset($d['card_detail']) && is_array($d['card_detail'])) {
            $d = $d['card_detail'];
        }

        // NFC API field names — try all known variants
        $pan    = '';
        foreach (array('card_number','cardNumber','card_pan','pan','maskedPan','card_no') as $k) {
            if (!empty($d[$k])) { $pan = $d[$k]; break; }
        }
        $cvv    = '';
        foreach (array('cvv','cvv2','cvc') as $k) {
            if (!empty($d[$k])) { $cvv = $d[$k]; break; }
        }
        $expiry = '';
        foreach (array('expiry','expiration','exp','exp_date','expiryDate','valid_thru') as $k) {
            if (!empty($d[$k])) { $expiry = $d[$k]; break; }
        }
        $bal    = isset($d['balance']) ? (float)$d['balance'] : (float)$local_card['balance'];
        $status = isset($d['card_status']) ? $d['card_status'] : (isset($d['status']) ? $d['status'] : 'processing');

        // Billing address from card_detail — cover all possible field name variants
        // StroWallet returns: billing_street, billing_city, billing_state, billing_zip_code, billing_country
        $billing_street  = '';
        foreach (array('billing_street','billing_address','line1','address','street') as $k) {
            if (!empty($d[$k])) { $billing_street = $d[$k]; break; }
        }
        $billing_city    = '';
        foreach (array('billing_city','city') as $k) {
            if (!empty($d[$k])) { $billing_city = $d[$k]; break; }
        }
        $billing_state   = '';
        foreach (array('billing_state','state') as $k) {
            if (!empty($d[$k])) { $billing_state = $d[$k]; break; }
        }
        $billing_zip     = '';
        foreach (array('billing_zip_code','billing_zip','postal_code','zip_code','zip','zipCode') as $k) {
            if (!empty($d[$k])) { $billing_zip = $d[$k]; break; }
        }
        $billing_country = '';
        foreach (array('billing_country','country') as $k) {
            if (!empty($d[$k])) { $billing_country = $d[$k]; break; }
        }

        // Log raw card_detail so we can see exact field names in server log
        error_log('[StroWallet][card_detail_raw] ' . json_encode($d));

        $normalized['card_number']    = $pan;
        $normalized['cvv']            = $cvv;
        $normalized['expiry']         = $expiry;
        $normalized['balance']        = $bal;
        $normalized['card_status']    = $status;
        // Use API billing address if present, else fall back to what user entered at creation
        $normalized['billing_street'] = $billing_street  ?: (isset($local_card['billing_address']) ? $local_card['billing_address'] : '');
        $normalized['billing_city']   = $billing_city    ?: (isset($local_card['billing_city'])    ? $local_card['billing_city']    : '');
        $normalized['billing_state']  = $billing_state   ?: (isset($local_card['billing_state'])   ? $local_card['billing_state']   : '');
        $normalized['billing_zip']    = $billing_zip     ?: (isset($local_card['billing_zip'])     ? $local_card['billing_zip']     : '');
        $normalized['billing_country']= $billing_country ?: (isset($local_card['billing_country']) ? $local_card['billing_country'] : '');
        $normalized['raw_response']   = $d;

        // Persist any newly received PAN/CVV/expiry back to DB
        $update_fields = array();
        $update_params = array('cid' => $card_id, 'uid' => $user_id);

        if ($pan    && empty($local_card['card_pan']))  { $update_fields[] = 'card_pan = :pan';    $update_params['pan']    = $pan; }
        if ($cvv    && empty($local_card['cvv']))       { $update_fields[] = 'cvv = :cvv';         $update_params['cvv']    = $cvv; }
        if ($expiry && empty($local_card['expiry']))    { $update_fields[] = 'expiry = :expiry';   $update_params['expiry'] = $expiry; }
        // Always overwrite billing address with StroWallet's actual assigned address
        if ($billing_street)  { $update_fields[] = 'billing_address = :baddr'; $update_params['baddr'] = $billing_street; }
        if ($billing_city)    { $update_fields[] = 'billing_city = :bcity';    $update_params['bcity'] = $billing_city; }
        if ($billing_state)   { $update_fields[] = 'billing_state = :bstate';  $update_params['bstate']= $billing_state; }
        if ($billing_zip)     { $update_fields[] = 'billing_zip = :bzip';      $update_params['bzip']  = $billing_zip; }
        if ($billing_country) { $update_fields[] = 'billing_country = :bctry'; $update_params['bctry'] = $billing_country; }
        $update_fields[] = 'balance = :bal';
        $update_params['bal'] = $bal;
        // Update frozen status if API says active/frozen
        if (in_array(strtolower($status), array('active','frozen'))) {
            $is_frozen = (strtolower($status) === 'frozen') ? 1 : 0;
            $update_fields[] = 'status = :st';
            $update_fields[] = 'is_frozen = :frz';
            $update_params['st']  = strtolower($status);
            $update_params['frz'] = $is_frozen;
        }

        if (!empty($update_fields)) {
            try {
                $pdo->prepare("UPDATE virtual_cards SET " . implode(', ', $update_fields) . ", updated_at = NOW() WHERE card_id = :cid AND user_id = :uid")
                    ->execute($update_params);
            } catch (PDOException $e) { /* non-critical */ }
        }

    } else {
        // API call failed — return whatever we have locally
        $normalized['card_number'] = isset($local_card['card_pan']) ? $local_card['card_pan'] : '';
        $normalized['cvv']         = isset($local_card['cvv'])      ? $local_card['cvv']      : '';
        $normalized['expiry']      = isset($local_card['expiry'])   ? $local_card['expiry']   : '';
        $normalized['card_status'] = isset($local_card['status'])   ? $local_card['status']   : 'processing';
    }

    echo json_encode(array('status'=>'1','card'=>$normalized));
    exit;
}

// ════════════════════════════════════════════════════════════════
// ACTION: get_transactions
// NFC endpoint: GET nfc-card-transactions/
// ════════════════════════════════════════════════════════════════
if ($action === 'get_transactions') {
    $card_id = isset($_POST['card_id']) ? trim($_POST['card_id']) : '';
    if (!$card_id) { echo json_encode(array('status'=>'0','msg'=>'Invalid card.')); exit; }

    try {
        $chk = $pdo->prepare("SELECT card_id FROM virtual_cards WHERE card_id = :cid AND user_id = :uid LIMIT 1");
        $chk->execute(array('cid'=>$card_id,'uid'=>$user_id));
        if (!$chk->fetch()) { echo json_encode(array('status'=>'0','msg'=>'Unauthorized.')); exit; }
    } catch (PDOException $e) { echo json_encode(array('status'=>'0','msg'=>'DB error.')); exit; }

    try {
        $result = $api->getCardTransactions($card_id);
    } catch (Exception $e) {
        $result = array('success'=>false,'error'=>$e->getMessage());
    }

    error_log('[StroWallet][nfc_transactions] ' . $api->getDebugLog());

    if ($result['success'] && !empty($result['data'])) {
        $data = $result['data'];

        // NFC transactions response structure:
        // { "response": { "card_transactions": [ {...}, {...} ] } }
        // parse() extracts 'response', so $data = { "card_transactions": [...] }
        if (isset($data['card_transactions']) && is_array($data['card_transactions'])) {
            $txns = $data['card_transactions'];
        } elseif (is_array($data) && isset($data[0])) {
            $txns = $data; // already an array
        } else {
            $txns = array();
        }

        // Normalize to consistent format for JS
        $normalized_txns = array();
        foreach ($txns as $t) {
            $normalized_txns[] = array(
                'description' => isset($t['narrative'])  ? $t['narrative']  : (isset($t['method']) ? ucfirst($t['method']) : 'Transaction'),
                'amount'      => isset($t['amount'])     ? $t['amount']     : '0',
                'type'        => isset($t['type'])       ? $t['type']       : 'debit',   // 'credit' or 'debit'
                'method'      => isset($t['method'])     ? $t['method']     : '',
                'status'      => isset($t['status'])     ? $t['status']     : 'success',
                'currency'    => isset($t['currency'])   ? strtoupper($t['currency']) : 'USD',
                'reference'   => isset($t['reference'])  ? $t['reference']  : '',
                'date'        => isset($t['createdAt'])  ? date('d M Y H:i', strtotime($t['createdAt'])) : '',
            );
        }

        echo json_encode(array('status'=>'1','transactions'=>$normalized_txns));
    } else {
        // Fallback: local DB transactions
        try {
            $local = $pdo->prepare("SELECT * FROM virtual_card_transactions WHERE card_id = :cid AND user_id = :uid ORDER BY created_at DESC LIMIT 30");
            $local->execute(array('cid'=>$card_id,'uid'=>$user_id));
            $rows = $local->fetchAll(PDO::FETCH_ASSOC);
            $mapped = array();
            foreach ($rows as $r) {
                $is_credit = in_array($r['type'], array('fund','refund','reversal'));
                $mapped[] = array(
                    'description' => $r['description'],
                    'amount'      => $r['amount_usd'],
                    'type'        => $is_credit ? 'credit' : 'debit',
                    'date'        => date('d M Y H:i', strtotime($r['created_at'])),
                );
            }
            echo json_encode(array('status'=>'1','transactions'=>$mapped));
        } catch (PDOException $e) {
            echo json_encode(array('status'=>'0','msg'=>'Could not load transactions.'));
        }
    }
    exit;
}

// ════════════════════════════════════════════════════════════════
// ACTION: fund_card
// NFC endpoint: POST fund-withdraw-nfccard/ type=fund
// ════════════════════════════════════════════════════════════════
if ($action === 'fund_card') {
    $card_id = isset($_POST['card_id']) ? trim($_POST['card_id']) : '';
    $amount  = (float)(isset($_POST['amount']) ? $_POST['amount'] : 0);

    if (!$card_id) { echo json_encode(array('status'=>'0','msg'=>'Invalid card.')); exit; }
    if ($amount < $min_fund) { echo json_encode(array('status'=>'0','msg'=>'Minimum top-up is $'.number_format($min_fund,2).'.')); exit; }

    try {
        $chk = $pdo->prepare("SELECT * FROM virtual_cards WHERE card_id = :cid AND user_id = :uid AND status = 'active' LIMIT 1");
        $chk->execute(array('cid'=>$card_id,'uid'=>$user_id));
        $card = $chk->fetch(PDO::FETCH_ASSOC);
        if (!$card) { echo json_encode(array('status'=>'0','msg'=>'Card not found or inactive.')); exit; }
        if (!empty($card['is_frozen'])) { echo json_encode(array('status'=>'0','msg'=>'Card is frozen. Unfreeze it first.')); exit; }
    } catch (PDOException $e) { echo json_encode(array('status'=>'0','msg'=>'DB error.')); exit; }

    $ngn_charge = $amount * $fund_rate;

    // Deduct wallet atomically
    $pdo->beginTransaction();
    try {
        $u = $pdo->prepare("SELECT main_balance FROM users WHERE id = :id FOR UPDATE");
        $u->execute(array('id'=>$user_id));
        $row = $u->fetch(PDO::FETCH_ASSOC);
        if (!$row || (float)$row['main_balance'] < $ngn_charge) {
            $pdo->rollBack();
            echo json_encode(array('status'=>'0','msg'=>'Insufficient wallet balance.')); exit;
        }
        $pdo->prepare("UPDATE users SET main_balance = main_balance - :amt WHERE id = :uid AND main_balance >= :amt")
            ->execute(array('amt'=>$ngn_charge,'uid'=>$user_id));
        $pdo->commit();
    } catch (PDOException $e) {
        $pdo->rollBack();
        echo json_encode(array('status'=>'0','msg'=>'DB error.')); exit;
    }

    try {
        $result = $api->fundCard($card_id, $amount);
    } catch (Exception $e) {
        $result = array('success'=>false,'error'=>$e->getMessage(),'data'=>null);
    }

    error_log('[StroWallet][fund_nfc_card] ' . $api->getDebugLog());

    // Fund/Withdraw API response:
    // { "response": { "card_id":"...", "amount":3, "type":"fund",
    //                 "reference":"card_fund_WQP...", "status":"pending" } }
    // "pending" means the request was accepted — treat as success
    $api_status = '';
    if (!empty($result['data'])) {
        $api_status = isset($result['data']['status']) ? $result['data']['status'] : '';
    }
    $accepted = $result['success'] || in_array($api_status, array('pending','success','completed'));

    if ($accepted) {
        try {
            // Optimistically add to cached balance (actual balance confirmed on next detail fetch)
            $pdo->prepare("UPDATE virtual_cards SET balance = balance + :amt, updated_at = NOW() WHERE card_id = :cid AND user_id = :uid")
                ->execute(array('amt'=>$amount,'cid'=>$card_id,'uid'=>$user_id));
            $ref = !empty($result['data']['reference']) ? $result['data']['reference'] : 'FUND_'.time().'_'.$user_id;
            vcLogTxn($pdo, $user_id, $card_id, 'fund', $amount, round($ngn_charge,2), $fund_rate, 'Card top-up', $ref);
        } catch (PDOException $e) { /* non-critical */ }
        echo json_encode(array('status'=>'1','msg'=>'Card funded successfully! $'.number_format($amount,2).' is being added to your card.'));
    } else {
        // Refund wallet
        try {
            $pdo->prepare("UPDATE users SET main_balance = main_balance + :amt WHERE id = :uid")
                ->execute(array('amt'=>$ngn_charge,'uid'=>$user_id));
        } catch (PDOException $e) { /* */ }
        $err = !empty($result['error']) ? $result['error'] : 'Unknown error';
        echo json_encode(array('status'=>'0','msg'=>'Funding failed: '.$err.'. Wallet refunded.'));
    }
    exit;
}

// ════════════════════════════════════════════════════════════════
// ACTION: freeze_card
// NFC endpoint: POST nfc-cards/status/ status=frozen|active
// ════════════════════════════════════════════════════════════════
if ($action === 'freeze_card') {
    $card_id      = isset($_POST['card_id'])      ? trim($_POST['card_id'])      : '';
    $freeze_action= isset($_POST['freeze_action']) ? trim($_POST['freeze_action']) : '';

    if (!in_array($freeze_action, array('freeze','unfreeze'))) {
        echo json_encode(array('status'=>'0','msg'=>'Invalid action.')); exit;
    }

    try {
        $chk = $pdo->prepare("SELECT * FROM virtual_cards WHERE card_id = :cid AND user_id = :uid LIMIT 1");
        $chk->execute(array('cid'=>$card_id,'uid'=>$user_id));
        $card = $chk->fetch(PDO::FETCH_ASSOC);
        if (!$card) { echo json_encode(array('status'=>'0','msg'=>'Card not found.')); exit; }
    } catch (PDOException $e) { echo json_encode(array('status'=>'0','msg'=>'DB error.')); exit; }

    try {
        $result = ($freeze_action === 'freeze')
            ? $api->freezeCard($card_id)
            : $api->unfreezeCard($card_id);
    } catch (Exception $e) {
        $result = array('success'=>false,'error'=>$e->getMessage());
    }

    error_log('[StroWallet][nfc_status] ' . $api->getDebugLog());

    // Freeze API response: { "response": { "card_id":"...", "status":"frozen" } }
    // parse() extracts 'response' → $result['data'] = { "card_id":"...", "status":"frozen" }
    $confirmed_status = '';
    if (!empty($result['data']) && isset($result['data']['status'])) {
        $confirmed_status = strtolower($result['data']['status']);
    }

    // Accept if API success OR if confirmed_status matches what we sent
    $expected = ($freeze_action === 'freeze') ? 'frozen' : 'active';
    $accepted  = $result['success'] || $confirmed_status === $expected;

    if ($accepted) {
        $is_frozen = ($expected === 'frozen') ? 1 : 0;
        try {
            $pdo->prepare("UPDATE virtual_cards SET is_frozen = :f, status = :s, updated_at = NOW() WHERE card_id = :cid AND user_id = :uid")
                ->execute(array('f'=>$is_frozen,'s'=>$expected,'cid'=>$card_id,'uid'=>$user_id));
        } catch (PDOException $e) { /* */ }
        $msg = ($freeze_action === 'freeze') ? 'Card frozen successfully.' : 'Card unfrozen successfully.';
        echo json_encode(array('status'=>'1','msg'=>$msg));
    } else {
        $err = !empty($result['error']) ? $result['error'] : 'Operation failed.';
        echo json_encode(array('status'=>'0','msg'=>$err));
    }
    exit;
}

// ════════════════════════════════════════════════════════════════
// ACTION: withdraw_card
// NFC endpoint: POST fund-withdraw-nfccard/ type=withdraw
// ════════════════════════════════════════════════════════════════
if ($action === 'withdraw_card') {
    $card_id = isset($_POST['card_id']) ? trim($_POST['card_id']) : '';
    $amount  = (float)(isset($_POST['amount']) ? $_POST['amount'] : 0);

    if (!$card_id || $amount <= 0) { echo json_encode(array('status'=>'0','msg'=>'Invalid request.')); exit; }

    try {
        $chk = $pdo->prepare("SELECT * FROM virtual_cards WHERE card_id = :cid AND user_id = :uid AND status = 'active' LIMIT 1");
        $chk->execute(array('cid'=>$card_id,'uid'=>$user_id));
        $card = $chk->fetch(PDO::FETCH_ASSOC);
        if (!$card) { echo json_encode(array('status'=>'0','msg'=>'Card not found or inactive.')); exit; }
    } catch (PDOException $e) { echo json_encode(array('status'=>'0','msg'=>'DB error.')); exit; }

    if ((float)$card['balance'] - $amount < $min_balance) {
        echo json_encode(array('status'=>'0','msg'=>'Card must retain at least $'.number_format($min_balance,2).' balance after withdrawal.')); exit;
    }

    try {
        $result = $api->withdrawFromCard($card_id, $amount);
    } catch (Exception $e) {
        $result = array('success'=>false,'error'=>$e->getMessage());
    }

    error_log('[StroWallet][withdraw_nfc] ' . $api->getDebugLog());

    // Withdraw API response: { "response": { "status":"pending", ... } }
    // "pending" = accepted — credit wallet immediately (same as fund)
    $api_wd_status = '';
    if (!empty($result['data']) && isset($result['data']['status'])) {
        $api_wd_status = $result['data']['status'];
    }
    $wd_accepted = $result['success'] || in_array($api_wd_status, array('pending','success','completed'));

    if ($wd_accepted) {
        $ngn_credit = $amount * $wd_rate;
        try {
            $pdo->prepare("UPDATE users SET main_balance = main_balance + :amt WHERE id = :uid")
                ->execute(array('amt'=>$ngn_credit,'uid'=>$user_id));
            $pdo->prepare("UPDATE virtual_cards SET balance = balance - :amt, updated_at = NOW() WHERE card_id = :cid AND user_id = :uid")
                ->execute(array('amt'=>$amount,'cid'=>$card_id,'uid'=>$user_id));
            $ref = !empty($result['data']['reference']) ? $result['data']['reference'] : 'WD_'.time().'_'.$user_id;
            vcLogTxn($pdo, $user_id, $card_id, 'withdraw', $amount, round($ngn_credit,2), $wd_rate, 'Withdrawal to wallet', $ref);
        } catch (PDOException $e) { error_log('[vcard] post-withdraw DB: '.$e->getMessage()); }

        echo json_encode(array(
            'status' => '1',
            'msg'    => '$'.number_format($amount,2).' withdrawal submitted. ₦'.number_format($ngn_credit,2).' added to your wallet.',
        ));
    } else {
        $err = !empty($result['error']) ? $result['error'] : 'Unknown error.';
        echo json_encode(array('status'=>'0','msg'=>'Withdrawal failed: '.$err));
    }
    exit;
}

// ════════════════════════════════════════════════════════════════
// ACTION: card_statement — NFC has no statement endpoint yet;
// serve local DB transactions as fallback
// ════════════════════════════════════════════════════════════════
if ($action === 'card_statement') {
    $card_id = isset($_POST['card_id']) ? trim($_POST['card_id']) : '';
    $from    = isset($_POST['from'])    ? trim($_POST['from'])    : '';
    $to      = isset($_POST['to'])      ? trim($_POST['to'])      : '';

    try {
        $chk = $pdo->prepare("SELECT card_id FROM virtual_cards WHERE card_id = :cid AND user_id = :uid LIMIT 1");
        $chk->execute(array('cid'=>$card_id,'uid'=>$user_id));
        if (!$chk->fetch()) { echo json_encode(array('status'=>'0','msg'=>'Unauthorized.')); exit; }
    } catch (PDOException $e) { echo json_encode(array('status'=>'0','msg'=>'DB error.')); exit; }

    // Use nfc-card-transactions as the statement source
    try {
        $result = $api->getCardTransactions($card_id);
    } catch (Exception $e) {
        $result = array('success'=>false);
    }

    if ($result['success'] && !empty($result['data'])) {
        echo json_encode(array('status'=>'1','msg'=>'Statement ready.','data'=>$result['data'],'url'=>null));
    } else {
        // Local DB fallback
        try {
            $q = "SELECT * FROM virtual_card_transactions WHERE card_id = :cid AND user_id = :uid";
            $p = array('cid'=>$card_id,'uid'=>$user_id);
            if ($from) { $q .= " AND DATE(created_at) >= :from"; $p['from'] = $from; }
            if ($to)   { $q .= " AND DATE(created_at) <= :to";   $p['to']   = $to;   }
            $q .= " ORDER BY created_at DESC LIMIT 100";
            $stmt = $pdo->prepare($q);
            $stmt->execute($p);
            echo json_encode(array('status'=>'1','msg'=>'Statement ready.','data'=>$stmt->fetchAll(PDO::FETCH_ASSOC),'url'=>null));
        } catch (PDOException $e) {
            echo json_encode(array('status'=>'0','msg'=>'Could not get statement.'));
        }
    }
    exit;
}

// ════════════════════════════════════════════════════════════════
// ACTION: delete_card — freeze then mark terminated
// (NFC API has no delete endpoint; freeze + mark terminated locally)
// ════════════════════════════════════════════════════════════════
if ($action === 'delete_card') {
    $card_id = isset($_POST['card_id']) ? trim($_POST['card_id']) : '';
    if (!$card_id) { echo json_encode(array('status'=>'0','msg'=>'Invalid card.')); exit; }

    try {
        $chk = $pdo->prepare("SELECT * FROM virtual_cards WHERE card_id = :cid AND user_id = :uid LIMIT 1");
        $chk->execute(array('cid'=>$card_id,'uid'=>$user_id));
        $card = $chk->fetch(PDO::FETCH_ASSOC);
        if (!$card) { echo json_encode(array('status'=>'0','msg'=>'Card not found.')); exit; }
    } catch (PDOException $e) { echo json_encode(array('status'=>'0','msg'=>'DB error.')); exit; }

    // Auto-withdraw remaining balance before terminating
    $remaining = (float)$card['balance'];
    if ($remaining > $min_balance) {
        $wd_amt = round($remaining - $min_balance, 2);
        try {
            $wd_result = $api->withdrawFromCard($card_id, $wd_amt);
            if ($wd_result['success']) {
                $ngn_credit = $wd_amt * $wd_rate;
                $pdo->prepare("UPDATE users SET main_balance = main_balance + :amt WHERE id = :uid")
                    ->execute(array('amt'=>$ngn_credit,'uid'=>$user_id));
                vcLogTxn($pdo, $user_id, $card_id, 'withdraw', $wd_amt, round($ngn_credit,2), $wd_rate, 'Auto-withdrawal on card deletion', 'WD_DEL_'.time());
            }
        } catch (Exception $e) { /* proceed */ }
    }

    // Freeze the card via API
    try { $api->freezeCard($card_id); } catch (Exception $e) { /* proceed */ }

    // Mark terminated locally
    try {
        $pdo->prepare("UPDATE virtual_cards SET status = 'terminated', is_frozen = 1, updated_at = NOW() WHERE card_id = :cid AND user_id = :uid")
            ->execute(array('cid'=>$card_id,'uid'=>$user_id));
    } catch (PDOException $e) { /* */ }

    echo json_encode(array('status'=>'1','msg'=>'Card deleted successfully.'));
    exit;
}

echo json_encode(array('status'=>'0','msg'=>'Invalid action.'));
exit;