<?php

declare(strict_types=1);

/*
|--------------------------------------------------------------------------
| Debug sementara
|--------------------------------------------------------------------------
| Aktifkan hanya ketika mencari error 500.
| Setelah berhasil, ubah menjadi 0 atau hapus.
*/

ini_set('display_errors', '0');
ini_set('display_startup_errors', '0');
error_reporting(E_ALL);

/*
|--------------------------------------------------------------------------
| Session admin
|--------------------------------------------------------------------------
*/

ini_set('session.use_strict_mode', '1');
ini_set('session.use_only_cookies', '1');
ini_set('session.cookie_httponly', '1');

$isHttps = (
    (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ||
    (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) &&
        $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https')
);

session_name('ADMINPANELSESSID');

session_set_cookie_params([
    'lifetime' => 0,
    'path'     => '/',
    'domain'   => '',
    'secure'   => $isHttps,
    'httponly' => true,
    'samesite' => 'Lax',
]);

session_start();

/*
|--------------------------------------------------------------------------
| Wajib login admin
|--------------------------------------------------------------------------
*/



/*
|--------------------------------------------------------------------------
| Database
|--------------------------------------------------------------------------
| File database.php harus menyediakan variabel:
|
| $pdo = new PDO(...);
*/

$databaseFile = dirname(__DIR__) . '/config/database.php';

if (!is_file($databaseFile)) {
    http_response_code(500);
    exit('File config/database.php tidak ditemukan.');
}

require_once $databaseFile;

if (!isset($pdo) || !($pdo instanceof PDO)) {
    http_response_code(500);
    exit('Koneksi PDO tidak tersedia.');
}

/*
|--------------------------------------------------------------------------
| Helper respons JSON
|--------------------------------------------------------------------------
*/

function nexusJsonResponse(array $data, int $httpCode = 200)
{
    http_response_code($httpCode);

    header('Content-Type: application/json; charset=utf-8');
    header('X-Content-Type-Options: nosniff');
    header('Cache-Control: no-store, no-cache, must-revalidate');

    echo json_encode(
        $data,
        JSON_PRETTY_PRINT |
        JSON_UNESCAPED_UNICODE |
        JSON_UNESCAPED_SLASHES
    );

    exit;
}

/*
|--------------------------------------------------------------------------
| CSRF token
|--------------------------------------------------------------------------
*/

if (
    empty($_SESSION['csrf_sync_provider_nexus']) ||
    !is_string($_SESSION['csrf_sync_provider_nexus'])
) {
    $_SESSION['csrf_sync_provider_nexus'] = bin2hex(
        random_bytes(32)
    );
}

/*
|--------------------------------------------------------------------------
| Halaman GET
|--------------------------------------------------------------------------
*/

if ($_SERVER['REQUEST_METHOD'] === 'GET') {
    $csrfToken = htmlspecialchars(
        $_SESSION['csrf_sync_provider_nexus'],
        ENT_QUOTES,
        'UTF-8'
    );

    $actionUrl = htmlspecialchars(
        $_SERVER['PHP_SELF'] ?? '',
        ENT_QUOTES,
        'UTF-8'
    );

    header('Content-Type: text/html; charset=utf-8');
    header('X-Content-Type-Options: nosniff');
    header('Cache-Control: no-store, no-cache, must-revalidate');

    ?>
    <!DOCTYPE html>
    <html lang="id">
    <head>
        <meta charset="UTF-8">

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

        <title>Sinkronisasi Provider Nexus</title>

        <style>
            * {
                box-sizing: border-box;
            }

            body {
                margin: 0;
                min-height: 100vh;
                display: flex;
                align-items: center;
                justify-content: center;
                padding: 20px;
                background: #071426;
                color: #ffffff;
                font-family: Arial, Helvetica, sans-serif;
            }

            .card {
                width: 100%;
                max-width: 500px;
                padding: 30px;
                border: 1px solid rgba(255, 255, 255, .12);
                border-radius: 18px;
                background: #0d2038;
                box-shadow: 0 20px 60px rgba(0, 0, 0, .35);
            }

            h1 {
                margin: 0 0 12px;
                font-size: 25px;
            }

            p {
                margin: 0 0 24px;
                color: #bdd0e5;
                line-height: 1.6;
            }

            .info {
                margin-bottom: 22px;
                padding: 14px;
                border-radius: 10px;
                background: #08192c;
                color: #b9cbe0;
                font-size: 14px;
                line-height: 1.6;
            }

            button {
                width: 100%;
                min-height: 50px;
                border: 0;
                border-radius: 12px;
                padding: 12px 18px;
                background: #f2b632;
                color: #111827;
                font-size: 16px;
                font-weight: 700;
                cursor: pointer;
            }

            button:hover {
                filter: brightness(1.05);
            }
        </style>
    </head>

    <body>
        <div class="card">
            <h1>Sinkronisasi Provider Nexus</h1>

            <p>
                Mengambil daftar provider terbaru dari API Nexus
                dan menyimpannya ke tabel providers_nexus.
            </p>

            <div class="info">
                Pengaturan lokal seperti is_active, is_popular,
                popular_order, provider_type dan provider_image
                tidak akan direset saat sinkronisasi.
            </div>

            <form method="POST" action="<?= $actionUrl ?>">
                <input
                    type="hidden"
                    name="csrf_token"
                    value="<?= $csrfToken ?>"
                >

                <button type="submit">
                    Sinkronkan Provider Nexus
                </button>
            </form>
        </div>
    </body>
    </html>
    <?php

    exit;
}

/*
|--------------------------------------------------------------------------
| Hanya izinkan POST
|--------------------------------------------------------------------------
*/

if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
    header('Allow: GET, POST');

    nexusJsonResponse([
        'success' => false,
        'message' => 'Metode request tidak diperbolehkan.',
    ], 405);
}

