<?php

declare(strict_types=1);

namespace PpPhp\Plugins;

use PpPhp\Core\ViewPlugin;
use PpPhp\Core\Storage\StorageRef;
use PpPhp\Core\Storage\StorageRegistry;

/**
 * Image view control.
 *
 * Renders one or many images stored as StorageRefs (or legacy paths/URLs) as a
 * gallery — masonry / grid / horizontal / vertical / single — with an optional
 * click-to-open lightbox (scoped to this field, the record, or the whole page),
 * captions, thumbnails, borders and responsive behaviour. Resolves each ref's
 * URL through the modular storage driver, so cloud-hosted images just work.
 */
class Image implements ViewPlugin
{
    public static function id(): string { return 'Image'; }
    public static function label(): string { return 'Image'; }
    public static function version(): string { return '1.0.0'; }
    public static function description(): string { return 'Renders a stored image with lightbox, thumbnails and layout options.'; }

    private static function flag(array $s, string $key, bool $default = false): bool
    {
        if (!array_key_exists($key, $s)) return $default;
        return in_array(strtolower((string) $s[$key]), ['1', 'yes', 'true', 'on'], true);
    }

    public static function render(mixed $value, array $settings): string
    {
        $refs = StorageRef::decode($value);
        if ($refs === []) return '';

        $isUrlField = self::flag($settings, 'isUrl');
        $w = max(0, (int) ($settings['width'] ?? 60));   // defaults match settingsSchema (60×40 thumbnail)
        $h = max(0, (int) ($settings['height'] ?? 40));
        $layout = strtolower((string) ($settings['layout'] ?? (count($refs) > 1 ? 'masonry' : 'single')));
        if (!in_array($layout, ['single', 'masonry', 'grid', 'horizontal', 'vertical'], true)) $layout = 'masonry';
        $max = max(0, (int) ($settings['maxImages'] ?? 0));
        $border = self::flag($settings, 'border', true);
        $mobileFull = self::flag($settings, 'mobileFull', true);
        $lightbox = self::flag($settings, 'lightbox', true);
        $scope = (string) ($settings['lightboxScope'] ?? 'field'); // field|record|page
        $captions = (string) ($settings['captions'] ?? 'filename');  // none|filename|field
        $captionField = (string) ($settings['captionField'] ?? '');

        if ($max > 0 && count($refs) > $max) $refs = array_slice($refs, 0, $max);

        // A per-render group id so lightbox next/prev stays within scope.
        $group = $scope === 'page' ? 'page'
            : ($scope === 'field' ? 'f' . substr(md5((string) ($settings['_field'] ?? microtime())), 0, 8)
            : 'r' . substr(md5(json_encode($refs)), 0, 8));

        // Fixed thumbnail: both width AND height set → each image is exactly w×h
        // (object-fit:cover), in EVERY layout — so the 60×40 default is a clean
        // thumbnail grid, not a 60px-wide masonry column.
        $fixedThumb = ($w > 0 && $h > 0);
        $cls = 'pp-gallery pp-g-' . ($fixedThumb ? 'thumbs' : $layout) . ($border ? ' pp-g-border' : '') . ($mobileFull ? ' pp-g-mobfull' : '');
        $sizeStyle = '';
        if ($fixedThumb) {
            $sizeStyle = 'width:' . $w . 'px;height:' . $h . 'px;object-fit:cover;';
        } elseif ($layout === 'single' || $layout === 'horizontal') {
            if ($w) $sizeStyle .= 'width:' . $w . 'px;';
            if ($h) $sizeStyle .= 'height:' . $h . 'px;';
        }
        // For the whole-gallery viewport (masonry/grid/vertical use width as a cap
        // only when NOT a fixed-thumbnail grid).
        $wrapStyle = '';
        if (!$fixedThumb && in_array($layout, ['masonry', 'grid', 'vertical'], true) && $w) $wrapStyle = 'max-width:' . $w . 'px;';

        $items = '';
        foreach ($refs as $ref) {
            $url = self::url($ref, $isUrlField, false);
            if ($url === '') continue;
            $full = self::url($ref, $isUrlField, false);
            $thumb = self::url($ref, $isUrlField, true) ?: $url;
            $cap = self::caption($ref, $captions, $captionField, $settings);
            $capEsc = htmlspecialchars($cap, ENT_QUOTES, 'UTF-8');
            // Prefer the author-supplied alt text (accessibility) over the filename.
            $alt = htmlspecialchars((string) ($ref['alt'] ?? $ref['name'] ?? ''), ENT_QUOTES, 'UTF-8');

            $imgStyle = $sizeStyle;
            $img = '<img src="' . htmlspecialchars($thumb, ENT_QUOTES, 'UTF-8') . '" alt="' . $alt . '" loading="lazy"'
                 . ($imgStyle ? ' style="' . $imgStyle . '"' : '') . '>';
            $capHtml = $cap !== '' ? '<span class="pp-g-cap">' . $capEsc . '</span>' : '';

            if ($lightbox) {
                $items .= '<a data-pp-lb data-pp-lb-group="' . $group . '" href="' . htmlspecialchars($full, ENT_QUOTES, 'UTF-8') . '"'
                        . ($cap !== '' ? ' data-pp-lb-cap="' . $capEsc . '"' : '') . '>' . $img . $capHtml . '</a>';
            } else {
                $items .= '<a href="' . htmlspecialchars($full, ENT_QUOTES, 'UTF-8') . '" target="_blank" rel="noopener">' . $img . $capHtml . '</a>';
            }
        }
        if ($items === '') return '';

        return '<div class="' . $cls . '"' . ($wrapStyle ? ' style="' . $wrapStyle . '"' : '') . '>' . $items . '</div>';
    }

