<?php

declare(strict_types=1);

function handle_image_request(string $reference, ?int $width = null, ?int $height = null): void
{
    $reference = trim($reference);

    if (!validate_reference($reference)) {
        http_response_code(400);
        send_placeholder_image('INVALID-REF', $width, $height);
        return;
    }

    $width = $width !== null ? max(0, min(1600, $width)) : null;
    $height = $height !== null ? max(0, min(1600, $height)) : null;

    if ($width === 0) {
        $width = null;
    }
    if ($height === 0) {
        $height = null;
    }

    $imageSource = repo_find_article_image_source($reference);
    if ($imageSource === null) {
        send_placeholder_image($reference, $width, $height);
        return;
    }

    $sourceUrl = resolve_image_source_url($imageSource);
    if ($sourceUrl === null) {
        send_placeholder_image($reference, $width, $height);
        return;
    }

    $cached = image_cache_resolve($sourceUrl);
    if ($cached === null) {
        send_placeholder_image($reference, $width, $height);
        return;
    }

    $targetPath = $cached['path'];
    $contentType = $cached['content_type'];

    if ($width !== null || $height !== null) {
        $thumbnail = image_thumbnail_cached($targetPath, $contentType, $width, $height);
        if ($thumbnail !== null) {
            $targetPath = $thumbnail['path'];
            $contentType = $thumbnail['content_type'];
        }
    }

    send_image_file($targetPath, $contentType, (int) config('app.image_cache_ttl', 604800));
}

function resolve_image_source_url(array $imageSource): ?string
{
    $imageUrl = trim((string) ($imageSource['image_url'] ?? ''));
    if ($imageUrl !== '' && filter_var($imageUrl, FILTER_VALIDATE_URL)) {
        return $imageUrl;
    }

    $imageKey = trim((string) ($imageSource['image_key'] ?? ''));
    if ($imageKey === '') {
        return null;
    }

    if (filter_var($imageKey, FILTER_VALIDATE_URL)) {
        return $imageKey;
    }

    $base = (string) config('app.image_base_url', '');
    if ($base === '') {
        return null;
    }

    $cleanKey = preg_replace('/[^A-Za-z0-9_\/.\-]/', '', $imageKey);
    if ($cleanKey === '' || str_contains($cleanKey, '..')) {
        return null;
    }

    return rtrim($base, '/') . '/' . ltrim($cleanKey, '/');
}

function image_cache_resolve(string $url): ?array
{
    if (!filter_var($url, FILTER_VALIDATE_URL)) {
        return null;
    }

    $key = sha1($url);
    $dataPath = runtime_path('cache/images/' . $key . '.bin');
    $metaPath = runtime_path('cache/images/' . $key . '.json');
    $ttl = (int) config('app.image_cache_ttl', 604800);

    if (is_file($dataPath) && is_file($metaPath)) {
        $meta = json_decode((string) file_get_contents($metaPath), true);
        $fetchedAt = (int) ($meta['fetched_at'] ?? 0);
        $contentType = (string) ($meta['content_type'] ?? '');

        if ($fetchedAt > 0 && (time() - $fetchedAt) <= $ttl && $contentType !== '') {
            return [
                'path' => $dataPath,
                'content_type' => $contentType,
            ];
        }
    }

    $download = fetch_remote_image($url, (int) config('app.image_fetch_timeout', 4));
    if ($download !== null) {
        file_put_contents($dataPath, $download['body'], LOCK_EX);
        file_put_contents($metaPath, json_encode([
            'url' => $url,
            'content_type' => $download['content_type'],
            'fetched_at' => time(),
        ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), LOCK_EX);

        return [
            'path' => $dataPath,
            'content_type' => $download['content_type'],
        ];
    }

    if (is_file($dataPath)) {
        $fallbackType = detect_content_type($dataPath) ?? 'application/octet-stream';
        return [
            'path' => $dataPath,
            'content_type' => $fallbackType,
        ];
    }

    return null;
}

function fetch_remote_image(string $url, int $timeoutSeconds): ?array
{
    $timeoutSeconds = max(2, $timeoutSeconds);
    $body = null;
    $contentType = '';

    if (function_exists('curl_init')) {
        $ch = curl_init($url);
        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_FOLLOWLOCATION => true,
            CURLOPT_MAXREDIRS => 3,
            CURLOPT_CONNECTTIMEOUT => $timeoutSeconds,
            CURLOPT_TIMEOUT => $timeoutSeconds + 2,
            CURLOPT_USERAGENT => 'CampartsImageProxy/1.0',
            CURLOPT_SSL_VERIFYPEER => true,
        ]);

        $response = curl_exec($ch);
        if ($response === false) {
            curl_close($ch);
            return null;
        }

        $httpCode = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $contentType = (string) curl_getinfo($ch, CURLINFO_CONTENT_TYPE);
        curl_close($ch);

        if ($httpCode < 200 || $httpCode >= 300) {
            return null;
        }

        $body = $response;
    } else {
        $context = stream_context_create([
            'http' => [
                'method' => 'GET',
                'timeout' => $timeoutSeconds,
                'follow_location' => 1,
                'max_redirects' => 3,
                'header' => "User-Agent: CampartsImageProxy/1.0\r\n",
            ],
        ]);

        $result = @file_get_contents($url, false, $context);
        if ($result === false) {
            return null;
        }

        $body = $result;
        $headers = $http_response_header ?? [];
        foreach ($headers as $headerLine) {
            if (stripos($headerLine, 'Content-Type:') === 0) {
                $contentType = trim(substr($headerLine, strlen('Content-Type:')));
                break;
            }
        }
    }

    if (!is_string($body) || $body === '') {
        return null;
    }

    if (strlen($body) > 12 * 1024 * 1024) {
        return null;
    }

    $contentType = strtolower(trim(explode(';', $contentType)[0] ?? ''));
    if ($contentType === '') {
        $temp = tempnam(sys_get_temp_dir(), 'img_');
        if ($temp !== false) {
            file_put_contents($temp, $body);
            $contentType = detect_content_type($temp) ?? '';
            @unlink($temp);
        }
    }

    if (!str_starts_with($contentType, 'image/')) {
        return null;
    }

    return [
        'body' => $body,
        'content_type' => $contentType,
    ];
}

