<?php
declare(strict_types=1);

/**
 * Responsive image variant proxy.
 * Example:
 *   /api/image-variant.php?url=https%3A%2F%2Fi.ibb.co%2F...jpg&w=480&q=78
 */

function respondError(int $status, string $message): void {
    http_response_code($status);
    header('Content-Type: application/json; charset=utf-8');
    echo json_encode(['ok' => false, 'error' => $message], JSON_UNESCAPED_SLASHES);
    exit;
}

function serveBinary(string $body, string $contentType, string $etag): void {
    header('Content-Type: ' . $contentType);
    header('Cache-Control: public, max-age=2592000, stale-while-revalidate=86400');
    header('ETag: "' . $etag . '"');
    if (isset($_SERVER['HTTP_IF_NONE_MATCH']) && trim((string)$_SERVER['HTTP_IF_NONE_MATCH']) === '"' . $etag . '"') {
        http_response_code(304);
        exit;
    }
    echo $body;
    exit;
}

$url = isset($_GET['url']) ? trim((string)$_GET['url']) : '';
$targetWidth = isset($_GET['w']) ? (int)$_GET['w'] : 480;
$quality = isset($_GET['q']) ? (int)$_GET['q'] : 78;

if ($url === '') respondError(400, 'missing_url');
if (!preg_match('#^https://#i', $url)) respondError(400, 'https_required');

$allowedHostSuffixes = [
    'i.ibb.co',
    'ibb.co',
    'image.daiman.shop',
    'firebasestorage.googleapis.com',
    'storage.googleapis.com',
];

$host = strtolower((string)parse_url($url, PHP_URL_HOST));
if ($host === '') respondError(400, 'invalid_url');
$hostAllowed = false;
foreach ($allowedHostSuffixes as $suffix) {
    if ($host === $suffix || str_ends_with($host, '.' . $suffix)) {
        $hostAllowed = true;
        break;
    }
}
if (!$hostAllowed) respondError(403, 'host_not_allowed');

$targetWidth = max(64, min(2400, $targetWidth));
$quality = max(50, min(92, $quality));

$cacheDir = dirname(__DIR__) . DIRECTORY_SEPARATOR . 'data' . DIRECTORY_SEPARATOR . 'image-cache';
if (!is_dir($cacheDir)) {
    @mkdir($cacheDir, 0775, true);
}

$cacheKey = sha1($url . '|' . $targetWidth . '|' . $quality);
$metaPath = $cacheDir . DIRECTORY_SEPARATOR . $cacheKey . '.meta.json';

if (is_file($metaPath)) {
    $metaRaw = @file_get_contents($metaPath);
    $meta = is_string($metaRaw) ? json_decode($metaRaw, true) : null;
    if (is_array($meta) && !empty($meta['path']) && is_file($meta['path'])) {
        $body = @file_get_contents($meta['path']);
        if (is_string($body) && $body !== '') {
            serveBinary($body, (string)($meta['contentType'] ?? 'image/jpeg'), (string)($meta['etag'] ?? $cacheKey));
        }
    }
}

$ch = curl_init($url);
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_FOLLOWLOCATION => true,
    CURLOPT_MAXREDIRS => 4,
    CURLOPT_CONNECTTIMEOUT => 8,
    CURLOPT_TIMEOUT => 15,
    CURLOPT_USERAGENT => 'AhadMartImageVariant/1.0',
]);
$raw = curl_exec($ch);
$httpCode = (int)curl_getinfo($ch, CURLINFO_HTTP_CODE);
$contentType = (string)curl_getinfo($ch, CURLINFO_CONTENT_TYPE);
curl_close($ch);

if (!is_string($raw) || $raw === '') respondError(502, 'upstream_empty');
if ($httpCode < 200 || $httpCode >= 300) respondError(502, 'upstream_http_' . $httpCode);
if (stripos($contentType, 'image/') !== 0) respondError(415, 'upstream_not_image');

