<?php

class Gallery {
    private array $config;

    public function __construct(array $config) {
        $this->config = $config;
    }

    public function getAlbums(): array {
        $dir = $this->config['photos_dir'];
        if (!is_dir($dir)) return [];

        $items = scandir($dir);
        sort($items);
        $albums = [];

        foreach ($items as $item) {
            if ($item[0] === '.' || !is_dir("$dir/$item")) continue;
            $album = $this->loadAlbum($item);
            if ($album && $album['count'] > 0) $albums[] = $album;
        }
        return $albums;
    }

    public function loadAlbum(string $slug): ?array {
        $path = $this->config['photos_dir'] . '/' . $slug;
        if (!is_dir($path)) return null;

        $meta = [
            'title'       => $this->humanize($slug),
            'description' => '',
            'date'        => null,
            'location'    => '',
        ];

        $metaFile = "$path/album.json";
        if (file_exists($metaFile)) {
            $decoded = json_decode(file_get_contents($metaFile), true);
            if (is_array($decoded)) $meta = array_merge($meta, $decoded);
        }

        $photos = [];
        $files = scandir($path);
        sort($files);
        foreach ($files as $item) {
            if (preg_match('/\.(jpe?g|png|gif|webp)$/i', $item)) {
                $photos[] = $this->loadPhoto($slug, $item);
            }
        }

        return [
            'slug'   => $slug,
            'meta'   => $meta,
            'photos' => $photos,
            'count'  => count($photos),
            'cover'  => $photos[0] ?? null,
        ];
    }

    public function loadPhoto(string $albumSlug, string $filename): array {
        $path = $this->config['photos_dir'] . '/' . $albumSlug . '/' . $filename;
        $info = [
            'file'   => $filename,
            'album'  => $albumSlug,
            'path'   => $path,
            'url'    => $this->config['photos_url'] . '/' . rawurlencode($albumSlug) . '/' . rawurlencode($filename),
            'size'   => @filesize($path) ?: 0,
            'width'  => 0,
            'height' => 0,
            'ratio'  => 1.0,
            'exif'   => null,
        ];

        $dim = @getimagesize($path);
        if ($dim) {
            $info['width']  = $dim[0];
            $info['height'] = $dim[1];
            $info['ratio']  = $dim[1] > 0 ? $dim[0] / $dim[1] : 1.0;
        }

        if (function_exists('exif_read_data') && preg_match('/\.jpe?g$/i', $filename)) {
            $exif = @exif_read_data($path);
            if ($exif) {
                $info['exif'] = [
                    'camera'   => trim(($exif['Make'] ?? '') . ' ' . ($exif['Model'] ?? '')),
                    'lens'     => $exif['UndefinedTag:0xA434'] ?? ($exif['LensModel'] ?? ''),
                    'iso'      => $exif['ISOSpeedRatings'] ?? null,
                    'shutter'  => $exif['ExposureTime'] ?? null,
                    'aperture' => isset($exif['FNumber']) ? $this->fracToFloat($exif['FNumber']) : null,
                    'focal'    => isset($exif['FocalLength']) ? $this->fracToFloat($exif['FocalLength']) : null,
                    'date'     => $exif['DateTimeOriginal'] ?? null,
                ];
            }
        }
        return $info;
    }

    public function thumbUrl(string $albumSlug, string $filename, string $size = 'md'): string {
        return 'thumb.php?a=' . rawurlencode($albumSlug)
             . '&p=' . rawurlencode($filename)
             . '&s=' . $size;
    }

    public function totalPhotoCount(): int {
        $n = 0;
        foreach ($this->getAlbums() as $a) $n += $a['count'];
        return $n;
    }

    private function humanize(string $slug): string {
        $slug = preg_replace('/^\d+[_-]/', '', $slug);
        $clean = str_replace(['-', '_'], ' ', $slug);
        return function_exists('mb_strtoupper') ? mb_strtoupper($clean, 'UTF-8') : strtoupper($clean);
    }

    private function fracToFloat($frac) {
        if (!is_string($frac)) return (float)$frac;
        if (strpos($frac, '/') === false) return (float)$frac;
        [$n, $d] = explode('/', $frac);
        return $d ? round((float)$n / (float)$d, 2) : 0;
    }

    public static function formatShutter($s): string {
        if (!$s) return '—';
        if (is_string($s) && strpos($s, '/') !== false) return $s . 's';
        $f = (float)$s;
        if ($f >= 1) return $f . 's';
        return '1/' . round(1 / $f) . 's';
    }

    public static function formatBytes(int $b): string {
        if ($b > 1048576) return round($b / 1048576, 1) . ' MB';
        if ($b > 1024) return round($b / 1024) . ' KB';
        return $b . ' B';
    }
}
