<?php

declare(strict_types=1);



class AlbumAsset
{
    private const BASE_DIR = '/public/uploads/albums';

    private static function mediaBase(?int $storageId = null): string
    {
        return MediaStorage::mediaUrl($storageId);
    }

    public static function createFolder(): string
    {
        return bin2hex(random_bytes(8));
    }

    public static function dir(string $folder): string
    {
        return APP_ROOT . self::BASE_DIR . '/' . $folder;
    }

     
    public static function resolveUrl(string $folder, string $file, ?int $storageId = null): string
    {
        if ($file === '') return '';
        if (str_starts_with($file, 'http://') || str_starts_with($file, 'https://')) {
            return $file;  
        }
        $path = 'uploads/albums/' . $folder . '/' . $file;
        if ($storageId) {
            $storage = MediaStorage::get($storageId);
            if ($storage && $storage['secure_urls']) {
                return SecureMedia::signUrl($path, $storageId);
            }
        }
        return self::mediaBase($storageId) . '/' . $path;
    }

     
    public static function coverUrl(array $album): string
    {
        $folder = $album['album_folder'] ?? '';
        $sid = isset($album['storage_id']) ? (int) $album['storage_id'] : null;
        $file = (string) ($album['cover_file'] ?? '');
        if ($file === '') {
            $imgs = !empty($album['images']) ? (json_decode($album['images'], true) ?: []) : [];
            $file = $imgs[0]['f'] ?? '';
        }
         
        if ($file === '' || (!str_starts_with($file, 'http') && $folder === '')) return '';
        return self::resolveUrl($folder, $file, $sid);
    }

    

    public static function assignEntityCovers(array &$items, string $mapTable, string $fk, string $manual = 'thumbnail'): void
    {
        if (empty($items)) return;
        $ids = [];
        foreach ($items as $it) {
            if (empty($it[$manual]) && !empty($it['id'])) $ids[] = (int) $it['id'];
        }
        if (empty($ids)) return;
        $ids = array_values(array_unique($ids));
        $ph = implode(',', array_fill(0, count($ids), '?'));
        $order = self::albumsHaveRanking() ? 'a.ranking_score DESC, a.views DESC, a.id DESC' : 'a.views DESC, a.id DESC';
        $rows = Database::fetchAll(
            "SELECT t.eid, a2.cover_file, a2.album_folder, a2.storage_id, a2.images
             FROM (
                 SELECT m.{$fk} AS eid, m.album_id,
                        ROW_NUMBER() OVER (PARTITION BY m.{$fk} ORDER BY {$order}) rn
                 FROM {$mapTable} m JOIN albums a ON a.id = m.album_id
                 WHERE a.status = 'published' AND m.{$fk} IN ({$ph})
             ) t
             JOIN albums a2 ON a2.id = t.album_id
             WHERE t.rn = 1",
            $ids
        );
        $byId = [];
        foreach ($rows as $r) {
            $url = self::coverUrl($r);
            if ($url !== '') $byId[(int) $r['eid']] = $url;
        }
        foreach ($items as &$it) {
            $eid = (int) ($it['id'] ?? 0);
            if (empty($it[$manual]) && isset($byId[$eid])) {
                $it['_fallback_cover'] = $byId[$eid];
            }
        }
        unset($it);
    }

     
    private static function albumsHaveRanking(): bool
    {
        static $has = null;
        if ($has === null) {
            try { $has = (bool) Database::fetchOne("SHOW COLUMNS FROM albums LIKE 'ranking_score'"); }
            catch (\Throwable $e) { $has = false; }
        }
        return $has;
    }

     
    public static function imageUrls(array $album): array
    {
        $folder = $album['album_folder'] ?? '';
        $sid = isset($album['storage_id']) ? (int) $album['storage_id'] : null;
        $imgs = !empty($album['images']) ? (json_decode($album['images'], true) ?: []) : [];
        $out = [];
        foreach ($imgs as $im) {
            $f = is_array($im) ? ($im['f'] ?? '') : (is_string($im) ? $im : '');
            if ($f === '') continue;
            $out[] = [
                'url' => self::resolveUrl($folder, $f, $sid),
                'f'   => $f,
                'w'   => is_array($im) ? ($im['w'] ?? null) : null,
                'h'   => is_array($im) ? ($im['h'] ?? null) : null,
            ];
        }
        return $out;
    }

     
    public static function saveUploadedImage(string $folder, string $tmpFile, string $origName, ?int $storageId = null): string
    {
        $ext = strtolower(pathinfo($origName, PATHINFO_EXTENSION));
        if (!in_array($ext, ['jpg', 'jpeg', 'png', 'webp', 'gif'], true)) {
            $ext = 'jpg';
        }
        $filename = bin2hex(random_bytes(6)) . '.' . $ext;
        return self::store($folder, $tmpFile, $filename, $storageId, true) ? $filename : '';
    }

     
    public static function saveRaw(string $folder, string $filename, string $data, ?int $storageId = null): bool
    {
        if (!self::validName($filename)) return false;
        $dir = self::dir($folder);
        if (!is_dir($dir)) mkdir($dir, 0755, true);
        $local = $dir . '/' . $filename;
        if (file_put_contents($local, $data) === false) return false;
        return self::pushRemote($local, $folder, $filename, $storageId);
    }