function detect_content_type(string $path): ?string
{
    if (!is_file($path)) {
        return null;
    }

    if (function_exists('finfo_open')) {
        $finfo = finfo_open(FILEINFO_MIME_TYPE);
        if ($finfo !== false) {
            $mime = finfo_file($finfo, $path);
            finfo_close($finfo);
            if (is_string($mime) && $mime !== '') {
                return $mime;
            }
        }
    }

    return null;
}

function image_thumbnail_cached(string $sourcePath, string $sourceType, ?int $width, ?int $height): ?array
{
    if (!is_file($sourcePath)) {
        return null;
    }

    if (!function_exists('imagecreatefromstring')) {
        return null;
    }

    $width = $width ?? 0;
    $height = $height ?? 0;

    if ($width <= 0 && $height <= 0) {
        return null;
    }

    $mtime = (string) filemtime($sourcePath);
    $quality = (int) config('app.image_thumb_quality', 82);
    $format = function_exists('imagewebp') ? 'webp' : 'jpg';
    $thumbKey = sha1($sourcePath . '|' . $mtime . '|' . $width . 'x' . $height . '|' . $format . '|' . $quality);
    $thumbPath = runtime_path('cache/thumbs/' . $thumbKey . '.' . $format);

    if (is_file($thumbPath)) {
        return [
            'path' => $thumbPath,
            'content_type' => $format === 'webp' ? 'image/webp' : 'image/jpeg',
        ];
    }

    $binary = file_get_contents($sourcePath);
    if ($binary === false || $binary === '') {
        return null;
    }

    $sourceImage = @imagecreatefromstring($binary);
    if ($sourceImage === false) {
        return null;
    }

    $srcW = imagesx($sourceImage);
    $srcH = imagesy($sourceImage);

    if ($srcW <= 0 || $srcH <= 0) {
        imagedestroy($sourceImage);
        return null;
    }

    if ($width <= 0) {
        $ratio = $height / $srcH;
    } elseif ($height <= 0) {
        $ratio = $width / $srcW;
    } else {
        $ratio = min($width / $srcW, $height / $srcH);
    }

    $ratio = min(1.0, max(0.01, $ratio));
    $targetW = max(1, (int) round($srcW * $ratio));
    $targetH = max(1, (int) round($srcH * $ratio));

    if ($targetW === $srcW && $targetH === $srcH) {
        imagedestroy($sourceImage);
        return [
            'path' => $sourcePath,
            'content_type' => $sourceType,
        ];
    }

    $targetImage = imagecreatetruecolor($targetW, $targetH);
    if ($targetImage === false) {
        imagedestroy($sourceImage);
        return null;
    }

    imagealphablending($targetImage, false);
    imagesavealpha($targetImage, true);
    $transparent = imagecolorallocatealpha($targetImage, 255, 255, 255, 127);
    imagefill($targetImage, 0, 0, $transparent);

    imagecopyresampled($targetImage, $sourceImage, 0, 0, 0, 0, $targetW, $targetH, $srcW, $srcH);

    $written = false;
    if ($format === 'webp' && function_exists('imagewebp')) {
        $written = imagewebp($targetImage, $thumbPath, $quality);
    } else {
        $whiteBg = imagecreatetruecolor($targetW, $targetH);
        if ($whiteBg !== false) {
            $white = imagecolorallocate($whiteBg, 255, 255, 255);
            imagefill($whiteBg, 0, 0, $white);
            imagecopy($whiteBg, $targetImage, 0, 0, 0, 0, $targetW, $targetH);
            imagedestroy($targetImage);
            $targetImage = $whiteBg;
        }

        $written = imagejpeg($targetImage, $thumbPath, $quality);
    }

    imagedestroy($sourceImage);
    imagedestroy($targetImage);

    if (!$written || !is_file($thumbPath)) {
        return null;
    }

    return [
        'path' => $thumbPath,
        'content_type' => $format === 'webp' ? 'image/webp' : 'image/jpeg',
    ];
}

