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

if (!isset($_SESSION['admin'])) {
    header("Location: admin_login.php");
    exit();
}

$conn = new mysqli(
    "localhost",
    "nassrrkx_Asovtu",
    "nassrrkx_Asovtu",
    "nassrrkx_Asovtu"
);

if ($conn->connect_error) {
    die("DB Error");
}

$conn->set_charset("utf8mb4");
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);


/* ============================================================
   SCHEMA-DRIVEN UPGRADE
   ============================================================ */

$requiredCols = [
    'nin_firstname'  => "ALTER TABLE validation_requests ADD COLUMN nin_firstname VARCHAR(120) NULL AFTER nin",
    'nin_middlename' => "ALTER TABLE validation_requests ADD COLUMN nin_middlename VARCHAR(120) NULL AFTER nin_firstname",
    'nin_surname'    => "ALTER TABLE validation_requests ADD COLUMN nin_surname VARCHAR(120) NULL AFTER nin_middlename",
    'nin_dob'        => "ALTER TABLE validation_requests ADD COLUMN nin_dob VARCHAR(40) NULL AFTER nin_surname",
    'nin_photo'      => "ALTER TABLE validation_requests ADD COLUMN nin_photo MEDIUMTEXT NULL AFTER nin_dob",
    'nin_photo_path' => "ALTER TABLE validation_requests ADD COLUMN nin_photo_path VARCHAR(255) NULL AFTER nin_photo",
    'verified_at'    => "ALTER TABLE validation_requests ADD COLUMN verified_at DATETIME NULL AFTER nin_photo_path",
    'verify_status'  => "ALTER TABLE validation_requests ADD COLUMN verify_status VARCHAR(40) NULL AFTER verified_at",
];

$existingCols = [];

try {
    $colRes = $conn->query("SHOW COLUMNS FROM validation_requests");

    if ($colRes instanceof mysqli_result) {
        while ($cr = $colRes->fetch_assoc()) {
            $existingCols[(string)$cr['Field']] = true;
        }
    }
} catch (Throwable $e) {
}

foreach ($requiredCols as $col => $sql) {
    if (isset($existingCols[$col])) {
        continue;
    }

    try {
        $conn->query($sql);
    } catch (Throwable $e) {
    }
}


/* ============================================================
   HELPERS
   ============================================================ */

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

function naira($v)
{
    return number_format((float)($v ?? 0), 2);
}

function isAjaxRequest(): bool
{
    return isset($_SERVER['HTTP_X_REQUESTED_WITH']) &&
           strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) === 'xmlhttprequest';
}


function columnMap(mysqli $conn, string $table, array $cols): array
{
    $out = array_fill_keys($cols, false);

    try {
        $res = $conn->query("SHOW COLUMNS FROM `{$table}`");

        if ($res instanceof mysqli_result) {
            while ($r = $res->fetch_assoc()) {
                $f = (string)($r['Field'] ?? '');

                if (isset($out[$f])) {
                    $out[$f] = true;
                }
            }
        }
    } catch (Throwable $e) {
    }

    return $out;
}


/* ============================================================
   NIN API
   ============================================================ */

const NIN_API_URL = 'https://new.unifyxpress.com/api/v4/verify/nin';
const NIN_API_KEY = 'sk_live_uqSkHKwJDJjKgrQZR8knNJHHtsSOFK3dybnD';


function ninApiCall(string $nin): array
{
    $headersList = [
        [
            'Content-Type: application/json',
            "Authorization: Bearer " . NIN_API_KEY
        ],
        [
            'Content-Type: application/json',
            "Authorization: " . NIN_API_KEY
        ],
        [
            'Content-Type: application/json',
            "x-api-key: " . NIN_API_KEY
        ],
    ];

    $payload = json_encode(
        ['nin' => $nin],
        JSON_UNESCAPED_SLASHES
    );

    $lastBody = '';
    $lastHttp = 0;
    $decoded = null;

    foreach ($headersList as $headers) {

        $ch = curl_init(NIN_API_URL);

        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_POST           => true,
            CURLOPT_POSTFIELDS     => $payload,
            CURLOPT_HTTPHEADER     => $headers,
            CURLOPT_TIMEOUT        => 25,
            CURLOPT_CONNECTTIMEOUT => 10,
            CURLOPT_SSL_VERIFYPEER => true,
        ]);

        $body = curl_exec($ch);

        $http = (int)curl_getinfo(
            $ch,
            CURLINFO_HTTP_CODE
        );

        curl_close($ch);

        $j = json_decode((string)$body, true);

        if (
            is_array($j) &&
            $http === 200 &&
            isset($j['data']['nin'])
        ) {
            return [
                'success'   => true,
                'no_record' => false,
                'suspended' => false,
                'photo_err' => false,
                'record'    => $j['data'],
                'raw'       => $j,
                'http'      => $http
            ];
        }

        $lastBody = (string)$body;
        $lastHttp = $http;
        $decoded = $j;
    }

    $lower = strtolower($lastBody);

    $suspended = is_array($decoded) && (
        strpos($lower, 'suspend') !== false ||
        strpos($lower, 'inactive') !== false ||
        strpos($lower, 'deactivat') !== false
    );

    return [
        'success'   => false,
        'no_record' => !$suspended,
        'suspended' => $suspended,
        'photo_err' => false,
        'record'    => is_array($decoded)
                        ? ($decoded['data'] ?? null)
                        : null,
        'raw'       => is_array($decoded)
                        ? $decoded
                        : [
                            'raw_body' => $lastBody,
                            'http'     => $lastHttp
                        ],
        'http'      => $lastHttp
    ];
}


/* ============================================================
   DOB
   ============================================================ */

function formatDobForReply(string $raw): string
{
    $raw = trim($raw);

    if ($raw === '') {
        return '';
    }

    $ts = strtotime($raw);

    if ($ts !== false) {
        return date('d-m-Y', $ts);
    }

    if (
        preg_match(
            '/^(\d{1,2})[-\/](\d{1,2})[-\/](\d{2,4})$/',
            $raw,
            $m
        )
    ) {
        $dd = str_pad(
            $m[1],
            2,
            '0',
            STR_PAD_LEFT
        );

        $mm = str_pad(
            $m[2],
            2,
            '0',
            STR_PAD_LEFT
        );

        $yy = strlen($m[3]) === 2
            ? '19' . $m[3]
            : $m[3];

        return $dd . '-' . $mm . '-' . $yy;
    }

    return $raw;
}


/* ============================================================
   FOUND REPLY
   ============================================================ */

function buildFoundReply(array $r): string
{
    $fn = trim((string)($r['firstname'] ?? ''));
    $mn = trim((string)($r['middlename'] ?? ''));
    $sn = trim((string)($r['surname'] ?? ''));

    $name = trim(
        $fn . ' ' .
        ($mn !== '' ? $mn . ' ' : '') .
        $sn
    );

    return $name . "\n" .
           formatDobForReply(
               (string)($r['dob'] ?? '')
           );
}


/* ============================================================
   DEBUG LOG
   ============================================================ */

function logDebug(string $msg): void
{
    $dir = __DIR__ . '/uploads/nin_photos';

    if (!is_dir($dir)) {
        @mkdir($dir, 0775, true);
    }

    @file_put_contents(
        $dir . '/_debug.log',
        '[' . date('Y-m-d H:i:s') . '] ' .
        $msg . "\n",
        FILE_APPEND
    );
}


/* ============================================================
   SAVE VERIFICATION PHOTO
   ============================================================ */

