<?php
declare(strict_types=1);

require_once __DIR__ . '/db.php';

/**
 * Optimize uploaded image to WebP (falls back to original if GD/WebP unavailable).
 * Optionally crop to destination aspect ratio using crop box coords (normalized 0–1 or pixels).
 */
function media_ensure_upload_dirs(int $tenantId): string
{
    $dir = UPLOAD_DIR . DIRECTORY_SEPARATOR . 'tenant_' . $tenantId;
    if (!is_dir($dir)) {
        mkdir($dir, 0775, true);
    }
    return $dir;
}

function media_aspect_ratio(string $tag): ?float
{
    return match ($tag) {
        'staff', 'barber', 'profile' => 1.0,
        'hero', 'banner' => 16 / 9,
        'style', 'styles' => 4 / 5,
        'service' => 1.0,
        'product' => 1.0,
        'products' => 1.0,
        default => null,
    };
}

/**
 * @param array{x:float,y:float,width:float,height:float}|null $crop Crop in source pixel coords
 */
function media_process_upload(array $file, int $tenantId, string $tag, ?array $crop = null): array
{
    if (($file['error'] ?? UPLOAD_ERR_NO_FILE) !== UPLOAD_ERR_OK) {
        throw new RuntimeException('Upload failed (code ' . ($file['error'] ?? '?') . ').');
    }

    $tmp = $file['tmp_name'];
    $origName = basename((string) $file['name']);
    $mime = mime_content_type($tmp) ?: ($file['type'] ?? 'application/octet-stream');
    if (!str_starts_with($mime, 'image/') && !str_starts_with($mime, 'video/')) {
        throw new RuntimeException('Only image or video uploads are allowed.');
    }

    $dir = media_ensure_upload_dirs($tenantId);
    $base = bin2hex(random_bytes(8)) . '_' . time();
    $ext = strtolower(pathinfo($origName, PATHINFO_EXTENSION) ?: 'bin');
    $rawRel = 'tenant_' . $tenantId . '/' . $base . '.' . $ext;
    $rawAbs = UPLOAD_DIR . DIRECTORY_SEPARATOR . str_replace('/', DIRECTORY_SEPARATOR, $rawRel);

    if (!move_uploaded_file($tmp, $rawAbs)) {
        throw new RuntimeException('Could not store uploaded file.');
    }

    $optimizedRel = null;
    if (str_starts_with($mime, 'image/') && function_exists('imagecreatefromstring')) {
        $optimizedRel = media_optimize_image($rawAbs, $tenantId, $base, $tag, $crop);
    }

    $stmt = db()->prepare(
        'INSERT INTO media_assets (tenant_id, file_path, file_tag, optimized_path, original_name, mime_type)
         VALUES (?, ?, ?, ?, ?, ?)'
    );
    $stmt->execute([
        $tenantId,
        $rawRel,
        $tag,
        $optimizedRel,
        $origName,
        $mime,
    ]);

    $id = (int) db()->lastInsertId();
    return [
        'id' => $id,
        'file_path' => $rawRel,
        'optimized_path' => $optimizedRel,
        'url' => media_public_url($optimizedRel ?: $rawRel),
        'file_tag' => $tag,
    ];
}

function media_optimize_image(string $absPath, int $tenantId, string $base, string $tag, ?array $crop): ?string
{
    $bytes = file_get_contents($absPath);
    if ($bytes === false) {
        return null;
    }
    $src = @imagecreatefromstring($bytes);
    if ($src === false) {
        return null;
    }

    $sw = imagesx($src);
    $sh = imagesy($src);

    if ($crop && isset($crop['width'], $crop['height']) && $crop['width'] > 0 && $crop['height'] > 0) {
        $cx = (int) max(0, $crop['x'] ?? 0);
        $cy = (int) max(0, $crop['y'] ?? 0);
        $cw = (int) min($sw - $cx, $crop['width']);
        $ch = (int) min($sh - $cy, $crop['height']);
        $cropped = imagecrop($src, ['x' => $cx, 'y' => $cy, 'width' => $cw, 'height' => $ch]);
        if ($cropped !== false) {
            imagedestroy($src);
            $src = $cropped;
            $sw = imagesx($src);
            $sh = imagesy($src);
        }
    } else {
        $ratio = media_aspect_ratio($tag);
        if ($ratio !== null) {
            $src = media_center_crop_to_ratio($src, $ratio);
            $sw = imagesx($src);
            $sh = imagesy($src);
        }
    }

    // Cap long edge
    $maxEdge = 1920;
    if (max($sw, $sh) > $maxEdge) {
        if ($sw >= $sh) {
            $nw = $maxEdge;
            $nh = (int) round($sh * ($maxEdge / $sw));
        } else {
            $nh = $maxEdge;
            $nw = (int) round($sw * ($maxEdge / $sh));
        }
        $resized = imagecreatetruecolor($nw, $nh);
        imagealphablending($resized, false);
        imagesavealpha($resized, true);
        imagecopyresampled($resized, $src, 0, 0, 0, 0, $nw, $nh, $sw, $sh);
        imagedestroy($src);
        $src = $resized;
    }

    $rel = 'tenant_' . $tenantId . '/' . $base . '.webp';
    $abs = UPLOAD_DIR . DIRECTORY_SEPARATOR . str_replace('/', DIRECTORY_SEPARATOR, $rel);
    $ok = false;
    if (function_exists('imagewebp')) {
        $ok = imagewebp($src, $abs, 82);
    }
    imagedestroy($src);

    return $ok ? $rel : null;
}

