<?php
require_once __DIR__ . '/config.php';
require_once __DIR__ . '/routeros_api.class.php';

function h(string $v): string { return htmlspecialchars($v, ENT_QUOTES, 'UTF-8'); }

function new_invoice(): string {
    return 'HS' . date('ymdHis') . random_int(1000, 9999);
}

function clean_value($v, int $max = 200): string {
    $v = trim((string)$v);
    $v = str_replace(["\r", "\n", "\0"], '', $v);
    if (function_exists('mb_substr')) return mb_substr($v, 0, $max);
    return substr($v, 0, $max);
}

function generate_token(?string $mac, string $invoice): string {
    $digits = preg_replace('/\D+/', '', (string)$mac);
    if (strlen($digits) >= 6) return substr($digits, -6);
    return substr(preg_replace('/\D+/', '', $invoice), -8);
}

function db_insert_txn(array $txn): void {
    $sql = "INSERT INTO hotspot_payment_transactions
    (invoice, username, package_key, package_label, amount, profile, days, mac, ip, login_url, dst, status, created_at)
    VALUES (?,?,?,?,?,?,?,?,?,?,?,'created',NOW())
    ON DUPLICATE KEY UPDATE
      username=VALUES(username), package_key=VALUES(package_key), package_label=VALUES(package_label),
      amount=VALUES(amount), profile=VALUES(profile), days=VALUES(days), mac=VALUES(mac), ip=VALUES(ip),
      login_url=VALUES(login_url), dst=VALUES(dst), status='created', error_message=NULL";
    $stmt = db()->prepare($sql);
    $username = $txn['username'] ?? 'hotspot';
    $packageLabel = $txn['package_label'] ?? $txn['package_key'];

    // FIX: numeric profile -> label profile
    $map = [
        '1'  => '1-Day',
        '3'  => '3-Day',
        '7'  => '7-Day',
        '15' => '15-Day',
        '30' => '30-Day'
    ];

    if (isset($txn['profile']) && isset($map[$txn['profile']])) {
        $txn['profile'] = $map[$txn['profile']];
    }

    $stmt->bind_param(
        'ssssdisssss',
        $txn['invoice'], $username, $txn['package_key'], $packageLabel, $txn['amount'], $txn['profile'], $txn['days'],
        $txn['mac'], $txn['ip'], $txn['login_url'], $txn['dst']
    );
    $stmt->execute();
}

function db_mark_payment_created(string $invoice, string $paymentId, array $raw): void {
    $rawJson = json_encode($raw, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
    $stmt = db()->prepare("UPDATE hotspot_payment_transactions SET status='payment_created', payment_id=?, raw_response=?, error_message=NULL WHERE invoice=? LIMIT 1");
    $stmt->bind_param('sss', $paymentId, $rawJson, $invoice);
    $stmt->execute();
}

function db_get_txn(string $invoice): ?array {
    $stmt = db()->prepare("SELECT * FROM hotspot_payment_transactions WHERE invoice=? LIMIT 1");
    $stmt->bind_param('s', $invoice);
    $stmt->execute();
    $row = $stmt->get_result()->fetch_assoc();
    return $row ?: null;
}

function db_get_txn_by_payment_id(string $paymentId): ?array {
    $stmt = db()->prepare("SELECT * FROM hotspot_payment_transactions WHERE payment_id=? LIMIT 1");
    $stmt->bind_param('s', $paymentId);
    $stmt->execute();
    $row = $stmt->get_result()->fetch_assoc();
    return $row ?: null;
}

function db_trx_exists(string $trxId, string $invoice = ''): bool {
    if ($invoice !== '') {
        $stmt = db()->prepare("SELECT id FROM hotspot_payment_transactions WHERE trx_id=? AND invoice<>? LIMIT 1");
        $stmt->bind_param('ss', $trxId, $invoice);
    } else {
        $stmt = db()->prepare("SELECT id FROM hotspot_payment_transactions WHERE trx_id=? LIMIT 1");
        $stmt->bind_param('s', $trxId);
    }
    $stmt->execute();
    return (bool)$stmt->get_result()->fetch_assoc();
}

function db_mark_paid(string $invoice, string $paymentId, string $trxId, string $token, array $raw): void {
    $rawJson = json_encode($raw, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
    $stmt = db()->prepare("UPDATE hotspot_payment_transactions
        SET status='paid', payment_id=?, trx_id=?, token=?, raw_response=?, error_message=NULL, paid_at=NOW()
        WHERE invoice=? LIMIT 1");
    $stmt->bind_param('sssss', $paymentId, $trxId, $token, $rawJson, $invoice);
    $stmt->execute();
}

function db_mark_failed(string $invoice, string $message, array $raw = []): void {
    $rawJson = $raw ? json_encode($raw, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) : null;
    $stmt = db()->prepare("UPDATE hotspot_payment_transactions SET status='failed', error_message=?, raw_response=COALESCE(?, raw_response) WHERE invoice=? LIMIT 1");
    $stmt->bind_param('sss', $message, $rawJson, $invoice);
    $stmt->execute();
}

function http_json(string $url, array $headers = [], ?array $body = null): array {
    if (!function_exists('curl_init')) throw new Exception('PHP cURL extension missing');
    $ch = curl_init($url);
    $h = array_merge(['Content-Type: application/json', 'Accept: application/json'], $headers);
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_HTTPHEADER => $h,
        CURLOPT_TIMEOUT => 35,
        CURLOPT_CONNECTTIMEOUT => 15,
        CURLOPT_SSL_VERIFYPEER => true,
        CURLOPT_SSL_VERIFYHOST => 2,
    ]);
    if ($body !== null) {
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($body, JSON_UNESCAPED_SLASHES));
    }
    $raw = curl_exec($ch);
    $err = curl_error($ch);
    $code = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
    curl_close($ch);
    if ($raw === false || $raw === null) return ['_ok' => false, '_error' => $err, '_http_code' => $code];
    $data = json_decode($raw, true);
    if (!is_array($data)) return ['_ok' => false, '_error' => 'Invalid JSON', '_raw' => $raw, '_http_code' => $code];
    $data['_http_code'] = $code;
    return $data;
}

