<?php
declare(strict_types=1);

/**
 * sync_ai_mode.php
 *
 * FULL AUTO SYSTEM:
 * - auto run prediksi + result
 * - retry failed jobs
 * - optional lock file to prevent overlap
 * - optional purge once at end
 * - summary dashboard JSON
 * - detailed log
 *
 * Browser:
 *   /sync_ai_mode.php
 *   /sync_ai_mode.php?purge=1
 *
 * CLI:
 *   php sync_ai_mode.php
 *   php sync_ai_mode.php --purge=1
 */

error_reporting(E_ALL);
ini_set('display_errors', '1');
set_time_limit(1800);

$baseDir = __DIR__;
$logFile = $baseDir . '/sync_ai_mode.log';
$lockFile = $baseDir . '/sync_ai_mode.lock';

$jobs = [
    'prediksi' => $baseDir . '/sync_prediksi_pro.php',
    'result'   => $baseDir . '/sync_result_pro.php',
];

function isCli(): bool { return PHP_SAPI === 'cli'; }

function getOptValue(string $name, string $default = ''): string
{
    if (isCli()) {
        global $argv;
        foreach ($argv as $arg) {
            if (strpos($arg, "--{$name}=") === 0) {
                return substr($arg, strlen($name) + 3);
            }
        }
        return $default;
    }
    return isset($_GET[$name]) ? (string)$_GET[$name] : $default;
}

function appendLog(string $path, string $line): void
{
    @file_put_contents($path, '[' . date('Y-m-d H:i:s') . '] ' . $line . PHP_EOL, FILE_APPEND);
}

function acquireLock(string $lockFile): array
{
    $fp = fopen($lockFile, 'c+');
    if (!$fp) {
        throw new RuntimeException('Tidak bisa membuat lock file.');
    }

    if (!flock($fp, LOCK_EX | LOCK_NB)) {
        $content = stream_get_contents($fp, -1, 0);
        return ['ok' => false, 'handle' => $fp, 'content' => $content ?: 'busy'];
    }

    ftruncate($fp, 0);
    fwrite($fp, json_encode([
        'pid' => getmypid(),
        'started_at' => date('Y-m-d H:i:s'),
    ], JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE));
    fflush($fp);

    return ['ok' => true, 'handle' => $fp];
}

function releaseLock($fp, string $lockFile): void
{
    if (is_resource($fp)) {
        flock($fp, LOCK_UN);
        fclose($fp);
    }
    @unlink($lockFile);
}

function runPhpScript(string $file, array $params = []): array
{
    if (!file_exists($file)) {
        return [
            'success' => false,
            'error' => 'file not found',
            'file' => $file,
        ];
    }

    $cmd = 'php ' . escapeshellarg($file);
    foreach ($params as $key => $value) {
        $cmd .= ' --' . $key . '=' . escapeshellarg((string)$value);
    }

    $output = shell_exec($cmd . ' 2>&1');
    $decoded = json_decode((string)$output, true);

    return [
        'success' => true,
        'file' => $file,
        'command' => $cmd,
        'raw_output' => $output,
        'json' => is_array($decoded) ? $decoded : null,
    ];
}

function summarizeJob(string $label, array $run): array
{
    if (!$run['success']) {
        return [
            'label' => $label,
            'success' => false,
            'error' => $run['error'] ?? 'unknown',
        ];
    }

    $json = $run['json'];
    if (!is_array($json)) {
        return [
            'label' => $label,
            'success' => false,
            'error' => 'output is not valid JSON',
            'command' => $run['command'],
            'raw_output' => $run['raw_output'],
        ];
    }

    return [
        'label' => $label,
        'success' => (bool)($json['success'] ?? false),
        'updated_ids' => $json['updated_ids'] ?? [],
        'checked_no_change_ids' => $json['checked_no_change_ids'] ?? [],
        'failed_ids' => $json['failed_ids'] ?? [],
        'count_updated' => $json['count_updated'] ?? 0,
        'count_no_change' => $json['count_no_change'] ?? 0,
        'count_failed' => $json['count_failed'] ?? 0,
        'log_file' => $json['log_file'] ?? null,
        'command' => $run['command'],
    ];
}