/** @param \GdImage $src */
function media_center_crop_to_ratio($src, float $ratio)
{
    $sw = imagesx($src);
    $sh = imagesy($src);
    $current = $sw / max(1, $sh);

    if (abs($current - $ratio) < 0.01) {
        return $src;
    }

    if ($current > $ratio) {
        $nh = $sh;
        $nw = (int) round($sh * $ratio);
        $x = (int) round(($sw - $nw) / 2);
        $y = 0;
    } else {
        $nw = $sw;
        $nh = (int) round($sw / $ratio);
        $x = 0;
        $y = (int) round(($sh - $nh) / 2);
    }

    $cropped = imagecrop($src, ['x' => $x, 'y' => $y, 'width' => $nw, 'height' => $nh]);
    if ($cropped === false) {
        return $src;
    }
    imagedestroy($src);
    return $cropped;
}

function media_public_url(?string $relPath): string
{
    if (!$relPath) {
        return '';
    }
    if (preg_match('#^https?://#i', $relPath)) {
        return $relPath;
    }
    $path = str_replace('\\', '/', $relPath);
    $path = preg_replace('#^\./#', '', $path) ?? $path;
    // Allow storing either "tenant_1/x.webp" or "uploads/tenant_1/x.webp" or "./uploads/x.jpg"
    $path = preg_replace('#^/?uploads/#', '', $path) ?? $path;
    return rtrim(UPLOAD_URL, '/') . '/' . ltrim($path, '/');
}

/**
 * Normalize a user-selected upload path for DB storage (relative under /uploads).
 */
function media_normalize_stored_path(string $path): string
{
    $path = trim($path);
    if ($path === '' || preg_match('#^https?://#i', $path)) {
        return $path;
    }
    $path = str_replace('\\', '/', $path);
    $path = preg_replace('#^\./#', '', $path) ?? $path;
    $path = preg_replace('#^/?uploads/#', '', $path) ?? $path;
    return ltrim($path, '/');
}

/**
 * List selectable local upload files for a tenant (library + loose files under uploads/).
 * @return list<array{path:string,url:string,label:string,source:string}>
 */
function media_list_local_files(int $tenantId): array
{
    $out = [];
    $seen = [];

    $stmt = db()->prepare('SELECT * FROM media_assets WHERE tenant_id = ? ORDER BY id DESC');
    $stmt->execute([$tenantId]);
    foreach ($stmt->fetchAll() as $row) {
        $path = media_normalize_stored_path((string) ($row['optimized_path'] ?: $row['file_path']));
        if ($path === '' || isset($seen[$path])) {
            continue;
        }
        $seen[$path] = true;
        $out[] = [
            'path' => $path,
            'url' => media_public_url($path),
            'label' => (string) ($row['original_name'] ?: $path),
            'source' => 'library',
            'tag' => (string) ($row['file_tag'] ?? 'general'),
        ];
    }

    $roots = [
        UPLOAD_DIR . DIRECTORY_SEPARATOR . 'tenant_' . $tenantId,
        UPLOAD_DIR,
    ];
    foreach ($roots as $root) {
        if (!is_dir($root)) {
            continue;
        }
        $iterator = new RecursiveIteratorIterator(
            new RecursiveDirectoryIterator($root, FilesystemIterator::SKIP_DOTS)
        );
        foreach ($iterator as $file) {
            if (!$file->isFile()) {
                continue;
            }
            $ext = strtolower($file->getExtension());
            if (!in_array($ext, ['jpg', 'jpeg', 'png', 'webp', 'gif', 'avif', 'mp4', 'webm'], true)) {
                continue;
            }
            $abs = $file->getPathname();
            $rel = substr($abs, strlen(UPLOAD_DIR) + 1);
            $rel = media_normalize_stored_path(str_replace('\\', '/', $rel));
            if ($rel === '' || isset($seen[$rel])) {
                continue;
            }
            $seen[$rel] = true;
            $out[] = [
                'path' => $rel,
                'url' => media_public_url($rel),
                'label' => basename($rel),
                'source' => 'uploads',
                'tag' => 'file',
            ];
        }
    }

    return $out;
}