function saveVerificationPhoto(
    int $rowId,
    string $photoRaw
): array {

    if ($photoRaw === '') {
        return [
            'path' => '',
            'error' => 'photo field was empty'
        ];
    }

    $photoRaw = trim($photoRaw);

    $dir = __DIR__ . '/uploads/nin_photos';

    if (!is_dir($dir)) {

        if (
            !@mkdir($dir, 0775, true) &&
            !is_dir($dir)
        ) {
            return [
                'path' => '',
                'error' => "could not create directory: {$dir}"
            ];
        }
    }

    if (!is_writable($dir)) {
        return [
            'path' => '',
            'error' =>
                "directory not writable by PHP: {$dir}"
        ];
    }

    $bin = null;
    $ext = 'jpg';

    if (
        stripos(
            $photoRaw,
            'data:image/'
        ) === 0
    ) {

        if (
            !preg_match(
                '#^data:image/([a-z0-9]+);base64,(.*)$#is',
                $photoRaw,
                $m
            )
        ) {
            return [
                'path' => '',
                'error' =>
                    'malformed data:image base64 string'
            ];
        }

        $ext = strtolower($m[1]);

        $cleanB64 = preg_replace(
            '/\s+/',
            '',
            $m[2]
        );

        $bin = base64_decode(
            $cleanB64,
            true
        );

        if (
            $bin === false ||
            $bin === ''
        ) {
            return [
                'path' => '',
                'error' =>
                    'base64_decode failed'
            ];
        }

    } elseif (
        preg_match(
            '#^https?://#i',
            $photoRaw
        )
    ) {

        $ch = curl_init($photoRaw);

        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_FOLLOWLOCATION => true,
            CURLOPT_TIMEOUT        => 15,
            CURLOPT_SSL_VERIFYPEER => true,
        ]);

        $bin = curl_exec($ch);

        $curlErr = curl_error($ch);

        $http = (int)curl_getinfo(
            $ch,
            CURLINFO_HTTP_CODE
        );

        $ct = (string)curl_getinfo(
            $ch,
            CURLINFO_CONTENT_TYPE
        );

        curl_close($ch);

        if (
            !is_string($bin) ||
            $bin === ''
        ) {
            return [
                'path' => '',
                'error' =>
                    "failed to download photo URL " .
                    "(http={$http}" .
                    (
                        $curlErr !== ''
                        ? ", curl_error={$curlErr}"
                        : ''
                    ) .
                    ')'
            ];
        }

        if (
            stripos($ct, 'png') !== false
        ) {
            $ext = 'png';
        } elseif (
            stripos($ct, 'webp') !== false
        ) {
            $ext = 'webp';
        } elseif (
            stripos($ct, 'jpeg') !== false ||
            stripos($ct, 'jpg') !== false
        ) {
            $ext = 'jpg';
        }

    } else {

        $cleanB64 = preg_replace(
            '/\s+/',
            '',
            $photoRaw
        );

        $bin = base64_decode(
            $cleanB64,
            true
        );

        if (
            $bin === false ||
            $bin === ''
        ) {
            return [
                'path' => '',
                'error' =>
                    'base64_decode failed for raw string'
            ];
        }

        $ext = 'jpg';
    }

    $path =
        $dir . '/' .
        $rowId . '_' .
        substr(
            bin2hex(random_bytes(4)),
            0,
            8
        ) .
        '.' .
        $ext;

    $written = @file_put_contents(
        $path,
        $bin
    );

    if (
        $written === false ||
        $written === 0
    ) {

        $err = error_get_last();

        return [
            'path' => '',
            'error' =>
                'file_put_contents failed: ' .
                ($err['message'] ?? 'unknown filesystem error')
        ];
    }

    @chmod($path, 0644);

    return [
        'path' =>
            'uploads/nin_photos/' .
            basename($path),
        'error' => ''
    ];
}


/* ============================================================
   STATUS BADGE
   ============================================================ */

function getStatusBadgeHtml(
    string $status
): string {

    $s = strtolower(trim($status));

    if ($s === 'successful') {

        return "
        <span class='px-2 py-1 bg-green-500/20
                     text-green-400 rounded-full text-xs'>
            Successful
        </span>";

    } elseif ($s === 'failed') {

        return "
        <span class='px-2 py-1 bg-red-500/20
                     text-red-400 rounded-full text-xs'>
            Failed
        </span>";

    } elseif ($s === 'processing') {

        return "
        <span class='px-2 py-1 bg-blue-500/20
                     text-blue-400 rounded-full text-xs'>
            Processing
        </span>";

    } elseif ($s === 'in progress') {

        return "
        <span class='px-2 py-1 bg-orange-500/20
                     text-orange-400 rounded-full text-xs'>
            In Progress
        </span>";
    }

    return "
    <span class='px-2 py-1 bg-yellow-500/20
                 text-yellow-400 rounded-full text-xs'>
        Pending
    </span>";
}


/* ============================================================
   4-DAY COUNTDOWN HELPERS
   ============================================================ */

function isCountdownStatus(
    string $status
): bool {

    $s = strtolower(trim($status));

    return in_array(
        $s,
        [
            'pending',
            'in progress',
            'processing'
        ],
        true
    );
}


function getCountdownDeadline(
    $createdAt
): int {

    $createdTs = strtotime(
        (string)$createdAt
    );

    if ($createdTs === false) {
        $createdTs = time();
    }

    /*
     * Exactly 4 days / 96 hours.
     */
    return $createdTs + (
        4 * 24 * 60 * 60
    );
}


function getCountdownHtml(
    array $row
): string {

    $status = strtolower(
        trim(
            (string)($row['status'] ?? '')
        )
    );

    $id = (int)(
        $row['id'] ?? 0
    );

    /*
     * Successful and Failed requests
     * immediately stop the countdown.
     */
    if (!isCountdownStatus($status)) {

        return '
        <span class="countdown-stopped
                     text-green-400
                     text-xs
                     font-semibold">

            <i class="fa-solid fa-circle-check"></i>
            Completed

        </span>';
    }

    $deadline = getCountdownDeadline(
        $row['created_at'] ?? ''
    );

    return '
    <div class="countdown-box"
         data-countdown-id="' . $id . '"
         data-deadline="' . $deadline . '">

        <div class="text-xs text-gray-400 mb-1">
            <i class="fa-regular fa-clock"></i>
            Time Remaining
        </div>

        <div class="countdown-value
                    text-yellow-300
                    font-bold
                    text-sm">

            Calculating...

        </div>

    </div>';
}


/* ============================================================
   REFUND
   ============================================================ */

function getRefundHtml(
    array $row
): string {

    $id = (int)(
        $row['id'] ?? 0
    );

    $status = strtolower(
        (string)($row['status'] ?? '')
    );

    $refunded = (int)(
        $row['refunded'] ?? 0
    );

    if ($refunded === 1) {

        return '
        <span class="text-green-400 text-xs">
            Refunded 80%
        </span>';
    }

    if ($status === 'failed') {

        return '
        <form method="post"
              class="refund-form">

            <input type="hidden"
                   name="id"
                   value="' . $id . '">

            <button
                name="refund"
                class="bg-red-500
                       px-3 py-1
                       rounded
                       text-xs
                       hover:bg-red-600">

                Refund 80%

            </button>

        </form>';
    }

    return '-';
}


/* ============================================================
   DASHBOARD STATS
   ============================================================ */