    private static function store(string $folder, string $srcPath, string $filename, ?int $storageId, bool $isUpload): bool
    {
        if (!self::validName($filename)) return false;
        $dir = self::dir($folder);
        if (!is_dir($dir)) mkdir($dir, 0755, true);
        $dest = $dir . '/' . $filename;
        $ok = $isUpload ? (move_uploaded_file($srcPath, $dest) || copy($srcPath, $dest)) : copy($srcPath, $dest);
        if (!$ok) return false;
        return self::pushRemote($dest, $folder, $filename, $storageId);
    }

     
    private static function pushRemote(string $local, string $folder, string $filename, ?int $storageId): bool
    {
        $sid = $storageId ?? MediaStorage::defaultId();
        if ($sid && MediaStorage::isRemote($sid)) {
            if (!MediaStorage::put($local, 'uploads/albums/' . $folder . '/' . $filename, $sid)) {
                error_log("AlbumAsset: failed to upload {$filename} to storage #{$sid}");
                return false;
            }
            @unlink($local);  
        }
        return true;
    }

    public static function deleteImage(string $folder, string $file, ?int $storageId = null): void
    {
        if ($folder === '' || !self::validName($file)) return;
        $sid = $storageId ?? MediaStorage::defaultId();
        if ($sid && MediaStorage::isRemote($sid)) {
            MediaStorage::deleteFile('uploads/albums/' . $folder . '/' . $file, $sid);
        }
        $local = self::dir($folder) . '/' . $file;
        if (is_file($local)) @unlink($local);
    }

    

    /** Remove only the local files of an album folder; remote storage is purged in batch. */
    public static function purgeLocalFolder(string $folder): void
    {
        if ($folder === '' || !preg_match('/^[a-f0-9]+$/i', $folder)) return;
        $dir = self::dir($folder);
        if (!is_dir($dir)) return;
        $realDir = realpath($dir);
        $baseDir = realpath(APP_ROOT . self::BASE_DIR);
        if ($realDir === false || $baseDir === false || !str_starts_with($realDir, $baseDir . '/')) return;
        foreach (glob($dir . '/*') ?: [] as $f) {
            if (is_file($f)) @unlink($f);
        }
        @rmdir($dir);
    }

    public static function deleteFolder(string $folder, ?int $storageId = null, array $files = []): void
    {
        if ($folder === '' || !preg_match('/^[a-f0-9]+$/i', $folder)) return;

        $sid = $storageId ?? MediaStorage::defaultId();
        if ($sid && MediaStorage::isRemote($sid)) {
            // One batched call rather than one request per image: a gallery can hold hundreds.
            $paths = [];
            foreach (array_unique($files) as $f) {
                if (self::validName($f)) $paths[] = 'uploads/albums/' . $folder . '/' . $f;
            }
            if ($paths) MediaStorage::deleteRemoteKeys($paths, $sid);
        }

        self::purgeLocalFolder($folder);
    }

    private static function validName(string $f): bool
    {
        return $f !== '' && preg_match('/^[a-zA-Z0-9_.-]+$/', $f) === 1 && !str_contains($f, '..');
    }
}