function media_delete(int $id, int $tenantId): bool
{
    $stmt = db()->prepare('SELECT * FROM media_assets WHERE id = ? AND tenant_id = ?');
    $stmt->execute([$id, $tenantId]);
    $row = $stmt->fetch();
    if (!$row) {
        return false;
    }
    foreach (['file_path', 'optimized_path'] as $col) {
        if (!empty($row[$col])) {
            $abs = UPLOAD_DIR . DIRECTORY_SEPARATOR . str_replace('/', DIRECTORY_SEPARATOR, $row[$col]);
            if (is_file($abs)) {
                @unlink($abs);
            }
        }
    }
    $del = db()->prepare('DELETE FROM media_assets WHERE id = ? AND tenant_id = ?');
    return $del->execute([$id, $tenantId]);
}

/**
 * Stock imagery search hooks (Pexels / Unsplash).
 * Returns normalized results; empty when API keys are not configured.
 */
function stock_search(string $query, string $provider = 'pexels', int $perPage = 12): array
{
    $query = trim($query);
    if ($query === '') {
        return ['provider' => $provider, 'results' => [], 'configured' => false];
    }

    if ($provider === 'unsplash') {
        if (UNSPLASH_ACCESS_KEY === '') {
            return ['provider' => 'unsplash', 'results' => [], 'configured' => false, 'hint' => 'Set UNSPLASH_ACCESS_KEY'];
        }
        $url = 'https://api.unsplash.com/search/photos?query=' . urlencode($query) . '&per_page=' . $perPage;
        $raw = stock_http_get($url, ['Authorization: Client-ID ' . UNSPLASH_ACCESS_KEY]);
        $data = json_decode($raw ?: '[]', true);
        $results = [];
        foreach (($data['results'] ?? []) as $item) {
            $results[] = [
                'id' => (string) ($item['id'] ?? ''),
                'thumb' => $item['urls']['small'] ?? '',
                'full' => $item['urls']['regular'] ?? '',
                'credit' => $item['user']['name'] ?? 'Unsplash',
            ];
        }
        return ['provider' => 'unsplash', 'results' => $results, 'configured' => true];
    }

    // Default: Pexels
    if (PEXELS_API_KEY === '') {
        return ['provider' => 'pexels', 'results' => [], 'configured' => false, 'hint' => 'Set PEXELS_API_KEY'];
    }
    $url = 'https://api.pexels.com/v1/search?query=' . urlencode($query) . '&per_page=' . $perPage;
    $raw = stock_http_get($url, ['Authorization: ' . PEXELS_API_KEY]);
    $data = json_decode($raw ?: '[]', true);
    $results = [];
    foreach (($data['photos'] ?? []) as $item) {
        $results[] = [
            'id' => (string) ($item['id'] ?? ''),
            'thumb' => $item['src']['medium'] ?? '',
            'full' => $item['src']['large2x'] ?? ($item['src']['large'] ?? ''),
            'credit' => $item['photographer'] ?? 'Pexels',
        ];
    }
    return ['provider' => 'pexels', 'results' => $results, 'configured' => true];
}

function stock_http_get(string $url, array $headers): ?string
{
    if (function_exists('curl_init')) {
        $ch = curl_init($url);
        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_HTTPHEADER => $headers,
            CURLOPT_TIMEOUT => 20,
        ]);
        $body = curl_exec($ch);
        curl_close($ch);
        return is_string($body) ? $body : null;
    }
    $ctx = stream_context_create(['http' => ['header' => implode("\r\n", $headers) . "\r\n"]]);
    $body = @file_get_contents($url, false, $ctx);
    return is_string($body) ? $body : null;
}

function stock_save_to_library(int $tenantId, string $imageUrl, string $tag = 'stock'): array
{
    $dir = media_ensure_upload_dirs($tenantId);
    $bytes = stock_http_get($imageUrl, []);
    if ($bytes === null || $bytes === '') {
        throw new RuntimeException('Could not download stock image.');
    }
    $base = 'stock_' . bin2hex(random_bytes(6)) . '_' . time();
    $rawRel = 'tenant_' . $tenantId . '/' . $base . '.jpg';
    $rawAbs = UPLOAD_DIR . DIRECTORY_SEPARATOR . str_replace('/', DIRECTORY_SEPARATOR, $rawRel);
    file_put_contents($rawAbs, $bytes);

    $optimized = media_optimize_image($rawAbs, $tenantId, $base, $tag, null);
    $stmt = db()->prepare(
        'INSERT INTO media_assets (tenant_id, file_path, file_tag, optimized_path, original_name, mime_type)
         VALUES (?, ?, ?, ?, ?, ?)'
    );
    $stmt->execute([$tenantId, $rawRel, $tag, $optimized, 'stock.jpg', 'image/jpeg']);
    $id = (int) db()->lastInsertId();
    return [
        'id' => $id,
        'url' => media_public_url($optimized ?: $rawRel),
        'file_path' => $rawRel,
        'optimized_path' => $optimized,
    ];
}