    private static function url(array $ref, bool $isUrlField, bool $thumb): string
    {
        if ($isUrlField && ($ref['url'] ?? '') === '' && ($ref['key'] ?? '') !== '') {
            // "field contains image URL" mode: the stored value IS the URL.
            $k = (string) $ref['key'];
            if (preg_match('#^(https?:)?//|^data:#i', $k) || str_starts_with($k, '/')) return $k;
        }
        if (($ref['url'] ?? '') !== '') return (string) $ref['url'];
        if (class_exists(StorageRegistry::class)) {
            try { return StorageRegistry::forRef($ref)->url($ref, ['thumb' => $thumb, 'inline' => true]); }
            catch (\Throwable $e) {}
        }
        return (string) ($ref['key'] ?? '');
    }

    private static function caption(array $ref, string $mode, string $field, array $settings): string
    {
        if ($mode === 'none') return '';
        if ($mode === 'field' && $field !== '') {
            $row = (array) ($settings['_row'] ?? []);
            return (string) ($row[$field] ?? '');
        }
        return (string) ($ref['name'] ?? '');
    }

    public static function settingsSchema(): array
    {
        return [
            // ── Layout ────────────────────────────────────────────
            ['key' => 'layout', 'type' => 'select', 'label' => 'Layout', 'default' => 'masonry',
             'options' => [['single', 'Single'], ['masonry', 'Masonry'], ['grid', 'Grid'], ['horizontal', 'Row'], ['vertical', 'Stack']],
             'group' => 'Layout', 'hint' => 'How multiple images are arranged. Single shows just the first.'],
            ['key' => 'width', 'type' => 'number', 'label' => 'Width (px)', 'default' => 60, 'half' => true, 'group' => 'Layout', 'hint' => '0 = fluid. With height set, images are fixed thumbnails.'],
            ['key' => 'height', 'type' => 'number', 'label' => 'Height (px)', 'default' => 40, 'half' => true, 'group' => 'Layout',
             'hint' => 'With width set, each image is a fixed width×height thumbnail; 0 = auto.'],
            ['key' => 'maxImages', 'type' => 'number', 'label' => 'Max images', 'default' => 0, 'group' => 'Layout', 'hint' => '0 = show all.'],

            // ── Lightbox ──────────────────────────────────────────
            ['key' => 'lightbox', 'type' => 'bool', 'label' => 'Open lightbox on click', 'default' => 'yes', 'group' => 'Lightbox',
             'hint' => 'Click an image to view it full-screen with prev/next navigation.'],
            ['key' => 'lightboxScope', 'type' => 'select', 'label' => 'Gallery spans', 'default' => 'field',
             'options' => [['field', 'This field'], ['record', 'Whole record'], ['page', 'Whole page']],
             'group' => 'Lightbox', 'showIf' => ['key' => 'lightbox', 'in' => ['yes']],
             'hint' => 'Which images the prev/next arrows walk through.'],

            // ── Captions & style ──────────────────────────────────
            ['key' => 'captions', 'type' => 'select', 'label' => 'Captions', 'default' => 'filename',
             'options' => [['none', 'None'], ['filename', 'File name'], ['field', 'From a field']], 'group' => 'Captions & style'],
            ['key' => 'captionField', 'type' => 'text', 'label' => 'Caption field', 'default' => '', 'group' => 'Captions & style',
             'showIf' => ['key' => 'captions', 'in' => ['field']], 'hint' => 'Column whose value is shown as the caption.'],
            ['key' => 'border', 'type' => 'bool', 'label' => 'Border', 'default' => 'yes', 'half' => true, 'group' => 'Captions & style'],
            ['key' => 'mobileFull', 'type' => 'bool', 'label' => 'Full width on mobile', 'default' => 'yes', 'half' => true, 'group' => 'Captions & style'],
            ['key' => 'isUrl', 'type' => 'bool', 'label' => 'Field holds an image URL', 'default' => 'no', 'group' => 'Captions & style',
             'hint' => 'The column stores a direct image URL rather than an uploaded file.'],
        ];
    }

    public static function assets(): array
    {
        return [
            'js'  => ['assets/vendor/pp-lightbox/pp-lightbox.js'],
            'css' => ['assets/vendor/pp-lightbox/pp-lightbox.css'],
        ];
    }
}
