<?php

declare(strict_types=1);

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

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') ||
    (($_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
|--------------------------------------------------------------------------
*/



/*
|--------------------------------------------------------------------------
| Koneksi database
|--------------------------------------------------------------------------
*/

require_once dirname(__DIR__) . '/config/database.php';

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

/*
|--------------------------------------------------------------------------
| Fungsi respons JSON
|--------------------------------------------------------------------------
*/

function jsonResponse(array $data, int $httpCode = 200): never
{
    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
|--------------------------------------------------------------------------
| Saat halaman dibuka dengan GET, tampilkan tombol sinkronisasi.
| Proses perubahan database hanya dijalankan melalui POST.
*/

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

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

    $action = 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');

    echo <<<HTML
<!DOCTYPE html>
<html lang="id">
<head>
    <meta charset="UTF-8">
    <meta
        name="viewport"
        content="width=device-width, initial-scale=1"
    >
    <title>Sinkronisasi Provider SGX</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: 480px;
            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: 24px;
        }

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

        button {
            width: 100%;
            border: 0;
            border-radius: 12px;
            padding: 15px 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 SGX</h1>

        <p>
            Tekan tombol berikut untuk mengambil provider terbaru
            dari API SGX dan menyimpannya ke database.
        </p>

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

            <button type="submit">
                Sinkronkan Provider Sekarang
            </button>
        </form>
    </div>
</body>
</html>
HTML;

    exit;
}

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

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

$submittedToken = (string) ($_POST['csrf_token'] ?? '');
$sessionToken   = (string) ($_SESSION['csrf_sync_provider_sgx'] ?? '');

if (
    $submittedToken === '' ||
    $sessionToken === '' ||
    !hash_equals($sessionToken, $submittedToken)
) {
    jsonResponse([
        'success' => false,
        'message' => 'CSRF token tidak valid atau sudah kedaluwarsa.',
    ], 419);
}

/*
|--------------------------------------------------------------------------
| Konfigurasi SGX
|--------------------------------------------------------------------------
*/

$apiUrl = trim(
    getenv('SGX_API_URL') ?: 'https://sgxcenter.xyz/api'
);

$agentCode = trim(
    getenv('SGX_AGENT_CODE') ?: 'rudal28'
);

$signature = trim(
    getenv('SGX_SIGNATURE')
        ?: '2036dc7347d1d3f1b799465a6a7b3d4e'
);

if (
    $apiUrl === '' ||
    filter_var($apiUrl, FILTER_VALIDATE_URL) === false
) {
    jsonResponse([
        'success' => false,
        'message' => 'URL API SGX tidak valid.',
    ], 500);
}

if (
    strtolower((string) parse_url($apiUrl, PHP_URL_SCHEME)) !== 'https'
) {
    jsonResponse([
        'success' => false,
        'message' => 'URL SGX wajib menggunakan HTTPS.',
    ], 500);
}

if ($agentCode === '') {
    jsonResponse([
        'success' => false,
        'message' => 'SGX agent code belum dikonfigurasi.',
    ], 500);
}

if ($signature === '') {
    jsonResponse([
        'success' => false,
        'message' => 'SGX signature belum dikonfigurasi.',
    ], 500);
}

/*
|--------------------------------------------------------------------------
| Buat payload SGX
|--------------------------------------------------------------------------
*/

$payload = [
    'command'    => 'provider_list',
    'agent_code' => $agentCode,
    'signature'  => $signature,
];

try {
    $jsonPayload = json_encode(
        $payload,
        JSON_UNESCAPED_SLASHES |
        JSON_UNESCAPED_UNICODE |
        JSON_THROW_ON_ERROR
    );
} catch (JsonException $e) {
    error_log('SGX JSON encode error: ' . $e->getMessage());

    jsonResponse([
        'success' => false,
        'message' => 'Gagal membuat payload JSON SGX.',
    ], 500);
}

/*
|--------------------------------------------------------------------------
| Request provider_list
|--------------------------------------------------------------------------
*/

$ch = curl_init();

if ($ch === false) {
    jsonResponse([
        '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        => 30,

    CURLOPT_SSL_VERIFYPEER => true,
    CURLOPT_SSL_VERIFYHOST => 2,

    /*
     * Menggunakan IPv4 supaya sesuai dengan IP whitelist:
     * 109.110.188.195
     */
    CURLOPT_IPRESOLVE      => CURL_IPRESOLVE_V4,
    CURLOPT_HTTP_VERSION   => CURL_HTTP_VERSION_1_1,

    CURLOPT_FOLLOWLOCATION => false,
    CURLOPT_MAXREDIRS      => 0,

    CURLOPT_ENCODING       => '',
    CURLOPT_USERAGENT      => 'SGX-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   = (int) ($curlInfo['http_code'] ?? 0);
$remoteIp   = (string) ($curlInfo['primary_ip'] ?? '');
$localIp    = (string) ($curlInfo['local_ip'] ?? '');
$contentType = (string) ($curlInfo['content_type'] ?? '');

curl_close($ch);

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

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

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

/*
|--------------------------------------------------------------------------
| Decode respons SGX
|--------------------------------------------------------------------------
*/

try {
    $response = json_decode(
        $responseBody,
        true,
        512,
        JSON_THROW_ON_ERROR
    );
} catch (JsonException $e) {
    $safeBody = trim(
        preg_replace(
            '/\s+/',
            ' ',
            strip_tags((string) $responseBody)
        ) ?? ''
    );

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

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

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

if ($httpCode < 200 || $httpCode >= 300) {
    $sgxMessage = trim(
        (string) ($response['message'] ?? 'Tidak ada pesan dari SGX.')
    );

    error_log(json_encode([
        'event'        => 'SGX_HTTP_ERROR',
        'http_code'    => $httpCode,
        'command'      => 'provider_list',
        'agent_code'   => $agentCode,
        'remote_ip'    => $remoteIp,
        'local_ip'     => $localIp,
        'sgx_message'  => substr($sgxMessage, 0, 500),
    ], JSON_UNESCAPED_UNICODE));

    jsonResponse([
        'success'     => false,
        'http_code'   => $httpCode,
        'message'     => 'API SGX menolak request.',
        'sgx_message' => $sgxMessage,
    ], $httpCode === 403 ? 403 : 502);
}

/*
|--------------------------------------------------------------------------
| Validasi status API
|--------------------------------------------------------------------------
*/

if (!is_array($response)) {
    jsonResponse([
        'success' => false,
        'message' => 'Format respons SGX tidak valid.',
    ], 502);
}

$apiStatus = (int) ($response['status'] ?? 0);
$apiMessage = trim(
    (string) ($response['message'] ?? 'Unknown SGX error')
);

if ($apiStatus !== 200) {
    error_log(json_encode([
        'event'       => 'SGX_API_REJECTED',
        'api_status'  => $apiStatus,
        'command'     => 'provider_list',
        'agent_code'  => $agentCode,
        'api_message' => substr($apiMessage, 0, 500),
    ], JSON_UNESCAPED_UNICODE));

    jsonResponse([
        'success'     => false,
        'status'      => $apiStatus,
        'message'     => 'SGX gagal memproses provider_list.',
        'sgx_message' => $apiMessage,
    ], 502);
}

$providers = $response['data']['providers'] ?? null;

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

/*
|--------------------------------------------------------------------------
| Query sinkronisasi
|--------------------------------------------------------------------------
| Penting:
|
| is_active, is_popular dan popular_order tidak diperbarui saat sync.
| Dengan begitu, pilihan admin tidak akan direset.
|--------------------------------------------------------------------------
*/

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

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

/*
|--------------------------------------------------------------------------
| Proses provider
|--------------------------------------------------------------------------
*/

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

try {
    $pdo->beginTransaction();

    foreach ($providers as $index => $provider) {
        if (!is_array($provider)) {
            $skipped++;
            $errors[] = 'Provider index ' . $index . ' bukan array.';
            continue;
        }

        $providerCode = strtoupper(
            trim((string) ($provider['provider_code'] ?? ''))
        );

        $providerName = trim(
            (string) ($provider['provider_name'] ?? '')
        );

        $providerType = strtoupper(
            trim((string) ($provider['provider_type'] ?? ''))
        );

        $providerImage = trim(
            (string) ($provider['provider_image'] ?? '')
        );

        $providerStatus = (
            (int) ($provider['provider_status'] ?? 0) === 1
        ) ? 1 : 0;

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

            $errors[] = sprintf(
                'Provider index %d tidak lengkap. Code: %s',
                $index,
                $providerCode !== '' ? $providerCode : '-'
            );

            continue;
        }

        /*
         * Batasi panjang sesuai tabel.
         */
        if (strlen($providerCode) > 50) {
            $skipped++;

            $errors[] = sprintf(
                'Provider code terlalu panjang pada index %d.',
                $index
            );

            continue;
        }

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

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

        /*
         * Provider image hanya menerima URL HTTPS.
         */
        if (
            $providerImage === '' ||
            filter_var(
                $providerImage,
                FILTER_VALIDATE_URL
            ) === false ||
            strtolower(
                (string) parse_url(
                    $providerImage,
                    PHP_URL_SCHEME
                )
            ) !== 'https'
        ) {
            $providerImage = null;
        }

        $stmt->execute([
            'provider_code'   => $providerCode,
            'provider_name'   => $providerName,
            'provider_type'   => $providerType,
            'provider_image'  => $providerImage,
            'provider_status' => $providerStatus,
        ]);

        /*
         * MySQL biasanya:
         * rowCount 1 = insert
         * rowCount 2 = update
         * rowCount 0 = data tidak berubah
         */
        $affectedRows = $stmt->rowCount();

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

        $processed++;
    }

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

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

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

/*
|--------------------------------------------------------------------------
| Rotasi CSRF token setelah berhasil
|--------------------------------------------------------------------------
*/

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

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

jsonResponse([
    'success' => true,
    'message' => 'Provider SGX berhasil disinkronkan.',

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

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

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