function bkash_grant_token(): string {
    $res = http_json(bkash_base_url() . '/token/grant', [
        'username: ' . BKASH_USERNAME,
        'password: ' . BKASH_PASSWORD,
    ], ['app_key' => BKASH_APP_KEY, 'app_secret' => BKASH_APP_SECRET]);
    if (empty($res['id_token'])) throw new Exception('bKash token failed: ' . json_encode($res, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
    return $res['id_token'];
}

function bkash_create_payment(string $invoice, float $amount): array {
    $token = bkash_grant_token();
    // bKash hosted page can fail with callback URL query string. Keep callback clean.
    $callback = APP_URL . '/callback.php';
    $payload = [
        'mode' => '0011',
        'payerReference' => 'hotspot-' . $invoice,
        'callbackURL' => $callback,
        'amount' => number_format($amount, 2, '.', ''),
        'currency' => 'BDT',
        'intent' => 'sale',
        'merchantInvoiceNumber' => $invoice,
    ];
    $res = http_json(bkash_base_url() . '/create', [
        'authorization: ' . $token,
        'x-app-key: ' . BKASH_APP_KEY,
    ], $payload);
    $res['_payload'] = $payload;
    if (empty($res['bkashURL']) || empty($res['paymentID'])) {
        throw new Exception('bKash create failed: ' . json_encode($res, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
    }
    return $res;
}

function bkash_execute_payment(string $paymentID): array {
    $token = bkash_grant_token();
    return http_json(bkash_base_url() . '/execute', [
        'authorization: ' . $token,
        'x-app-key: ' . BKASH_APP_KEY,
    ], ['paymentID' => $paymentID]);
}

function mikrotik_resolve_hotspot_profile_id(RouterosAPI $API, string $profile): string {
    $profile = trim($profile);
    if ($profile === '') {
        throw new Exception('MikroTik profile empty. Check config.php package profile.');
    }

    // RouterOS may treat a profile name as a partial match.
    // Example: profile "1day" can match "1day" and "1day-10M" and then API returns:
    // ambiguous value of profile, more than one possible value matches input.
    // So we always find the exact profile and use the internal .id.
    $profiles = $API->comm('/ip/hotspot/user/profile/print');
    $matches = [];
    foreach ($profiles as $row) {
        if (isset($row['name']) && (string)$row['name'] === $profile && !empty($row['.id'])) {
            $matches[] = $row;
        }
    }

    if (count($matches) === 1) {
        return (string)$matches[0]['.id'];
    }

    if (count($matches) > 1) {
        throw new Exception('Duplicate exact MikroTik hotspot profile found: ' . $profile . '. Please keep one profile name only.');
    }

    $available = [];
    foreach ($profiles as $row) {
        if (!empty($row['name'])) $available[] = (string)$row['name'];
    }
    throw new Exception('MikroTik hotspot profile not found: ' . $profile . '. Available profiles: ' . implode(', ', $available));
}

function mikrotik_upsert_hotspot_user(string $username, string $password, string $profile, string $comment): void {
    $API = new RouterosAPI();
    $API->debug = false;
    $API->port = MT_PORT;
    if (!$API->connect(MT_HOST, MT_USER, MT_PASS)) {
        throw new Exception('MikroTik API connect failed. Check host/port/user/pass/firewall.');
    }

    $profileId = mikrotik_resolve_hotspot_profile_id($API, $profile);

    $found = $API->comm('/ip/hotspot/user/print', ['?name' => $username]);
    if (!empty($found[0]['.id'])) {
        $API->comm('/ip/hotspot/user/set', [
            '.id' => $found[0]['.id'],
            'password' => $password,
            'profile' => $profileId,
            'disabled' => 'no',
            'comment' => $comment,
        ]);
    } else {
        $API->comm('/ip/hotspot/user/add', [
            'name' => $username,
            'password' => $password,
            'profile' => $profileId,
            'disabled' => 'no',
            'comment' => $comment,
        ]);
    }
    $API->disconnect();
}

function auto_login_html(?string $loginUrl, ?string $dst, string $username, string $password): string {
    $loginUrl = trim((string)$loginUrl) ?: MT_LOGIN_FALLBACK;
    $dst = trim((string)$dst) ?: 'http://neverssl.com/';
    return "<!doctype html><html lang='bn'><head><meta charset='utf-8'><meta name='viewport' content='width=device-width,initial-scale=1'><title>Connecting...</title><style>body{font-family:Arial,sans-serif;background:#f7f7f7;text-align:center;padding:30px}.box{max-width:460px;margin:50px auto;background:#fff;padding:24px;border-radius:16px;box-shadow:0 12px 35px rgba(0,0,0,.08)}button{background:#14a44d;color:#fff;border:0;border-radius:10px;padding:13px 22px;font-size:18px;font-weight:bold}.token{font-size:22px;font-weight:bold;color:#e2136e}</style></head><body><div class='box'><h2>Payment success ✅</h2><p>ইন্টারনেট auto connect হচ্ছে...</p><form id='f' method='post' action='".h($loginUrl)."'><input type='hidden' name='username' value='".h($username)."'><input type='hidden' name='password' value='".h($password)."'><input type='hidden' name='dst' value='".h($dst)."'><input type='hidden' name='popup' value='true'></form><script>setTimeout(function(){document.getElementById('f').submit();},800);</script><p>Auto না হলে:</p><button onclick=\"document.getElementById('f').submit()\">Connect Now</button><p>Token: <span class='token'>".h($username)."</span></p></div></body></html>";
}


function bkash_redirect_html(string $bkashURL): string {
    // IMPORTANT FIX:
    // bKash URL hash contains special characters (&, ), !, * etc.).
    // HTML href needs htmlspecialchars, but JavaScript redirect MUST use the raw URL via json_encode.
    // Otherwise & becomes &amp; and bKash shows: Invalid page access request.
    $href = h($bkashURL);
    $jsUrl = json_encode($bkashURL, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
    return "<!doctype html><html lang='bn'><head><meta charset='utf-8'><meta name='viewport' content='width=device-width,initial-scale=1'><title>Opening bKash...</title><style>body{font-family:Arial,sans-serif;background:#f7f7f7;text-align:center;padding:28px}.box{max-width:460px;margin:45px auto;background:#fff;padding:24px;border-radius:16px;box-shadow:0 12px 35px rgba(0,0,0,.08)}a.btn{display:inline-block;background:#e2136e;color:#fff;text-decoration:none;border-radius:10px;padding:13px 22px;font-size:18px;font-weight:bold}.small{font-size:13px;color:#555;margin-top:12px;line-height:1.5}.warn{background:#fff3cd;border:1px solid #ffe69c;border-radius:10px;padding:10px;margin-top:14px;color:#664d03}</style></head><body><div class='box'><h2>bKash Payment</h2><p>Payment page খুলছে...</p><p><a class='btn' href='".$href."' target='_top'>Open bKash Payment</a></p><p class='small'>Auto open না হলে button চাপুন। পুরনো/আগের bKash link আবার open করবেন না—নতুন payment click করলে নতুন link generate হবে।</p><p class='warn'>Hotspot captive browser এ সমস্যা হলে Chrome/Browser এ খুলুন। MikroTik walled-garden এ bKash domain allow থাকতে হবে।</p></div><script>setTimeout(function(){ window.top.location.href = ".$jsUrl."; }, 500);</script></body></html>";
}

function error_page(string $title, string $message): void {
    http_response_code(400);
    echo "<!doctype html><html lang='bn'><head><meta charset='utf-8'><meta name='viewport' content='width=device-width,initial-scale=1'><title>".h($title)."</title></head><body style='font-family:Arial;text-align:center;padding:35px'><h2>".h($title)."</h2><p>".h($message)."</p></body></html>";
}
