<?php

declare(strict_types=1);

namespace App\Controllers\Admin;

use App\Core\Html;
use App\Core\Request;
use App\Core\Response;
use App\Core\Session;
use App\Core\View;
use App\Models\GalleryRepository;
use App\Support\SlugService;
use FilesystemIterator;
use RecursiveDirectoryIterator;
use RecursiveIteratorIterator;

final class GalleryController extends AdminController
{
    /** @param array<string,string> $params */
    public function index(Request $request, array $params): Response
    {
        if ($r = $this->guard()) {
            return $r;
        }

        return Response::html(View::render('admin/galleries/index', [
            'pageTitle' => 'Galeries',
            'galleries' => GalleryRepository::all(),
            'flash'     => Session::pull('flash'),
        ], 'layouts/admin'));
    }

    /** @param array<string,string> $params */
    public function create(Request $request, array $params): Response
    {
        if ($r = $this->guard()) {
            return $r;
        }

        return $this->form($this->blank(), [], 'Nouvelle galerie');
    }

    /** @param array<string,string> $params */
    public function store(Request $request, array $params): Response
    {
        if ($r = $this->guard()) {
            return $r;
        }
        if (!$this->csrfValid($request)) {
            return Response::redirect(base_url('admin/galleries'));
        }

        [$data, $errors] = $this->validate($request, null);
        if ($errors !== []) {
            return $this->form(array_merge($this->blank(), $data), $errors, 'Nouvelle galerie');
        }

        $data['sort_order'] = GalleryRepository::nextSortOrder();
        GalleryRepository::create($data);
        Session::set('flash', 'Galerie créée.');

        return Response::redirect(base_url('admin/galleries'));
    }

    /** @param array<string,string> $params */
    public function edit(Request $request, array $params): Response
    {
        if ($r = $this->guard()) {
            return $r;
        }
        $id = (int) ($params['id'] ?? 0);
        $gallery = GalleryRepository::find($id);
        if ($gallery === null) {
            return $this->missing();
        }
        $gallery['images'] = GalleryRepository::imagesFor($id);

        return $this->form($gallery, [], 'Modifier la galerie', Session::pull('flash'));
    }

    /** @param array<string,string> $params */
    public function update(Request $request, array $params): Response
    {
        if ($r = $this->guard()) {
            return $r;
        }
        $id = (int) ($params['id'] ?? 0);
        $gallery = GalleryRepository::find($id);
        if ($gallery === null) {
            return $this->missing();
        }
        if (!$this->csrfValid($request)) {
            return Response::redirect(base_url('admin/galleries/' . $id . '/edit'));
        }

        [$data, $errors] = $this->validate($request, $id);
        $data['slug']    = (string) $gallery['slug']; // slug figé (généré à la création, jamais modifié)

        // Couverture : doit appartenir à la galerie.
        $images  = GalleryRepository::imagesFor($id);
        $coverIn = $request->input('cover_image_id');
        $coverId = is_numeric($coverIn) ? (int) $coverIn : null;
        if ($coverId !== null && !in_array($coverId, array_map(static fn ($i) => (int) $i['id'], $images), true)) {
            $coverId = null;
        }
        $data['cover_image_id'] = $coverId;

        if ($errors !== []) {
            $data['id']     = $id;
            $data['images'] = $images;
            return $this->form($data, $errors, 'Modifier la galerie');
        }

        GalleryRepository::update($id, $data);
        Session::set('flash', 'Galerie enregistrée.');

        return Response::redirect(base_url('admin/galleries'));
    }

    /** @param array<string,string> $params */
    public function destroy(Request $request, array $params): Response
    {
        if ($r = $this->guard()) {
            return $r;
        }
        $id = (int) ($params['id'] ?? 0);
        if ($this->csrfValid($request) && GalleryRepository::find($id) !== null) {
            GalleryRepository::delete($id);
            $this->removeMedia($id);
            Session::set('flash', 'Galerie supprimée.');
        }

        return Response::redirect(base_url('admin/galleries'));
    }

    /** @param array<string,string> $params */
    public function move(Request $request, array $params): Response
    {
        if ($r = $this->guard()) {
            return $r;
        }
        $id  = (int) ($params['id'] ?? 0);
        $dir = (string) $request->input('dir', '');
        if ($this->csrfValid($request) && in_array($dir, ['up', 'down'], true)) {
            GalleryRepository::move($id, $dir);
        }

        return Response::redirect(base_url('admin/galleries'));
    }