/*
|--------------------------------------------------------------------------
| Validasi CSRF
|--------------------------------------------------------------------------
*/

$csrfInput = isset($_POST['csrf_token'])
    ? (string) $_POST['csrf_token']
    : '';

$csrfSession = isset($_SESSION['csrf_sync_provider_nexus'])
    ? (string) $_SESSION['csrf_sync_provider_nexus']
    : '';

if (
    $csrfInput === '' ||
    $csrfSession === '' ||
    !hash_equals($csrfSession, $csrfInput)
) {
    nexusJsonResponse([
        'success' => false,
        'message' => 'CSRF token tidak valid atau kedaluwarsa.',
    ], 419);
}

/*
|--------------------------------------------------------------------------
| Konfigurasi Nexus
|--------------------------------------------------------------------------
|
| Jangan tulis token asli langsung di source produksi.
|
| Environment yang disarankan:
|
| NEXUS_API_URL=https://api-provider-nexus.com
| NEXUS_AGENT_CODE=kode_agent
| NEXUS_AGENT_TOKEN=token_rahasia
*/

$apiUrl = trim(
    getenv('NEXUS_API_URL')
        ?: 'https://api.nexusggr.com'
);

$agentCode = trim(
    getenv('NEXUS_AGENT_CODE')
        ?: 'uno15'
);

$agentToken = trim(
    getenv('NEXUS_AGENT_TOKEN')
        ?: '9611e842cbd19494e0f080e2f4d4af03'
);

/*
|--------------------------------------------------------------------------
| Validasi konfigurasi
|--------------------------------------------------------------------------
*/

if (
    $apiUrl === '' ||
    $apiUrl === 'https://API_SERVER_ANDA' ||
    filter_var($apiUrl, FILTER_VALIDATE_URL) === false
) {
    nexusJsonResponse([
        'success' => false,
        'message' => 'NEXUS_API_URL belum dikonfigurasi dengan benar.',
    ], 500);
}

$apiScheme = strtolower(
    (string) parse_url($apiUrl, PHP_URL_SCHEME)
);

if ($apiScheme !== 'https') {
    nexusJsonResponse([
        'success' => false,
        'message' => 'Endpoint Nexus wajib menggunakan HTTPS.',
    ], 500);
}

if (
    $agentCode === '' ||
    $agentCode === 'MASUKKAN_AGENT_CODE'
) {
    nexusJsonResponse([
        'success' => false,
        'message' => 'NEXUS_AGENT_CODE belum dikonfigurasi.',
    ], 500);
}