function purgeLiteSpeed(): array
{
    $urls = [
        'https://info-angkajitu.com/?LSCWP_CTRL=flush_all',
        'https://info-angkajitu.com/?litespeed_purge=all',
    ];

    $results = [];
    foreach ($urls as $url) {
        $ch = curl_init($url);
        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_FOLLOWLOCATION => true,
            CURLOPT_CONNECTTIMEOUT => 10,
            CURLOPT_TIMEOUT => 20,
            CURLOPT_SSL_VERIFYPEER => false,
            CURLOPT_SSL_VERIFYHOST => 0,
            CURLOPT_USERAGENT => 'Mozilla/5.0 SyncAIMode/1.0',
        ]);
        $body = curl_exec($ch);
        $http = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $err = curl_error($ch);
        curl_close($ch);

        $results[] = [
            'url' => $url,
            'ok' => $body !== false && $http < 400,
            'http_code' => $http,
            'error' => $err,
        ];
    }
    return $results;
}

$lock = null;

try {
    $purge = getOptValue('purge', '1') === '1';
    $force = getOptValue('force', '1');
    $marker = getOptValue('marker', '1');

    $lock = acquireLock($lockFile);
    if (!$lock['ok']) {
        $busy = [
            'success' => false,
            'error' => 'sync masih berjalan',
            'lock_info' => $lock['content'],
            'finished_at' => date('Y-m-d H:i:s'),
        ];
        if (isCli()) {
            fwrite(STDERR, json_encode($busy, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) . PHP_EOL);
        } else {
            header('Content-Type: application/json; charset=utf-8');
            echo json_encode($busy, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
        }
        exit;
    }

    appendLog($logFile, 'START AI MODE');

    $params = [
        'force' => $force,
        'marker' => $marker,
        'purge' => '0',
    ];

    $jobResults = [];
    foreach ($jobs as $label => $file) {
        appendLog($logFile, 'RUN ' . $label);
        $run = runPhpScript($file, $params);
        $summary = summarizeJob($label, $run);

        // retry once if failed IDs exist or JSON invalid
        if (!$summary['success'] || (($summary['count_failed'] ?? 0) > 0)) {
            appendLog($logFile, 'RETRY ' . $label);
            $runRetry = runPhpScript($file, $params);
            $summaryRetry = summarizeJob($label, $runRetry);

            if (($summaryRetry['count_failed'] ?? 9999) <= ($summary['count_failed'] ?? 9999)) {
                $summary = $summaryRetry;
            }
        }

        $jobResults[] = $summary;
    }

    $allUpdated = [];
    $allNoChange = [];
    $allFailed = [];

    foreach ($jobResults as $row) {
        foreach (($row['updated_ids'] ?? []) as $id) {
            $allUpdated[] = $row['label'] . ':' . $id;
        }
        foreach (($row['checked_no_change_ids'] ?? []) as $id) {
            $allNoChange[] = $row['label'] . ':' . $id;
        }
        foreach (($row['failed_ids'] ?? []) as $id) {
            $allFailed[] = $row['label'] . ':' . $id;
        }
    }

    $purgeResults = [];
    if ($purge) {
        appendLog($logFile, 'PURGE CACHE');
        $purgeResults = purgeLiteSpeed();
    }

    $output = [
        'success' => true,
        'mode' => 'ai_mode',
        'jobs' => $jobResults,
        'updated_items' => $allUpdated,
        'no_change_items' => $allNoChange,
        'failed_items' => $allFailed,
        'count_updated_items' => count($allUpdated),
        'count_no_change_items' => count($allNoChange),
        'count_failed_items' => count($allFailed),
        'purge' => $purge,
        'purge_results' => $purgeResults,
        'log_file' => $logFile,
        'finished_at' => date('Y-m-d H:i:s'),
    ];

    appendLog($logFile, 'DONE AI MODE');

    if (isCli()) {
        echo json_encode($output, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) . PHP_EOL;
    } else {
        header('Content-Type: application/json; charset=utf-8');
        echo json_encode($output, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
    }

} catch (Throwable $e) {
    appendLog($logFile, 'ERROR ' . $e->getMessage());

    $output = [
        'success' => false,
        'error' => $e->getMessage(),
        'log_file' => $logFile,
        'finished_at' => date('Y-m-d H:i:s'),
    ];

    if (isCli()) {
        fwrite(STDERR, json_encode($output, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) . PHP_EOL);
    } else {
        header('Content-Type: application/json; charset=utf-8');
        echo json_encode($output, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
    }
} finally {
    if (is_array($lock) && ($lock['ok'] ?? false) && isset($lock['handle'])) {
        releaseLock($lock['handle'], $lockFile);
    }
}
?>