function send_image_file(string $path, string $contentType, int $maxAge): void
{
    if (!is_file($path)) {
        send_placeholder_image('NO-FILE', null, null);
        return;
    }

    $maxAge = max(60, $maxAge);
    $etag = '"' . sha1($path . '|' . (string) filemtime($path) . '|' . (string) filesize($path)) . '"';
    $ifNoneMatch = trim((string) ($_SERVER['HTTP_IF_NONE_MATCH'] ?? ''));

    header('Cache-Control: public, max-age=' . $maxAge . ', stale-while-revalidate=86400');
    header('ETag: ' . $etag);
    header('Vary: Accept');

    if ($ifNoneMatch !== '' && $ifNoneMatch === $etag) {
        http_response_code(304);
        return;
    }

    header('Content-Type: ' . $contentType);
    header('Content-Length: ' . (string) filesize($path));
    header('Last-Modified: ' . gmdate('D, d M Y H:i:s', (int) filemtime($path)) . ' GMT');

    readfile($path);
}

function send_placeholder_image(string $reference, ?int $width, ?int $height): void
{
    $fallbackImagePath = base_path('img/imgnondispo.png');
    if (is_file($fallbackImagePath)) {
        $contentType = detect_content_type($fallbackImagePath) ?? 'image/png';
        $targetPath = $fallbackImagePath;

        if (($width !== null && $width > 0) || ($height !== null && $height > 0)) {
            $thumbnail = image_thumbnail_cached($fallbackImagePath, $contentType, $width, $height);
            if (is_array($thumbnail)) {
                $targetPath = (string) ($thumbnail['path'] ?? $fallbackImagePath);
                $contentType = (string) ($thumbnail['content_type'] ?? $contentType);
            }
        }

        send_image_file($targetPath, $contentType, 86400);
        return;
    }

    $w = $width !== null && $width > 0 ? min(1600, $width) : 600;
    $h = $height !== null && $height > 0 ? min(1600, $height) : 600;

    $safeRef = htmlspecialchars($reference, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');

    $svg = '<svg xmlns="http://www.w3.org/2000/svg" width="' . $w . '" height="' . $h . '" viewBox="0 0 ' . $w . ' ' . $h . '">'
        . '<defs><linearGradient id="g" x1="0" x2="1" y1="0" y2="1"><stop offset="0%" stop-color="#f3f4f6"/><stop offset="100%" stop-color="#e5e7eb"/></linearGradient></defs>'
        . '<rect width="100%" height="100%" fill="url(#g)"/>'
        . '<rect x="' . (int) ($w * 0.15) . '" y="' . (int) ($h * 0.18) . '" width="' . (int) ($w * 0.7) . '" height="' . (int) ($h * 0.52) . '" rx="16" fill="#d1d5db"/>'
        . '<text x="50%" y="' . (int) ($h * 0.82) . '" dominant-baseline="middle" text-anchor="middle" font-family="Arial, sans-serif" font-size="' . max(14, (int) ($w * 0.04)) . '" fill="#4b5563">Image indisponible</text>'
        . '<text x="50%" y="' . (int) ($h * 0.9) . '" dominant-baseline="middle" text-anchor="middle" font-family="Arial, sans-serif" font-size="' . max(10, (int) ($w * 0.03)) . '" fill="#6b7280">' . $safeRef . '</text>'
        . '</svg>';

    $etag = '"' . sha1($svg) . '"';
    $ifNoneMatch = trim((string) ($_SERVER['HTTP_IF_NONE_MATCH'] ?? ''));

    header('Cache-Control: public, max-age=86400');
    header('ETag: ' . $etag);

    if ($ifNoneMatch !== '' && $ifNoneMatch === $etag) {
        http_response_code(304);
        return;
    }

    header('Content-Type: image/svg+xml; charset=utf-8');
    echo $svg;
}