if (
    $agentToken === '' ||
    $agentToken === 'MASUKKAN_AGENT_TOKEN'
) {
    nexusJsonResponse([
        'success' => false,
        'message' => 'NEXUS_AGENT_TOKEN belum dikonfigurasi.',
    ], 500);
}

/*
|--------------------------------------------------------------------------
| Payload provider_list Nexus
|--------------------------------------------------------------------------
*/

$payload = [
    'method'      => 'provider_list',
    'agent_code'  => $agentCode,
    'agent_token' => $agentToken,
];

$jsonPayload = json_encode(
    $payload,
    JSON_UNESCAPED_SLASHES |
    JSON_UNESCAPED_UNICODE
);

if ($jsonPayload === false) {
    error_log(
        'Nexus provider_list JSON encode error: ' .
        json_last_error_msg()
    );

    nexusJsonResponse([
        'success' => false,
        'message' => 'Gagal membuat payload Nexus.',
    ], 500);
}

/*
|--------------------------------------------------------------------------
| Request API Nexus
|--------------------------------------------------------------------------
*/

$ch = curl_init();

if ($ch === false) {
    nexusJsonResponse([
        'success' => false,
        'message' => 'Gagal menginisialisasi cURL.',
    ], 500);
}

curl_setopt_array($ch, [
    CURLOPT_URL            => $apiUrl,
    CURLOPT_POST           => true,
    CURLOPT_POSTFIELDS     => $jsonPayload,
    CURLOPT_RETURNTRANSFER => true,

    CURLOPT_CONNECTTIMEOUT => 10,
    CURLOPT_TIMEOUT        => 45,

    CURLOPT_SSL_VERIFYPEER => true,
    CURLOPT_SSL_VERIFYHOST => 2,

    /*
     * Menggunakan IPv4 agar IP outbound konsisten
     * jika Nexus memakai sistem whitelist IP.
     */
    CURLOPT_IPRESOLVE      => CURL_IPRESOLVE_V4,
    CURLOPT_HTTP_VERSION   => CURL_HTTP_VERSION_1_1,

    CURLOPT_FOLLOWLOCATION => false,
    CURLOPT_MAXREDIRS      => 0,

    CURLOPT_ENCODING       => '',
    CURLOPT_USERAGENT      => 'Nexus-PHP-Provider-Sync/1.0',

    CURLOPT_HTTPHEADER => [
        'Accept: application/json',
        'Content-Type: application/json; charset=utf-8',
        'Content-Length: ' . strlen($jsonPayload),
        'Connection: close',
    ],
]);

$responseBody = curl_exec($ch);

$curlError = curl_error($ch);
$curlErrno = curl_errno($ch);
$curlInfo  = curl_getinfo($ch);

$httpCode = isset($curlInfo['http_code'])
    ? (int) $curlInfo['http_code']
    : 0;

$localIp = isset($curlInfo['local_ip'])
    ? (string) $curlInfo['local_ip']
    : '';

$remoteIp = isset($curlInfo['primary_ip'])
    ? (string) $curlInfo['primary_ip']
    : '';

$contentType = isset($curlInfo['content_type'])
    ? (string) $curlInfo['content_type']
    : '';

curl_close($ch);

/*
|--------------------------------------------------------------------------
| Error koneksi
|--------------------------------------------------------------------------
*/

if ($responseBody === false) {
    error_log(json_encode([
        'event'       => 'NEXUS_PROVIDER_CURL_FAILED',
        'method'      => 'provider_list',
        'agent_code'  => $agentCode,
        'curl_errno'  => $curlErrno,
        'curl_error'  => $curlError,
    ], JSON_UNESCAPED_UNICODE));

    nexusJsonResponse([
        'success'    => false,
        'message'    => 'Tidak dapat terhubung ke API Nexus.',
        'curl_errno' => $curlErrno,
        'curl_error' => $curlError,
    ], 502);
}

/*
|--------------------------------------------------------------------------
| Decode JSON
|--------------------------------------------------------------------------
*/

$response = json_decode($responseBody, true);