    /** Réordonnancement par glisser-déposer (AJAX). @param array<string,string> $params */
    public function reorder(Request $request, array $params): Response
    {
        if ($r = $this->guard()) {
            return $r;
        }
        if (!$this->csrfValid($request)) {
            return Response::html('', 400);
        }

        $ids = $request->input('order');
        if (is_array($ids)) {
            $clean = array_values(array_filter(array_map('intval', $ids), static fn ($x) => $x > 0));
            if ($clean !== []) {
                GalleryRepository::reorder($clean);
            }
        }

        return Response::html('', 204);
    }

    /** Bascule du statut publié/brouillon (AJAX JSON). @param array<string,string> $params */
    public function status(Request $request, array $params): Response
    {
        if ($r = $this->guard()) {
            return $r;
        }
        if (!$this->csrfValid($request)) {
            return $this->json(['success' => false], 400);
        }
        $id = (int) ($params['id'] ?? 0);
        if (GalleryRepository::find($id) === null) {
            return $this->json(['success' => false], 404);
        }
        $status = $request->input('value') ? 'published' : 'draft';
        GalleryRepository::setStatus($id, $status);

        return $this->json(['success' => true, 'status' => $status]);
    }

    /** @param array<string,mixed> $data */
    private function json(array $data, int $code = 200): Response
    {
        return new Response((string) json_encode($data), $code, ['Content-Type' => 'application/json']);
    }

    // ---- Helpers ---------------------------------------------------------

    /**
     * @return array{0:array<string,mixed>,1:array<string,string>}
     */
    private function validate(Request $request, ?int $exceptId): array
    {
        $title  = trim((string) $request->input('title', ''));
        $slugIn = trim((string) $request->input('slug', ''));
        $status = $request->input('status_published') ? 'published' : 'draft';
        $intro  = Html::sanitize((string) $request->input('intro_html', ''));
        $seoT   = trim((string) $request->input('seo_title', ''));
        $seoD   = trim((string) $request->input('seo_description', ''));

        $errors = [];
        if ($title === '') {
            $errors['title'] = 'Le titre est obligatoire.';
        }

        $base = SlugService::make($slugIn !== '' ? $slugIn : $title);
        $slug = GalleryRepository::uniqueSlug($base, $exceptId);

        $data = [
            'title'           => $title,
            'slug'            => $slug,
            'intro_html'      => $intro,
            'status'          => $status,
            'cover_image_id'  => null,
            'seo_title'       => $seoT !== '' ? $seoT : null,
            'seo_description' => $seoD !== '' ? $seoD : null,
            'seo_noindex'     => $request->input('seo_noindex') ? 1 : 0,
        ];

        return [$data, $errors];
    }

    /** @return array<string,mixed> */
    private function blank(): array
    {
        return [
            'id' => null, 'title' => '', 'slug' => '', 'intro_html' => '',
            'status' => 'draft', 'cover_image_id' => null,
            'seo_title' => '', 'seo_description' => '', 'seo_noindex' => 0,
            'images' => [],
        ];
    }

    /**
     * @param array<string,mixed> $gallery
     * @param array<string,string> $errors
     */
    private function form(array $gallery, array $errors, string $heading, ?string $flash = null): Response
    {
        return Response::html(View::render('admin/galleries/form', [
            'pageTitle' => $heading,
            'heading'   => $heading,
            'g'         => $gallery,
            'errors'    => $errors,
            'flash'     => $flash,
        ], 'layouts/admin'));
    }

    private function missing(): Response
    {
        return Response::html(View::render('errors/404', ['pageTitle' => 'Introuvable']), 404);
    }

    private function removeMedia(int $id): void
    {
        $dirs = [
            BASE_PATH . '/media/galleries/' . $id,           // dérivés publics
            BASE_PATH . '/storage/uploads/galleries/' . $id, // originaux privés
        ];
        foreach ($dirs as $dir) {
            if (!is_dir($dir)) {
                continue;
            }
            $items = new RecursiveIteratorIterator(
                new RecursiveDirectoryIterator($dir, FilesystemIterator::SKIP_DOTS),
                RecursiveIteratorIterator::CHILD_FIRST
            );
            foreach ($items as $item) {
                $item->isDir() ? @rmdir($item->getPathname()) : @unlink($item->getPathname());
            }
            @rmdir($dir);
        }
    }
}
