<?php

use Swoole\Coroutine\Http\Server;
use Swoole\Coroutine\Http\Client;
use Swoole\Coroutine;

$port = 9001;
$apiEndpoint = 'https://oss.x-php.com/get/';
$cacheDir = __DIR__ . '/.cache';
$pathIndex = [];
$viewsInfo = [
    'request' => 0,
    'cacheHit' => 0,
    'apiCall' => 0,
    'cacheCall' => 0,
    'cacheReadError' => 0,
    'fetchApiError' => 0,
    'fetchApiWarning' => 0,
];

// Ensure cache directory exists
if (!is_dir($cacheDir)) {
    mkdir($cacheDir, 0777, true);
}

Swoole\Coroutine\run(function () use ($port, $apiEndpoint, $cacheDir, &$pathIndex, &$viewsInfo) {
    $server = new Server('0.0.0.0', $port, false);

    $server->set([
        'daemonize' => true,
    ]);

    $server->handle('/', function ($request, $response) use ($apiEndpoint, $cacheDir, &$pathIndex, &$viewsInfo) {
        $viewsInfo['request']++;

        $uri = $request->server['request_uri'];
        $parsedUrl = parse_url($uri);
        parse_str($parsedUrl['query'] ?? '', $query);

        $reqPath = explode('/', trim($parsedUrl['path'], '/'))[0] ?? '';
        $token = implode('/', array_slice(explode('/', trim($parsedUrl['path'], '/')), 1));

        if ($reqPath === 'endpoint') {
            return sendJsonResponse($response, [
                'code' => 200,
                'data' => [
                    'api' => $apiEndpoint,
                    'port' => $port,
                    'cacheDir' => $cacheDir,
                    'pathIndexCount' => count($pathIndex),
                    'viewsInfo' => $viewsInfo,
                ],
            ]);
        }

        if (empty($token) || $token === 'undefined') {
            $token = $reqPath;
            $reqPath = 'go';
        }

        if (!in_array($reqPath, ['avatar', 'go', 'bbs', 'www', 'url', 'thumb'])) {
            return sendErrorResponse($response, 404, 'Not Found');
        }

        if (!$token) {
            return sendErrorResponse($response, 400, 'Bad Request: Missing Token or path');
        }

        $uniqidhex = md5($reqPath . $token . ($query['sign'] ?? ''));

        if (isset($pathIndex[$uniqidhex]) && isCacheValid($cacheDir, $pathIndex[$uniqidhex])) {
            $viewsInfo['cacheHit']++;
            return serveFromCache($cacheDir, $pathIndex[$uniqidhex], $response);
        }

        $viewsInfo['apiCall']++;
        fetchApiData($apiEndpoint, $reqPath, $token, $query['sign'] ?? '', function ($apiData) use ($cacheDir, &$pathIndex, $uniqidhex, $response) {
            if ($apiData['code'] === 200 && isset($apiData['data']['url'])) {
                $pathIndex[$uniqidhex] = $uniqidhex;

                if (isCacheValid($cacheDir, $uniqidhex)) {
                    serveFromCache($cacheDir, $uniqidhex, $response);
                    return;
                }

                // 写入缓存
                file_put_contents("$cacheDir/$uniqidhex.meta", json_encode($apiData['data']));

                // 获取文件内容, curl
                $ch = curl_init();
                curl_setopt($ch, CURLOPT_URL, $apiData['data']['url']);
                curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
                curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 50);
                $fileContent = curl_exec($ch);
                curl_close($ch);
                file_put_contents("$cacheDir/$uniqidhex.content", $fileContent);

                serveFromCache($cacheDir, $uniqidhex, $response);
            } else {
                sendErrorResponse($response, 502, 'Bad Gateway: ' . json_encode($apiData));
            }
        });
    });


    $server->start();
});

function isCacheValid($cacheDir, $cacheFile) {
    return file_exists("$cacheDir/$cacheFile.meta") && file_exists("$cacheDir/$cacheFile.content");
}

function serveFromCache($cacheDir, $cacheFile, $response) {
    $cacheData = json_decode(file_get_contents("$cacheDir/$cacheFile.meta"), true);
    $response->header('Content-Type', $cacheData['headers']['Content-Type'] ?? 'application/octet-stream');
    $response->header('Cloud-Type', $cacheData['cloudtype']);
    $response->header('Cloud-Expiration', $cacheData['expiration']);
    $response->header('ETag', $cacheData['uniqid'] ?? '');
    $response->header('Cache-Control', 'public, max-age=31536000');
    $response->header('Expires', gmdate('D, d M Y H:i:s', time() + 31536000000) . ' GMT');
    $response->header('Accept-Ranges', 'bytes');
    $response->header('Connection', 'keep-alive');
    $response->header('Date', gmdate('D, d M Y H:i:s') . ' GMT');
    $response->header('Last-Modified', gmdate('D, d M Y H:i:s') . ' GMT');

    // 高效的读取文件
    $file = fopen("$cacheDir/$cacheFile.content", 'r');
    $response->end(fread($file, filesize("$cacheDir/$cacheFile.content")));
    fclose($file);
}

function fetchApiData($apiEndpoint, $reqPath, $token, $sign, $callback) {
    Coroutine::create(function () use ($apiEndpoint, $reqPath, $token, $sign, $callback) {
        $client = new Client(parse_url($apiEndpoint, PHP_URL_HOST), 443, true);
        $client->setHeaders([
            'Accept' => 'application/json',
            'User-Agent' => 'Swoole-Client',
            'token' => $token,
        ]);
        $client->get(parse_url($apiEndpoint, PHP_URL_PATH) . "?type=$reqPath&sign=$sign");
        $callback(json_decode($client->body, true));
        $client->close();
    });
}

function sendJsonResponse($response, $data) {
    $response->header('Content-Type', 'application/json');
    $response->end(json_encode($data));
}

function sendErrorResponse($response, $status, $message) {
    $response->status($status);
    $response->end($message);
}