if (!is_array($response)) {
    $safeBody = trim(
        preg_replace(
            '/\s+/',
            ' ',
            strip_tags((string) $responseBody)
        )
    );

    error_log(json_encode([
        'event'        => 'NEXUS_PROVIDER_INVALID_JSON',
        'http_code'    => $httpCode,
        'content_type' => $contentType,
        'local_ip'     => $localIp,
        'remote_ip'    => $remoteIp,
        'body_preview' => substr($safeBody, 0, 1000),
    ], JSON_UNESCAPED_UNICODE));

    nexusJsonResponse([
        'success'   => false,
        'message'   => 'Respons Nexus bukan JSON yang valid.',
        'http_code' => $httpCode,
        'response'  => substr($safeBody, 0, 1000),
    ], 502);
}

/*
|--------------------------------------------------------------------------
| HTTP error
|--------------------------------------------------------------------------
*/

if ($httpCode < 200 || $httpCode >= 300) {
    $nexusMessage = isset($response['msg'])
        ? trim((string) $response['msg'])
        : 'Tidak ada pesan dari Nexus.';

    error_log(json_encode([
        'event'         => 'NEXUS_PROVIDER_HTTP_ERROR',
        'http_code'     => $httpCode,
        'method'        => 'provider_list',
        'agent_code'    => $agentCode,
        'local_ip'      => $localIp,
        'remote_ip'     => $remoteIp,
        'nexus_message' => substr($nexusMessage, 0, 500),
    ], JSON_UNESCAPED_UNICODE));

    nexusJsonResponse([
        'success'       => false,
        'http_code'     => $httpCode,
        'message'       => 'API Nexus menolak request.',
        'nexus_message' => $nexusMessage,
        'local_ip'      => $localIp,
    ], $httpCode === 403 ? 403 : 502);
}

/*
|--------------------------------------------------------------------------
| Validasi status Nexus
|--------------------------------------------------------------------------
*/

$nexusStatus = isset($response['status'])
    ? (int) $response['status']
    : 0;

$nexusMessage = isset($response['msg'])
    ? trim((string) $response['msg'])
    : 'Unknown Nexus error';

if ($nexusStatus !== 1) {
    error_log(json_encode([
        'event'         => 'NEXUS_PROVIDER_API_REJECTED',
        'method'        => 'provider_list',
        'agent_code'    => $agentCode,
        'nexus_status'  => $nexusStatus,
        'nexus_message' => substr($nexusMessage, 0, 500),
    ], JSON_UNESCAPED_UNICODE));

    nexusJsonResponse([
        'success'       => false,
        'status'        => $nexusStatus,
        'message'       => 'Nexus gagal memproses provider_list.',
        'nexus_message' => $nexusMessage,
    ], 502);
}

$providers = isset($response['providers'])
    ? $response['providers']
    : null;

if (!is_array($providers)) {
    nexusJsonResponse([
        'success' => false,
        'message' => 'Data providers tidak ditemukan pada respons Nexus.',
    ], 502);
}

/*
|--------------------------------------------------------------------------
| Lindungi database dari respons kosong tidak normal
|--------------------------------------------------------------------------
*/

if (count($providers) === 0) {
    nexusJsonResponse([
        'success' => false,
        'message' => 'Nexus mengembalikan provider kosong. Database tidak diubah.',
    ], 502);
}

/*
|--------------------------------------------------------------------------
| Query sinkronisasi
|--------------------------------------------------------------------------
|
| Field berikut tidak diperbarui saat sinkronisasi:
|
| provider_type
| provider_image
| is_active
| is_popular
| popular_order
|
| Dengan demikian, pengaturan admin tidak akan ter-reset.
*/

$sql = "
    INSERT INTO providers_nexus (
        provider_code,
        provider_name,
        provider_status,
        is_active,
        is_popular,
        popular_order,
        sync_token,
        last_synced_at
    ) VALUES (
        :provider_code,
        :provider_name,
        :provider_status,
        1,
        0,
        0,
        :sync_token,
        NOW()
    )
    ON DUPLICATE KEY UPDATE
        provider_name   = VALUES(provider_name),
        provider_status = VALUES(provider_status),
        sync_token      = VALUES(sync_token),
        last_synced_at  = NOW()
";

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

$syncToken = bin2hex(random_bytes(16));

$processed = 0;
$inserted  = 0;
$updated   = 0;
$unchanged = 0;
$skipped   = 0;
$disabled  = 0;
$errors    = [];