function getDashboardStats(
    mysqli $conn
): array {

    $stats = [
        'today' => [
            'count' => 0,
            'spent' => 0
        ],
        'week' => [
            'count' => 0,
            'spent' => 0
        ],
        'month' => [
            'count' => 0,
            'spent' => 0
        ],
        'total' => [
            'count' => 0,
            'spent' => 0
        ],
        'in_progress' => [
            'count' => 0
        ],
        'processing' => [
            'count' => 0
        ],
    ];

    $res = $conn->query("
        SELECT

        SUM(
            CASE
                WHEN DATE(created_at) = CURDATE()
                THEN 1 ELSE 0
            END
        ) AS today_count,

        SUM(
            CASE
                WHEN DATE(created_at) = CURDATE()
                THEN price ELSE 0
            END
        ) AS today_spent,

        SUM(
            CASE
                WHEN YEARWEEK(
                    created_at,
                    1
                ) =
                YEARWEEK(
                    CURDATE(),
                    1
                )
                THEN 1 ELSE 0
            END
        ) AS week_count,

        SUM(
            CASE
                WHEN YEARWEEK(
                    created_at,
                    1
                ) =
                YEARWEEK(
                    CURDATE(),
                    1
                )
                THEN price ELSE 0
            END
        ) AS week_spent,

        SUM(
            CASE
                WHEN YEAR(created_at)
                     = YEAR(CURDATE())
                 AND
                     MONTH(created_at)
                     = MONTH(CURDATE())
                THEN 1 ELSE 0
            END
        ) AS month_count,

        SUM(
            CASE
                WHEN YEAR(created_at)
                     = YEAR(CURDATE())
                 AND
                     MONTH(created_at)
                     = MONTH(CURDATE())
                THEN price ELSE 0
            END
        ) AS month_spent,

        COUNT(*) AS total_count,

        SUM(price) AS total_spent,

        SUM(
            CASE
                WHEN LOWER(TRIM(status))
                     = 'in progress'
                THEN 1 ELSE 0
            END
        ) AS in_progress_count,

        SUM(
            CASE
                WHEN LOWER(TRIM(status))
                     = 'processing'
                THEN 1 ELSE 0
            END
        ) AS processing_count

        FROM validation_requests
    ");

    if ($res instanceof mysqli_result) {

        $s = $res->fetch_assoc();

        if ($s) {

            foreach (
                ['today', 'week', 'month', 'total']
                as $k
            ) {

                $stats[$k]['count'] =
                    (int)(
                        $s[$k . '_count'] ?? 0
                    );

                $stats[$k]['spent'] =
                    (float)(
                        $s[$k . '_spent'] ?? 0
                    );
            }

            $stats['in_progress']['count'] =
                (int)(
                    $s['in_progress_count'] ?? 0
                );

            $stats['processing']['count'] =
                (int)(
                    $s['processing_count'] ?? 0
                );
        }
    }

    return $stats;
}


/* ============================================================
   STATS CARDS
   ============================================================ */

function renderStatsCards(
    array $stats
): string {

    ob_start();
    ?>

    <div
        class="grid sm:grid-cols-2 lg:grid-cols-3
               xl:grid-cols-6 gap-4 mb-6"
        id="stats-container">

        <div class="bg-blue-600 p-5 rounded-xl shadow">

            <div class="text-lg font-semibold mb-2">
                Today
            </div>

            <div class="text-sm">
                Today Count:
                <?= $stats['today']['count'] ?>
            </div>

            <div class="text-sm">
                Today Spent:
                ₦<?= naira($stats['today']['spent']) ?>
            </div>

        </div>


        <div class="bg-green-600 p-5 rounded-xl shadow">

            <div class="text-lg font-semibold mb-2">
                Weekly
            </div>

            <div class="text-sm">
                Weekly Count:
                <?= $stats['week']['count'] ?>
            </div>

            <div class="text-sm">
                Weekly Spent:
                ₦<?= naira($stats['week']['spent']) ?>
            </div>

        </div>


        <div class="bg-purple-600 p-5 rounded-xl shadow">

            <div class="text-lg font-semibold mb-2">
                Monthly
            </div>

            <div class="text-sm">
                Monthly Count:
                <?= $stats['month']['count'] ?>
            </div>

            <div class="text-sm">
                Monthly Spent:
                ₦<?= naira($stats['month']['spent']) ?>
            </div>

        </div>


        <div class="bg-orange-600 p-5 rounded-xl shadow">

            <div class="text-lg font-semibold mb-2">
                Total
            </div>

            <div class="text-sm">
                Total Count:
                <?= $stats['total']['count'] ?>
            </div>

            <div class="text-sm">
                Total Spent:
                ₦<?= naira($stats['total']['spent']) ?>
            </div>

        </div>


        <div class="bg-amber-600 p-5 rounded-xl shadow">

            <div class="text-lg font-semibold mb-2">
                In Progress
            </div>

            <div class="text-sm">
                Total In Progress:
                <?= $stats['in_progress']['count'] ?>
            </div>

        </div>


        <div class="bg-cyan-600 p-5 rounded-xl shadow">

            <div class="text-lg font-semibold mb-2">
                Processing
            </div>

            <div class="text-sm">
                Total Processing:
                <?= $stats['processing']['count'] ?>
            </div>

        </div>

    </div>

    <?php
    return ob_get_clean();
}


/* ============================================================
   PAGINATION FETCH
   ============================================================ */

function fetchValidationRows(
    mysqli $conn,
    string $searchNin = '',
    string $searchStatus = '',
    int $page = 1,
    int $perPage = 10
): array {

    $page = max(1, $page);

    $offset =
        ($page - 1) *
        $perPage;

    $rows = [];
    $total = 0;

    $where = [];
    $params = [];
    $types = '';

    if ($searchNin !== '') {

        $where[] = 'nin LIKE ?';

        $params[] =
            '%' . $searchNin . '%';

        $types .= 's';
    }

    if ($searchStatus !== '') {

        $where[] =
            'LOWER(TRIM(status)) = ?';

        $params[] =
            strtolower($searchStatus);

        $types .= 's';
    }

    $whereSql =
        empty($where)
        ? ''
        : 'WHERE ' . implode(
            ' AND ',
            $where
        );


    /* COUNT */

    $countSql = "
        SELECT COUNT(*) AS cnt
        FROM validation_requests
        {$whereSql}
    ";

    if ($types !== '') {

        $cstmt =
            $conn->prepare($countSql);

        $refArgs = [];

        foreach (
            $params as $k => $v
        ) {
            $refArgs[$k] =
                &$params[$k];
        }

        call_user_func_array(
            [$cstmt, 'bind_param'],
            array_merge(
                [$types],
                $refArgs
            )
        );

        $cstmt->execute();

        $cres =
            $cstmt->get_result();

        if (
            $cres instanceof mysqli_result
        ) {

            $crow =
                $cres->fetch_assoc();

            $total =
                (int)(
                    $crow['cnt'] ?? 0
                );
        }

        $cstmt->close();

    } else {

        $cres =
            $conn->query($countSql);

        if (
            $cres instanceof mysqli_result
        ) {

            $crow =
                $cres->fetch_assoc();

            $total =
                (int)(
                    $crow['cnt'] ?? 0
                );
        }
    }


    /* LIST */

    $listSql = "
        SELECT *
        FROM validation_requests
        {$whereSql}
        ORDER BY id DESC
        LIMIT ?
        OFFSET ?
    ";

    $listTypes =
        $types . 'ii';

    $listParams =
        $params;

    $listParams[] =
        $perPage;

    $listParams[] =
        $offset;

    $stmt =
        $conn->prepare($listSql);

    $refArgs = [];

    foreach (
        $listParams as $k => $v
    ) {
        $refArgs[$k] =
            &$listParams[$k];
    }

    call_user_func_array(
        [$stmt, 'bind_param'],
        array_merge(
            [$listTypes],
            $refArgs
        )
    );

    $stmt->execute();

    $res =
        $stmt->get_result();

    if (
        $res instanceof mysqli_result
    ) {

        while (
            $row =
            $res->fetch_assoc()
        ) {

            $rows[] = $row;
        }
    }

    $stmt->close();

    return [
        'rows' => $rows,
        'total' => $total
    ];
}


/* ============================================================
   SEARCH INFO
   ============================================================ */

function renderSearchInfo(
    string $searchNin,
    string $searchStatus,
    int $total
): string {

    if (
        $searchNin === '' &&
        $searchStatus === ''
    ) {
        return '';
    }

    $parts = [];

    if ($searchNin !== '') {

        $parts[] =
            'NIN: <span class="text-white font-semibold">' .
            h($searchNin) .
            '</span>';
    }

    if ($searchStatus !== '') {

        $parts[] =
            'Status: <span class="text-white font-semibold">' .
            h($searchStatus) .
            '</span>';
    }

    return
        '<div class="mt-3 text-sm text-gray-300">' .
        'Showing ' .
        $total .
        ' result(s) for ' .
        implode(
            ' &middot; ',
            $parts
        ) .
        '</div>';
}


/* ============================================================
   PAGINATION HTML
   ============================================================ */

function renderPaginationHtml(
    int $page,
    int $perPage,
    int $total,
    string $searchNin = '',
    string $searchStatus = ''
): string {

    $totalPages =
        (int)ceil(
            $total /
            max(1, $perPage)
        );

    if ($totalPages <= 1) {
        return '';
    }

    $page =
        max(
            1,
            min(
                $page,
                $totalPages
            )
        );

    ob_start();
    ?>

    <div
        class="flex flex-wrap
               items-center justify-between
               gap-3 p-4 text-sm"
        data-current-page="<?= $page ?>"
        data-total-pages="<?= $totalPages ?>">

        <div class="text-gray-300">

            Page <?= $page ?>
            of <?= $totalPages ?>

            (<?= $total ?> total)

        </div>


        <div class="flex flex-wrap gap-1">

            <button
                type="button"
                class="page-btn px-3 py-1 rounded
                       bg-black/30 hover:bg-black/50
                       disabled:opacity-40
                       disabled:cursor-not-allowed"
                data-page="<?= max(1, $page - 1) ?>"
                <?= $page <= 1 ? 'disabled' : '' ?>>

                Prev

            </button>


            <?php

            $start =
                max(
                    1,
                    $page - 2
                );

            $end =
                min(
                    $totalPages,
                    $page + 2
                );

            if ($start > 1) {

                echo '
                <button
                    type="button"
                    class="page-btn px-3 py-1 rounded
                           bg-black/30 hover:bg-black/50"
                    data-page="1">
                    1
                </button>';

                if ($start > 2) {

                    echo '
                    <span class="px-2 text-gray-400">
                        &hellip;
                    </span>';
                }
            }


            for (
                $p = $start;
                $p <= $end;
                $p++
            ):

                $active =
                    $p === $page
                    ? 'bg-blue-600'
                    : 'bg-black/30 hover:bg-black/50';

            ?>

                <button
                    type="button"
                    class="page-btn px-3 py-1 rounded <?= $active ?>"
                    data-page="<?= $p ?>"
                    <?= $p === $page ? 'disabled' : '' ?>>

                    <?= $p ?>

                </button>

            <?php
            endfor;


            if ($end < $totalPages) {

                if (
                    $end <
                    $totalPages - 1
                ) {

                    echo '
                    <span class="px-2 text-gray-400">
                        &hellip;
                    </span>';
                }

                echo '
                <button
                    type="button"
                    class="page-btn px-3 py-1 rounded
                           bg-black/30 hover:bg-black/50"
                    data-page="' .
                    $totalPages .
                    '">
                    ' .
                    $totalPages .
                    '
                </button>';
            }

            ?>

            <button
                type="button"
                class="page-btn px-3 py-1 rounded
                       bg-black/30 hover:bg-black/50
                       disabled:opacity-40
                       disabled:cursor-not-allowed"
                data-page="<?= min($totalPages, $page + 1) ?>"
                <?= $page >= $totalPages ? 'disabled' : '' ?>>

                Next

            </button>

        </div>

    </div>

    <?php

    return ob_get_clean();
}


/* ============================================================
   TABLE ROWS
   ============================================================ */

function renderTableRows(
    array $rows,
    string $searchNin = '',
    string $searchStatus = ''
): string {

    ob_start();

    if (!empty($rows)):

        foreach ($rows as $r):

            ?>

            <tr
                class="border-b border-gray-700
                       hover:bg-white/5 transition"
                data-row-id="<?= (int)$r['id'] ?>">

                <td class="p-3">
                    <?= h($r['user']) ?>
                </td>


                <td class="p-3">
                    <?= h($r['nin']) ?>
                </td>


                <td class="p-3">
                    <?= h($r['type'] ?? '') ?>
                </td>


                <td
                    class="p-3
                           text-green-400
                           font-semibold">

                    ₦<?= naira($r['price']) ?>

                </td>


                <td class="p-3 status-cell">

                    <?= getStatusBadgeHtml(
                        (string)$r['status']
                    ) ?>

                </td>


                <!-- =================================================
                     4-DAY COUNTDOWN
                     ================================================= -->

                <td class="p-3 countdown-cell">

                    <?= getCountdownHtml($r) ?>

                </td>


                <td class="p-3 refund-cell">

                    <?= getRefundHtml($r) ?>

                </td>


                <td class="p-3">

                    <!-- VERIFY -->

                    <form
                        method="post"
                        class="verify-form mb-2">

                        <input
                            type="hidden"
                            name="id"
                            value="<?= (int)$r['id'] ?>">

                        <input
                            type="hidden"
                            name="nin"
                            value="<?= h($r['nin']) ?>">

                        <button
                            type="submit"
                            name="verify_request"
                            class="w-full
                                   bg-purple-600
                                   hover:bg-purple-700
                                   text-xs
                                   p-1
                                   rounded
                                   font-semibold">

                            <i
                                class="fa-solid fa-bolt">
                            </i>

                            Verify

                        </button>

                    </form>


                    <!-- UPDATE -->

                    <form
                        method="post"
                        class="space-y-1 update-form">

                        <input
                            type="hidden"
                            name="id"
                            value="<?= (int)$r['id'] ?>">


                        <select
                            name="status"
                            class="w-full
                                   p-1
                                   rounded
                                   bg-black/30
                                   text-xs">

                            <option
                                value="Pending"
                                <?= strtolower(
                                    (string)$r['status']
                                ) === 'pending'
                                    ? 'selected'
                                    : '' ?>>

                                Pending

                            </option>


                            <option
                                value="In Progress"
                                <?= strtolower(
                                    (string)$r['status']
                                ) === 'in progress'
                                    ? 'selected'
                                    : '' ?>>

                                In Progress

                            </option>


                            <option
                                value="Processing"
                                <?= strtolower(
                                    (string)$r['status']
                                ) === 'processing'
                                    ? 'selected'
                                    : '' ?>>

                                Processing

                            </option>


                            <option
                                value="Successful"
                                <?= strtolower(
                                    (string)$r['status']
                                ) === 'successful'
                                    ? 'selected'
                                    : '' ?>>

                                Successful

                            </option>


                            <option
                                value="Failed"
                                <?= strtolower(
                                    (string)$r['status']
                                ) === 'failed'
                                    ? 'selected'
                                    : '' ?>>

                                Failed

                            </option>

                        </select>


                        <textarea
                            name="reply"
                            placeholder="Reply..."
                            class="w-full
                                   p-1
                                   rounded
                                   bg-black/30
                                   text-xs
                                   reply-cell"><?= h($r['reply'] ?? '') ?></textarea>


                        <button
                            type="submit"
                            name="update"
                            class="w-full
                                   bg-blue-600
                                   hover:bg-blue-700
                                   text-xs
                                   p-1
                                   rounded">

                            Update

                        </button>

                    </form>

                </td>

            </tr>

        <?php

        endforeach;

    else:

        ?>

        <tr>

            <td
                colspan="8"
                class="p-6
                       text-center
                       text-gray-300">

                No validation requests found
                <?= (
                    $searchNin !== '' ||
                    $searchStatus !== ''
                )
                    ? ' for the current filters.'
                    : '.' ?>

            </td>

        </tr>

    <?php

    endif;

    return ob_get_clean();
}


/* ============================================================
   VERIFY REQUEST
   ============================================================ */

if (
    $_SERVER['REQUEST_METHOD'] === 'POST' &&
    isset($_POST['verify_request'])
) {

    $reqId =
        (int)(
            $_POST['id'] ?? 0
        );

    $nin =
        trim(
            (string)(
                $_POST['nin'] ?? ''
            )
        );

    if (
        $reqId <= 0 ||
        !preg_match(
            '/^[0-9]{11}$/',
            $nin
        )
    ) {

        header(
            'Content-Type: application/json'
        );

        echo json_encode([
            'success' => false,
            'message' =>
                'Invalid row / NIN pair.'
        ]);

        exit;
    }


    $api =
        ninApiCall($nin);


    $cmap =
        columnMap(
            $conn,
            'validation_requests',
            [
                'nin',
                'nin_firstname',
                'nin_middlename',
                'nin_surname',
                'nin_dob',
                'nin_photo',
                'nin_photo_path',
                'verified_at',
                'verify_status',
                'status',
                'reply',
            ]
        );


    $newStatus = '';
    $newReply = '';

    $columnsSQL = [];
    $params = [];
    $types = '';

    $branch = '';

    $photoPath = '';
    $photoError = '';


    if ($api['success']) {

        $rec =
            $api['record'];


        $photoRaw =
            (string)(
                $rec['photo'] ?? ''
            );

        $photoFieldUsed =
            'photo';


        if ($photoRaw === '') {

            foreach (
                [
                    'photograph',
                    'image',
                    'picture',
                    'passport',
                    'face',
                    'photo_base64',
                    'photoBase64'
                ]
                as $altKey
            ) {

                if (
                    !empty(
                        $rec[$altKey]
                    )
                ) {

                    $photoRaw =
                        (string)(
                            $rec[$altKey]
                        );

                    $photoFieldUsed =
                        $altKey;

                    break;
                }
            }
        }


        $hasPhoto =
            ($photoRaw !== '');


        if ($hasPhoto) {

            $newStatus =
                'Successful';

            $newReply =
                buildFoundReply($rec);

            $branch =
                'found';

        } else {

            $newStatus =
                'Processing';

            $newReply =
                'photograph error is PROCESSING';

            $branch =
                'found_no_photo';
        }


        if (
            $cmap['nin_firstname'] &&
            $cmap['nin_middlename'] &&
            $cmap['nin_surname'] &&
            $cmap['nin_dob']
        ) {

            $columnsSQL[] =
                'nin_firstname = ?';

            $params[] =
                (string)(
                    $rec['firstname'] ?? ''
                );

            $types .= 's';


            $columnsSQL[] =
                'nin_middlename = ?';

            $params[] =
                (string)(
                    $rec['middlename'] ?? ''
                );

            $types .= 's';


            $columnsSQL[] =
                'nin_surname = ?';

            $params[] =
                (string)(
                    $rec['surname'] ?? ''
                );

            $types .= 's';


            $columnsSQL[] =
                'nin_dob = ?';

            $params[] =
                formatDobForReply(
                    (string)(
                        $rec['dob'] ?? ''
                    )
                );

            $types .= 's';
        }


        if (
            $hasPhoto &&
            $cmap['nin_photo']
        ) {

            $columnsSQL[] =
                'nin_photo = ?';

            $params[] =
                $photoRaw;

            $types .= 's';
        }


        if (
            $hasPhoto &&
            $cmap['nin_photo_path']
        ) {

            $photoResult =
                saveVerificationPhoto(
                    $reqId,
                    $photoRaw
                );

            $photoPath =
                $photoResult['path'];

            $photoError =
                $photoResult['error'];


            if ($photoPath !== '') {

                $columnsSQL[] =
                    'nin_photo_path = ?';

                $params[] =
                    $photoPath;

                $types .= 's';
            }

        } elseif (
            $hasPhoto &&
            !$cmap['nin_photo_path']
        ) {

            $photoError =
                'nin_photo_path column missing on validation_requests table';
        }


        logDebug(
            sprintf(
                "verify id=%d nin=%s branch=%s hasPhoto=%s photoField=%s recordKeys=[%s] savedPath=%s photoError=%s",
                $reqId,
                $nin,
                $branch,
                $hasPhoto
                    ? 'yes'
                    : 'no',
                $photoFieldUsed,
                implode(
                    ',',
                    array_keys($rec)
                ),
                $photoPath,
                $photoError
            )
        );


        if (
            $cmap['verified_at']
        ) {

            $columnsSQL[] =
                'verified_at = NOW()';
        }


        if (
            $cmap['verify_status']
        ) {

            $columnsSQL[] =
                'verify_status = ?';

            $params[] =
                $hasPhoto
                    ? 'found'
                    : 'found_no_photo';

            $types .= 's';
        }

    } elseif (
        $api['suspended']
    ) {

        $branch =
            'suspended';

        $newStatus =
            'Processing';

        $newReply =
            'suspended is processing';


        if (
            $cmap['verify_status']
        ) {

            $columnsSQL[] =
                'verify_status = ?';

            $params[] =
                'suspended';

            $types .= 's';
        }


        if (
            $cmap['verified_at']
        ) {

            $columnsSQL[] =
                'verified_at = NOW()';
        }

    } else {

        $branch =
            'no_record';

        $newStatus =
            'Processing';

        $newReply =
            'no record is processing';


        if (
            $cmap['verify_status']
        ) {

            $columnsSQL[] =
                'verify_status = ?';

            $params[] =
                'no_record';

            $types .= 's';
        }


        if (
            $cmap['verified_at']
        ) {

            $columnsSQL[] =
                'verified_at = NOW()';
        }
    }


    if ($cmap['status']) {

        $columnsSQL[] =
            'status = ?';

        $params[] =
            $newStatus;

        $types .= 's';
    }


    if ($cmap['reply']) {

        $columnsSQL[] =
            'reply = ?';

        $params[] =
            $newReply;

        $types .= 's';
    }


    $sql =
        "UPDATE validation_requests
         SET " .
        implode(
            ', ',
            $columnsSQL
        ) .
        " WHERE id = ?";


    $params[] =
        $reqId;

    $types .= 'i';


    $stmt =
        $conn->prepare($sql);


    $refArgs = [];

    foreach (
        $params as $i => $v
    ) {

        $refArgs[$i] =
            &$params[$i];
    }


    call_user_func_array(
        [$stmt, 'bind_param'],
        array_merge(
            [$types],
            $refArgs
        )
    );


    $stmt->execute();
    $stmt->close();


    if (isAjaxRequest()) {

        $row = null;


        $q =
            $conn->prepare("
                SELECT
                    id,
                    status,
                    refunded,
                    reply,
                    created_at
                FROM validation_requests
                WHERE id=?
                LIMIT 1
            ");


        $q->bind_param(
            "i",
            $reqId
        );

        $q->execute();


        $row =
            $q->get_result()
              ->fetch_assoc();


        $q->close();


        header(
            'Content-Type: application/json'
        );


        echo json_encode([
            'success' =>
                true,

            'message' =>
                'NIN verified.',

            'status' =>
                $newStatus,

            'reply' =>
                $newReply,

            'branch' =>
                $branch,

            'status_badge' =>
                getStatusBadgeHtml(
                    $newStatus
                ),

            'refund_html' =>
                $row
                    ? getRefundHtml($row)
                    : '-',

            'countdown_html' =>
                $row
                    ? getCountdownHtml($row)
                    : '-',

            'stats_html' =>
                renderStatsCards(
                    getDashboardStats($conn)
                ),

            'photo_saved' =>
                $photoPath !== '',

            'photo_error' =>
                $photoError,
        ]);

        exit;
    }


    header(
        'Location: ' .
        $_SERVER['REQUEST_URI']
    );

    exit;
}


/* ============================================================
   UPDATE STATUS
   ============================================================ */

$allowedStatuses = [
    'Pending',
    'In Progress',
    'Processing',
    'Successful',
    'Failed'
];


if (
    $_SERVER['REQUEST_METHOD'] === 'POST' &&
    isset($_POST['update'])
) {

    $id =
        (int)(
            $_POST['id'] ?? 0
        );

    $status =
        trim(
            (string)(
                $_POST['status']
                ?? 'Pending'
            )
        );

    $reply =
        trim(
            (string)(
                $_POST['reply']
                ?? ''
            )
        );


    if (
        !in_array(
            $status,
            $allowedStatuses,
            true
        )
    ) {

        $status =
            'Pending';
    }


    $stmt =
        $conn->prepare("
            UPDATE validation_requests
            SET status=?,
                reply=?
            WHERE id=?
        ");


    $stmt->bind_param(
        "ssi",
        $status,
        $reply,
        $id
    );


    $ok =
        $stmt->execute();


    $stmt->close();


    if (isAjaxRequest()) {

        $row = null;


        $q =
            $conn->prepare("
                SELECT
                    id,
                    status,
                    refunded,
                    reply,
                    created_at
                FROM validation_requests
                WHERE id=?
                LIMIT 1
            ");


        $q->bind_param(
            "i",
            $id
        );

        $q->execute();


        $row =
            $q->get_result()
              ->fetch_assoc();


        $q->close();


        header(
            'Content-Type: application/json'
        );


        echo json_encode([
            'success' =>
                $ok,

            'message' =>
                $ok
                    ? 'Request updated successfully.'
                    : 'Update failed.',

            'status' =>
                $status,

            'status_badge' =>
                getStatusBadgeHtml(
                    $status
                ),

            'refund_html' =>
                $row
                    ? getRefundHtml($row)
                    : '-',

            'countdown_html' =>
                $row
                    ? getCountdownHtml($row)
                    : '-',

            'reply' =>
                $reply,

            'stats_html' =>
                renderStatsCards(
                    getDashboardStats($conn)
                ),
        ]);

        exit;
    }


    header(
        'Location: ' .
        $_SERVER['REQUEST_URI']
    );

    exit;
}


/* ============================================================
   REFUND 80%
   ============================================================ */

if (
    $_SERVER['REQUEST_METHOD'] === 'POST' &&
    isset($_POST['refund'])
) {

    $id =
        (int)(
            $_POST['id'] ?? 0
        );


    $q =
        $conn->prepare("
            SELECT
                id,
                user,
                price,
                status,
                refunded
            FROM validation_requests
            WHERE id=?
            LIMIT 1
        ");


    $q->bind_param(
        "i",
        $id
    );


    $q->execute();


    $row =
        $q->get_result()
          ->fetch_assoc();


    $q->close();


    $success = false;

    $message =
        'Refund could not be processed.';


    if (
        $row &&
        strtolower(
            (string)$row['status']
        ) === 'failed' &&
        (int)$row['refunded'] === 0
    ) {

        $user =
            (string)$row['user'];

        $price =
            (float)$row['price'];

        $status =
            (string)$row['status'];

        $pct =
            80.00;

        $amt =
            round(
                $price * 0.80,
                2
            );

        $note =
            '80% refund for failed validation request';


        $conn->begin_transaction();


        try {

            $bal =
                $conn->prepare("
                    UPDATE balance
                    SET amount =
                        amount + ?
                    WHERE user = ?
                ");


            $bal->bind_param(
                "ds",
                $amt,
                $user
            );


            $bal->execute();

            $bal->close();


            $upd =
                $conn->prepare("
                    UPDATE validation_requests
                    SET refunded = 1
                    WHERE id = ?
                ");


            $upd->bind_param(
                "i",
                $id
            );


            $upd->execute();

            $upd->close();


            $ins =
                $conn->prepare("
                    INSERT INTO refund_transactions
                    (
                        validation_request_id,
                        user,
                        original_amount,
                        refund_percent,
                        refund_amount,
                        request_status,
                        note
                    )
                    VALUES
                    (?, ?, ?, ?, ?, ?, ?)
                ");


            $ins->bind_param(
                "isdddss",
                $id,
                $user,
                $price,
                $pct,
                $amt,
                $status,
                $note
            );


            $ins->execute();

            $ins->close();


            $conn->commit();

            $success =
                true;

            $message =
                'Refund processed successfully.';

        } catch (Throwable $e) {

            $conn->rollback();

            $success =
                false;

            $message =
                'Refund failed.';
        }
    }


    if (isAjaxRequest()) {

        header(
            'Content-Type: application/json'
        );


        echo json_encode([
            'success' =>
                $success,

            'message' =>
                $message,

            'refund_html' =>
                $success
                    ? '<span class="text-green-400 text-xs">Refunded 80%</span>'
                    : (
                        isset($row) &&
                        $row
                            ? getRefundHtml($row)
                            : '-'
                    ),
        ]);

        exit;
    }


    header(
        'Location: ' .
        $_SERVER['REQUEST_URI']
    );

    exit;
}


/* ============================================================
   PAGE VARIABLES
   ============================================================ */

$perPage = 10;

$searchNin =
    trim(
        (string)(
            $_GET['search_nin']
            ?? ''
        )
    );


$searchStatusRaw =
    trim(
        (string)(
            $_GET['search_status']
            ?? ''
        )
    );


$searchStatus =
    in_array(
        $searchStatusRaw,
        $allowedStatuses,
        true
    )
        ? $searchStatusRaw
        : '';


$page =
    max(
        1,
        (int)(
            $_GET['page']
            ?? 1
        )
    );


/* ============================================================
   AJAX GET SEARCH / PAGINATION
   ============================================================ */

if (
    $_SERVER['REQUEST_METHOD'] === 'GET' &&
    isAjaxRequest()
) {

    $result =
        fetchValidationRows(
            $conn,
            $searchNin,
            $searchStatus,
            $page,
            $perPage
        );


    header(
        'Content-Type: application/json'
    );


    echo json_encode([
        'success' =>
            true,

        'tbody_html' =>
            renderTableRows(
                $result['rows'],
                $searchNin,
                $searchStatus
            ),

        'search_info_html' =>
            renderSearchInfo(
                $searchNin,
                $searchStatus,
                $result['total']
            ),

        'pagination_html' =>
            renderPaginationHtml(
                $page,
                $perPage,
                $result['total'],
                $searchNin,
                $searchStatus
            ),

        'page' =>
            $page,
    ]);

    exit;
}


/* ============================================================
   INITIAL PAGE DATA
   ============================================================ */

$result =
    fetchValidationRows(
        $conn,
        $searchNin,
        $searchStatus,
        $page,
        $perPage
    );


$rows =
    $result['rows'];


$stats =
    getDashboardStats($conn);

?>
<!DOCTYPE html>

<html>

<head>

<meta charset="UTF-8">

<meta
    name="viewport"
    content="width=device-width, initial-scale=1.0">

<title>
    Validation Admin
</title>


<script src="https://cdn.tailwindcss.com">
</script>


<link
    rel="stylesheet"
    href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css">

</head>


<body
    class="bg-gradient-to-br
           from-slate-900
           via-blue-900
           to-slate-800
           text-white">


<div
    class="max-w-7xl mx-auto p-6">


<h1
    class="text-3xl font-bold mb-6">

    📋 Validation Dashboard

</h1>


<!-- TOAST -->

<div
    id="toast"
    class="hidden
           fixed
           top-5
           right-5
           z-50
           min-w-[220px]
           max-w-sm
           px-4
           py-3
           rounded-lg
           shadow-lg
           text-sm
           font-semibold
           transition-all
           duration-300
           opacity-0
           -translate-y-2">
</div>


<?= renderStatsCards($stats) ?>


<!-- SEARCH -->

<div
    class="bg-white/10
           backdrop-blur-xl
           rounded-2xl
           p-4
           mb-6">


<form
    method="get"
    id="searchForm"
    class="flex
           flex-col
           md:flex-row
           gap-3
           md:items-end">


<div class="flex-1">

<label
    class="block
           text-sm
           text-gray-300
           mb-1">

    Search by NIN

</label>


<input
    type="text"
    id="search_nin"
    name="search_nin"
    value="<?= h($searchNin) ?>"
    placeholder="Enter NIN..."
    class="w-full
           p-3
           rounded-lg
           bg-black/30
           text-white
           border
           border-gray-600
           outline-none
           focus:border-blue-400">

</div>


<div>

<label
    for="search_status"
    class="block
           text-sm
           text-gray-300
           mb-1">

    Filter by Status

</label>


<select
    id="search_status"
    name="search_status"
    class="p-3
           rounded-lg
           bg-black/30
           text-white
           border
           border-gray-600
           outline-none
           focus:border-blue-400
           min-w-[170px]">


<option
    value=""
    <?= $searchStatus === ''
        ? 'selected'
        : '' ?>>

    All Statuses

</option>


<?php foreach (
    $allowedStatuses
    as $opt
): ?>

<option
    value="<?= h($opt) ?>"
    <?= strcasecmp(
        $searchStatus,
        $opt
    ) === 0
        ? 'selected'
        : '' ?>>

    <?= h($opt) ?>

</option>

<?php endforeach; ?>


</select>

</div>


<div
    class="flex gap-2">


<button
    type="submit"
    id="searchBtn"
    class="bg-blue-600
           hover:bg-blue-700
           px-5
           py-3
           rounded-lg
           text-sm
           font-semibold">

    Search

</button>


<button
    type="button"
    id="clearSearchBtn"
    class="bg-gray-600
           hover:bg-gray-700
           px-5
           py-3
           rounded-lg
           text-sm
           font-semibold">

    Clear

</button>

</div>


</form>


<div id="search-info">

<?= renderSearchInfo(
    $searchNin,
    $searchStatus,
    $result['total']
) ?>

</div>


</div>


<!-- TABLE -->

<div
    class="bg-white/10
           backdrop-blur-xl
           rounded-2xl
           overflow-x-auto">


<table
    class="min-w-full
           text-sm">


<thead
    class="border-b
           border-gray-700
           text-gray-300">


<tr>

<th class="p-3">
    User
</th>

<th class="p-3">
    NIN
</th>

<th class="p-3">
    Type
</th>

<th class="p-3">
    Price
</th>

<th class="p-3">
    Status
</th>

<th class="p-3">
    4 Days Countdown
</th>

<th class="p-3">
    Refund
</th>

<th class="p-3">
    Action
</th>

</tr>


</thead>


<tbody id="table-body">

<?= renderTableRows(
    $rows,
    $searchNin,
    $searchStatus
) ?>

</tbody>


</table>


<div id="pagination-wrap">

<?= renderPaginationHtml(
    $page,
    $perPage,
    $result['total'],
    $searchNin,
    $searchStatus
) ?>

</div>


</div>


</div>


<script>

/* ============================================================
   TOAST
   ============================================================ */

function showToast(
    message,
    type = 'success'
) {

    const toast =
        document.getElementById('toast');

    toast.textContent =
        message;


    toast.classList.remove(
        'hidden',
        'bg-green-600',
        'bg-red-600',
        'bg-orange-600',
        'text-white',
        'opacity-0',
        '-translate-y-2'
    );


    if (type === 'success') {

        toast.classList.add(
            'bg-green-600',
            'text-white'
        );

    } else if (type === 'error') {

        toast.classList.add(
            'bg-red-600',
            'text-white'
        );

    } else {

        toast.classList.add(
            'bg-orange-600',
            'text-white'
        );
    }


    toast.classList.add(
        'opacity-100',
        'translate-y-0'
    );


    clearTimeout(
        toast.hideTimeout
    );


    toast.hideTimeout =
        setTimeout(
            () => {

                toast.classList.remove(
                    'opacity-100',
                    'translate-y-0'
                );

                toast.classList.add(
                    'opacity-0',
                    '-translate-y-2'
                );


                setTimeout(
                    () => {
                        toast.classList.add(
                            'hidden'
                        );
                    },
                    300
                );

            },
            2500
        );
}


/* ============================================================
   STATS UPDATE
   ============================================================ */

function updateStatsHtml(html) {

    const oldStats =
        document.getElementById(
            'stats-container'
        );


    if (!oldStats || !html) {
        return;
    }


    const wrapper =
        document.createElement('div');


    wrapper.innerHTML =
        html.trim();


    const newStats =
        wrapper.querySelector(
            '#stats-container'
        );


    if (newStats) {

        oldStats.replaceWith(
            newStats
        );
    }
}


/* ============================================================
   4-DAY COUNTDOWN
   ============================================================ */

const countdownTimers = {};


function formatCountdown(
    seconds
) {

    seconds =
        Math.max(
            0,
            Math.floor(seconds)
        );


    const days =
        Math.floor(
            seconds / 86400
        );


    seconds %= 86400;


    const hours =
        Math.floor(
            seconds / 3600
        );


    seconds %= 3600;


    const minutes =
        Math.floor(
            seconds / 60
        );


    const secs =
        seconds % 60;


    return (
        String(days).padStart(2, '0') +
        'd ' +
        String(hours).padStart(2, '0') +
        'h ' +
        String(minutes).padStart(2, '0') +
        'm ' +
        String(secs).padStart(2, '0') +
        's'
    );
}


function stopCountdown(id) {

    if (
        countdownTimers[id]
    ) {

        clearInterval(
            countdownTimers[id]
        );

        delete countdownTimers[id];
    }
}


function startCountdown(
    element
) {

    if (!element) {
        return;
    }


    const id =
        element.dataset.countdownId;


    const deadline =
        parseInt(
            element.dataset.deadline,
            10
        );


    if (
        !id ||
        !deadline
    ) {
        return;
    }


    /*
     * Prevent duplicate timers.
     */

    stopCountdown(id);


    const valueElement =
        element.querySelector(
            '.countdown-value'
        );


    if (!valueElement) {
        return;
    }


    function updateCountdown() {

        const now =
            Math.floor(
                Date.now() / 1000
            );


        const remaining =
            deadline - now;


        /*
         * Four days have elapsed.
         */

        if (
            remaining <= 0
        ) {

            valueElement.textContent =
                '00d 00h 00m 00s';


            valueElement.classList.remove(
                'text-yellow-300',
                'text-green-400'
            );


            valueElement.classList.add(
                'text-red-400'
            );


            stopCountdown(id);

            return;
        }


        valueElement.textContent =
            formatCountdown(
                remaining
            );
    }


    updateCountdown();


    countdownTimers[id] =
        setInterval(
            updateCountdown,
            1000
        );
}


function initCountdowns() {

    /*
     * Stop timers belonging to rows
     * that no longer exist.
     */

    Object.keys(
        countdownTimers
    ).forEach(
        id => {

            if (
                !document.querySelector(
                    '.countdown-box[data-countdown-id="' +
                    id +
                    '"]'
                )
            ) {

                stopCountdown(id);
            }
        }
    );


    /*
     * Start all visible countdowns.
     */

    document
        .querySelectorAll(
            '.countdown-box'
        )
        .forEach(
            element => {

                startCountdown(
                    element
                );
            }
        );
}


/* ============================================================
   UPDATE FORMS
   ============================================================ */

function bindUpdateForms() {

    document
        .querySelectorAll(
            '.update-form'
        )
        .forEach(
            form => {

                if (
                    form.dataset.bound === '1'
                ) {
                    return;
                }


                form.dataset.bound =
                    '1';


                form.addEventListener(
                    'submit',
                    async function(e) {

                        e.preventDefault();


                        const row =
                            form.closest('tr');


                        const statusCell =
                            row.querySelector(
                                '.status-cell'
                            );


                        const countdownCell =
                            row.querySelector(
                                '.countdown-cell'
                            );


                        const refundCell =
                            row.querySelector(
                                '.refund-cell'
                            );


                        const replyCell =
                            row.querySelector(
                                '.reply-cell'
                            );


                        const submitBtn =
                            form.querySelector(
                                'button[name="update"]'
                            );


                        const formData =
                            new FormData(form);


                        formData.append(
                            'update',
                            '1'
                        );


                        submitBtn.disabled =
                            true;


                        submitBtn.textContent =
                            'Updating...';


                        try {

                            const response =
                                await fetch(
                                    window.location.href,
                                    {
                                        method: 'POST',

                                        headers: {
                                            'X-Requested-With':
                                                'XMLHttpRequest'
                                        },

                                        body:
                                            formData
                                    }
                                );


                            const data =
                                await response.json();


                            if (
                                data.success
                            ) {

                                statusCell.innerHTML =
                                    data.status_badge;


                                refundCell.innerHTML =
                                    data.refund_html;


                                /*
                                 * Update countdown.
                                 *
                                 * Pending,
                                 * In Progress,
                                 * Processing
                                 * = running countdown.
                                 *
                                 * Successful / Failed
                                 * = Completed.
                                 */

                                if (
                                    countdownCell &&
                                    data.countdown_html !==
                                    undefined
                                ) {

                                    countdownCell.innerHTML =
                                        data.countdown_html;


                                    initCountdowns();
                                }


                                if (
                                    replyCell &&
                                    data.reply !==
                                    undefined
                                ) {

                                    replyCell.value =
                                        data.reply;
                                }


                                if (
                                    data.stats_html
                                ) {

                                    updateStatsHtml(
                                        data.stats_html
                                    );
                                }


                                bindRefundForms();
                                bindVerifyForms();


                                showToast(
                                    data.message ||
                                    'Request updated successfully.',
                                    'success'
                                );

                            } else {

                                showToast(
                                    data.message ||
                                    'Update failed.',
                                    'error'
                                );
                            }

                        } catch (err) {

                            console.error(err);

                            showToast(
                                'Network error occurred.',
                                'error'
                            );

                        } finally {

                            submitBtn.disabled =
                                false;

                            submitBtn.textContent =
                                'Update';
                        }
                    }
                );
            }
        );
}


/* ============================================================
   REFUND FORMS
   ============================================================ */

function bindRefundForms() {

    document
        .querySelectorAll(
            '.refund-form'
        )
        .forEach(
            form => {

                if (
                    form.dataset.bound === '1'
                ) {
                    return;
                }


                form.dataset.bound =
                    '1';


                form.addEventListener(
                    'submit',
                    async function(e) {

                        e.preventDefault();


                        if (
                            !confirm(
                                'Refund 80% for this failed request?'
                            )
                        ) {
                            return;
                        }


                        const row =
                            form.closest('tr');


                        const refundCell =
                            row.querySelector(
                                '.refund-cell'
                            );


                        const button =
                            form.querySelector(
                                'button[name="refund"]'
                            );


                        const formData =
                            new FormData(form);


                        formData.append(
                            'refund',
                            '1'
                        );


                        button.disabled =
                            true;


                        button.textContent =
                            'Processing...';


                        try {

                            const response =
                                await fetch(
                                    window.location.href,
                                    {
                                        method: 'POST',

                                        headers: {
                                            'X-Requested-With':
                                                'XMLHttpRequest'
                                        },

                                        body:
                                            formData
                                    }
                                );


                            const data =
                                await response.json();


                            if (
                                data.success
                            ) {

                                refundCell.innerHTML =
                                    data.refund_html;


                                showToast(
                                    data.message ||
                                    'Refund processed successfully.',
                                    'success'
                                );

                            } else {

                                button.disabled =
                                    false;

                                button.textContent =
                                    'Refund 80%';


                                showToast(
                                    data.message ||
                                    'Refund failed.',
                                    'error'
                                );
                            }

                        } catch (err) {

                            console.error(err);


                            button.disabled =
                                false;

                            button.textContent =
                                'Refund 80%';


                            showToast(
                                'Network error occurred.',
                                'error'
                            );
                        }
                    }
                );
            }
        );
}


/* ============================================================
   VERIFY FORMS
   ============================================================ */

function bindVerifyForms() {

    document
        .querySelectorAll(
            '.verify-form'
        )
        .forEach(
            form => {

                if (
                    form.dataset.bound === '1'
                ) {
                    return;
                }


                form.dataset.bound =
                    '1';


                form.addEventListener(
                    'submit',
                    async function(e) {

                        e.preventDefault();


                        const row =
                            form.closest('tr');


                        const btn =
                            form.querySelector(
                                'button[name="verify_request"]'
                            );


                        const orig =
                            btn.innerHTML;


                        const sc =
                            row.querySelector(
                                '.status-cell'
                            );


                        const rc =
                            row.querySelector(
                                '.refund-cell'
                            );


                        const countdownCell =
                            row.querySelector(
                                '.countdown-cell'
                            );


                        const reply =
                            row.querySelector(
                                '.reply-cell'
                            );


                        btn.disabled =
                            true;


                        btn.innerHTML =
                            '<i class="fa-solid fa-spinner fa-spin"></i> Verifying…';


                        try {

                            const formData =
                                new FormData(form);


                            formData.append(
                                'verify_request',
                                '1'
                            );


                            const response =
                                await fetch(
                                    window.location.href,
                                    {
                                        method: 'POST',

                                        headers: {
                                            'X-Requested-With':
                                                'XMLHttpRequest'
                                        },

                                        body:
                                            formData
                                    }
                                );


                            const data =
                                await response.json();


                            if (
                                data.success
                            ) {

                                if (sc) {

                                    sc.innerHTML =
                                        data.status_badge;
                                }


                                if (rc) {

                                    rc.innerHTML =
                                        data.refund_html;
                                }


                                /*
                                 * IMPORTANT:
                                 *
                                 * If API verification succeeds
                                 * and status becomes Successful,
                                 * countdown stops.
                                 *
                                 * If API returns no record,
                                 * status becomes Processing
                                 * and countdown continues.
                                 */

                                if (
                                    countdownCell &&
                                    data.countdown_html !==
                                    undefined
                                ) {

                                    countdownCell.innerHTML =
                                        data.countdown_html;


                                    initCountdowns();
                                }


                                if (
                                    reply &&
                                    data.reply !==
                                    undefined
                                ) {

                                    reply.value =
                                        data.reply;
                                }


                                if (
                                    data.stats_html
                                ) {

                                    updateStatsHtml(
                                        data.stats_html
                                    );
                                }


                                bindRefundForms();
                                bindVerifyForms();


                                const branch =
                                    data.branch ||
                                    '';


                                let msg =
                                    data.message ||
                                    'NIN verified.';


                                let toastType =
                                    'info';


                                if (
                                    branch ===
                                    'no_record'
                                ) {

                                    msg =
                                        'No record — mark as Processing.';

                                } else if (
                                    branch ===
                                    'suspended'
                                ) {

                                    msg =
                                        'Suspended — mark as Processing.';

                                } else if (
                                    branch ===
                                    'found_no_photo'
                                ) {

                                    msg =
                                        'Record found, photograph missing.';

                                } else if (
                                    branch ===
                                    'found'
                                ) {

                                    if (
                                        data.photo_saved
                                    ) {

                                        msg =
                                            'Record found — photo saved.';

                                        toastType =
                                            'success';

                                    } else {

                                        msg =
                                            'Record found, but photo was NOT saved: ' +
                                            (
                                                data.photo_error ||
                                                'unknown error'
                                            );

                                        toastType =
                                            'error';
                                    }
                                }


                                showToast(
                                    msg,
                                    toastType
                                );

                            } else {

                                showToast(
                                    data.message ||
                                    'Verify failed.',
                                    'error'
                                );
                            }

                        } catch (err) {

                            console.error(err);


                            showToast(
                                'Network error during verify.',
                                'error'
                            );

                        } finally {

                            btn.disabled =
                                false;

                            btn.innerHTML =
                                orig;
                        }
                    }
                );
            }
        );
}


/* ============================================================
   SEARCH / PAGINATION
   ============================================================ */

let currentSearch =
    <?= json_encode($searchNin) ?>;


let currentStatus =
    <?= json_encode($searchStatus) ?>;


let currentPage =
    <?= (int)$page ?>;


function bindSearchForm() {

    const form =
        document.getElementById(
            'searchForm'
        );


    const input =
        document.getElementById(
            'search_nin'
        );


    const statusSelect =
        document.getElementById(
            'search_status'
        );


    const searchBtn =
        document.getElementById(
            'searchBtn'
        );


    const clearBtn =
        document.getElementById(
            'clearSearchBtn'
        );


    const tableBody =
        document.getElementById(
            'table-body'
        );


    const searchInfo =
        document.getElementById(
            'search-info'
        );


    const paginationWrap =
        document.getElementById(
            'pagination-wrap'
        );


    let debounceTimer =
        null;


    async function runSearch(
        value = '',
        status = '',
        page = 1
    ) {

        const trimmed =
            value.trim();


        const trimmedStatus =
            status.trim();


        currentSearch =
            trimmed;


        currentStatus =
            trimmedStatus;


        currentPage =
            page;


        const params =
            new URLSearchParams();


        if (
            trimmed !== ''
        ) {

            params.set(
                'search_nin',
                trimmed
            );
        }


        if (
            trimmedStatus !== ''
        ) {

            params.set(
                'search_status',
                trimmedStatus
            );
        }


        if (
            page > 1
        ) {

            params.set(
                'page',
                page
            );
        }


        const url =
            window.location.pathname +
            (
                params.toString()
                    ? '?' +
                      params.toString()
                    : ''
            );


        searchBtn.disabled =
            true;


        searchBtn.textContent =
            'Searching...';


        try {

            const response =
                await fetch(
                    url,
                    {
                        method: 'GET',

                        headers: {
                            'X-Requested-With':
                                'XMLHttpRequest'
                        }
                    }
                );


            const data =
                await response.json();


            if (
                data.success
            ) {

                tableBody.innerHTML =
                    data.tbody_html;


                searchInfo.innerHTML =
                    data.search_info_html ||
                    '';


                if (
                    paginationWrap
                ) {

                    paginationWrap.innerHTML =
                        data.pagination_html ||
                        '';
                }


                history.replaceState(
                    null,
                    '',
                    url
                );


                bindUpdateForms();
                bindRefundForms();
                bindVerifyForms();


                /*
                 * Restart countdowns
                 * after AJAX search/pagination.
                 */

                initCountdowns();

            } else {

                showToast(
                    'Search failed.',
                    'error'
                );
            }

        } catch (err) {

            console.error(err);


            showToast(
                'Network error occurred.',
                'error'
            );

        } finally {

            searchBtn.disabled =
                false;

            searchBtn.textContent =
                'Search';
        }
    }


    form.addEventListener(
        'submit',
        function(e) {

            e.preventDefault();

            runSearch(
                input.value,
                statusSelect.value,
                1
            );
        }
    );


    input.addEventListener(
        'input',
        function() {

            clearTimeout(
                debounceTimer
            );


            debounceTimer =
                setTimeout(
                    () => {

                        runSearch(
                            input.value,
                            statusSelect.value,
                            1
                        );

                    },
                    400
                );
        }
    );


    statusSelect.addEventListener(
        'change',
        function() {

            runSearch(
                input.value,
                statusSelect.value,
                1
            );
        }
    );


    clearBtn.addEventListener(
        'click',
        function() {

            input.value =
                '';

            statusSelect.value =
                '';

            runSearch(
                '',
                '',
                1
            );
        }
    );


    /*
     * Delegated pagination handler.
     */

    if (paginationWrap) {

        paginationWrap.addEventListener(
            'click',
            function(e) {

                const btn =
                    e.target.closest(
                        '.page-btn'
                    );


                if (
                    !btn ||
                    btn.disabled
                ) {
                    return;
                }


                const page =
                    parseInt(
                        btn.dataset.page,
                        10
                    );


                if (
                    !page ||
                    page === currentPage
                ) {
                    return;
                }


                runSearch(
                    currentSearch,
                    currentStatus,
                    page
                );
            }
        );
    }
}


/* ============================================================
   INITIALIZE EVERYTHING
   ============================================================ */

bindUpdateForms();

bindRefundForms();

bindVerifyForms();

bindSearchForm();

initCountdowns();

</script>


</body>
</html>