$imgInfo = @getimagesizefromstring($raw);
if (!$imgInfo || empty($imgInfo[0]) || empty($imgInfo[1])) {
    // If parser fails, serve passthrough as fallback.
    $etag = sha1($raw);
    $origPath = $cacheDir . DIRECTORY_SEPARATOR . $cacheKey . '.bin';
    @file_put_contents($origPath, $raw, LOCK_EX);
    @file_put_contents($metaPath, json_encode([
        'path' => $origPath,
        'contentType' => $contentType ?: 'image/jpeg',
        'etag' => $etag,
    ], JSON_UNESCAPED_SLASHES), LOCK_EX);
    serveBinary($raw, $contentType ?: 'image/jpeg', $etag);
}

$origW = (int)$imgInfo[0];
$origH = (int)$imgInfo[1];
$sourceMime = strtolower((string)($imgInfo['mime'] ?? $contentType));

// Passthrough for vector/animated formats.
if ($sourceMime === 'image/svg+xml' || $sourceMime === 'image/gif') {
    $etag = sha1($raw);
    $origPath = $cacheDir . DIRECTORY_SEPARATOR . $cacheKey . '.bin';
    @file_put_contents($origPath, $raw, LOCK_EX);
    @file_put_contents($metaPath, json_encode([
        'path' => $origPath,
        'contentType' => $sourceMime,
        'etag' => $etag,
    ], JSON_UNESCAPED_SLASHES), LOCK_EX);
    serveBinary($raw, $sourceMime, $etag);
}

$srcIm = @imagecreatefromstring($raw);
if (!$srcIm) {
    $etag = sha1($raw);
    $origPath = $cacheDir . DIRECTORY_SEPARATOR . $cacheKey . '.bin';
    @file_put_contents($origPath, $raw, LOCK_EX);
    @file_put_contents($metaPath, json_encode([
        'path' => $origPath,
        'contentType' => $sourceMime ?: 'image/jpeg',
        'etag' => $etag,
    ], JSON_UNESCAPED_SLASHES), LOCK_EX);
    serveBinary($raw, $sourceMime ?: 'image/jpeg', $etag);
}

$scale = min(1.0, $targetWidth / max(1, $origW));
$newW = max(1, (int)round($origW * $scale));
$newH = max(1, (int)round($origH * $scale));

$dstIm = imagecreatetruecolor($newW, $newH);
if ($sourceMime === 'image/png' || $sourceMime === 'image/webp') {
    imagealphablending($dstIm, false);
    imagesavealpha($dstIm, true);
    $transparent = imagecolorallocatealpha($dstIm, 0, 0, 0, 127);
    imagefilledrectangle($dstIm, 0, 0, $newW, $newH, $transparent);
}
imagecopyresampled($dstIm, $srcIm, 0, 0, 0, 0, $newW, $newH, $origW, $origH);
imagedestroy($srcIm);

$outType = 'image/jpeg';
$outExt = 'jpg';
$outPath = $cacheDir . DIRECTORY_SEPARATOR . $cacheKey . '.jpg';

if (function_exists('imagewebp')) {
    $outType = 'image/webp';
    $outExt = 'webp';
    $outPath = $cacheDir . DIRECTORY_SEPARATOR . $cacheKey . '.webp';
    imagewebp($dstIm, $outPath, $quality);
} elseif ($sourceMime === 'image/png') {
    $outType = 'image/png';
    $outExt = 'png';
    $outPath = $cacheDir . DIRECTORY_SEPARATOR . $cacheKey . '.png';
    $pngLevel = (int)round((100 - $quality) * 9 / 100);
    imagepng($dstIm, $outPath, max(0, min(9, $pngLevel)));
} else {
    imagejpeg($dstIm, $outPath, $quality);
}
imagedestroy($dstIm);

$outData = @file_get_contents($outPath);
if (!is_string($outData) || $outData === '') {
    respondError(500, 'variant_generation_failed');
}
$etag = sha1($outData);

@file_put_contents($metaPath, json_encode([
    'path' => $outPath,
    'contentType' => $outType,
    'etag' => $etag,
    'ext' => $outExt,
], JSON_UNESCAPED_SLASHES), LOCK_EX);

serveBinary($outData, $outType, $etag);