/*
|--------------------------------------------------------------------------
| Simpan provider
|--------------------------------------------------------------------------
*/

try {
    $pdo->beginTransaction();

    foreach ($providers as $index => $provider) {
        if (!is_array($provider)) {
            $skipped++;

            $errors[] =
                'Provider index ' . $index . ' bukan array.';

            continue;
        }

        $providerCode = strtoupper(
            trim(
                isset($provider['code'])
                    ? (string) $provider['code']
                    : ''
            )
        );

        $providerName = trim(
            isset($provider['name'])
                ? (string) $provider['name']
                : ''
        );

        $providerStatus = (
            isset($provider['status']) &&
            (int) $provider['status'] === 1
        ) ? 1 : 0;

        /*
         * Validasi data wajib.
         */
        if (
            $providerCode === '' ||
            $providerName === ''
        ) {
            $skipped++;

            $errors[] =
                'Provider tidak lengkap pada index ' . $index . '.';

            continue;
        }

        /*
         * Provider code hanya menerima karakter aman.
         */
        if (
            preg_match(
                '/^[A-Z0-9_-]{1,50}$/',
                $providerCode
            ) !== 1
        ) {
            $skipped++;

            $errors[] =
                'Provider code tidak valid: ' . $providerCode;

            continue;
        }

        if (mb_strlen($providerName, 'UTF-8') > 150) {
            $providerName = mb_substr(
                $providerName,
                0,
                150,
                'UTF-8'
            );
        }

        $stmt->execute([
            'provider_code'   => $providerCode,
            'provider_name'   => $providerName,
            'provider_status' => $providerStatus,
            'sync_token'      => $syncToken,
        ]);

        $affectedRows = $stmt->rowCount();

        if ($affectedRows === 1) {
            $inserted++;
        } elseif ($affectedRows === 2) {
            $updated++;
        } else {
            $unchanged++;
        }

        $processed++;
    }

    /*
    |--------------------------------------------------------------------------
    | Nonaktifkan status API untuk provider yang hilang
    |--------------------------------------------------------------------------
    |
    | Hanya provider_status yang diubah.
    | is_active milik admin tetap tidak disentuh.
    */

    $disableStatement = $pdo->prepare("
        UPDATE providers_nexus
        SET
            provider_status = 0,
            last_synced_at = NOW()
        WHERE
            sync_token IS NULL
            OR sync_token <> :sync_token
    ");

    $disableStatement->execute([
        'sync_token' => $syncToken,
    ]);

    $disabled = $disableStatement->rowCount();

    $pdo->commit();
} catch (Throwable $e) {
    if ($pdo->inTransaction()) {
        $pdo->rollBack();
    }

    error_log(json_encode([
        'event'    => 'NEXUS_PROVIDER_SYNC_FAILED',
        'message'  => $e->getMessage(),
        'file'     => $e->getFile(),
        'line'     => $e->getLine(),
        'admin_id' => isset($_SESSION['admin_id'])
            ? $_SESSION['admin_id']
            : null,
    ], JSON_UNESCAPED_UNICODE));

    nexusJsonResponse([
        'success' => false,
        'message' => 'Sinkronisasi provider Nexus gagal.',
        'detail'  => 'Periksa error log server.',
    ], 500);
}

/*
|--------------------------------------------------------------------------
| Rotasi CSRF token
|--------------------------------------------------------------------------
*/

$_SESSION['csrf_sync_provider_nexus'] = bin2hex(
    random_bytes(32)
);

/*
|--------------------------------------------------------------------------
| Respons sukses
|--------------------------------------------------------------------------
*/

nexusJsonResponse([
    'success' => true,
    'message' => 'Provider Nexus berhasil disinkronkan.',

    'summary' => [
        'total_api' => count($providers),
        'processed' => $processed,
        'inserted'  => $inserted,
        'updated'   => $updated,
        'unchanged' => $unchanged,
        'disabled'  => $disabled,
        'skipped'   => $skipped,
    ],

    'connection' => [
        'http_code' => $httpCode,
        'local_ip'  => $localIp,
        'remote_ip' => $remoteIp,
    ],

    'errors' => array_slice($errors, 0, 20),
]);