<?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\PageRepository;

final class PageController extends AdminController
{
    private const IMG_MAX_BYTES = 10_485_760; // 10 Mo
    private const IMG_MIMES = ['image/jpeg' => 'jpg', 'image/png' => 'png', 'image/gif' => 'gif', 'image/webp' => 'webp'];

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

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

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

        return $this->form($page, [], 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);
        $page = PageRepository::find($id);
        if ($page === null) {
            return $this->missing();
        }
        if (!$this->csrfValid($request)) {
            return Response::redirect(base_url('admin/pages/' . $id . '/edit'));
        }

        $title    = trim((string) $request->input('title', ''));
        $isSystem = in_array((string) $page['slug'], ['home', 'mentions-legales'], true);
        $status   = (string) $request->input('status', 'published');
        if ($isSystem || !in_array($status, ['draft', 'published'], true)) {
            $status = 'published';
        }
        $seoT = trim((string) $request->input('seo_title', ''));
        $seoD = trim((string) $request->input('seo_description', ''));

        $data = [
            'title'           => $title !== '' ? $title : (string) $page['title'],
            'body_html'       => Html::sanitize((string) $request->input('body_html', '')),
            'status'          => $status,
            'seo_title'       => $seoT !== '' ? $seoT : null,
            'seo_description' => $seoD !== '' ? $seoD : null,
            'seo_noindex'     => $request->input('seo_noindex') ? 1 : 0,
        ];

        if ($title === '') {
            return $this->form(array_merge($page, $data), ['title' => 'Le titre est obligatoire.']);
        }

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

        return Response::redirect(base_url('admin/pages/' . $id . '/edit'));
    }

    /** Téléversement d'une image de contenu pour l'éditeur (TinyMCE). Retourne {location} ou {error}. */
    public function uploadImage(Request $request, array $params): Response
    {
        if ($r = $this->guard()) {
            return $r;
        }
        if (!$this->csrfValid($request)) {
            return $this->json(['error' => 'Jeton invalide.'], 400);
        }
        $file = $_FILES['file'] ?? null;
        if (!is_array($file) || (int) ($file['error'] ?? UPLOAD_ERR_NO_FILE) !== UPLOAD_ERR_OK) {
            return $this->json(['error' => 'Aucun fichier reçu.'], 422);
        }
        if ((int) $file['size'] > self::IMG_MAX_BYTES) {
            return $this->json(['error' => 'Fichier trop volumineux (max 10 Mo).'], 422);
        }
        $mime = '';
        if (function_exists('finfo_open') && ($fi = finfo_open(FILEINFO_MIME_TYPE)) !== false) {
            $mime = (string) finfo_file($fi, (string) $file['tmp_name']);
            finfo_close($fi);
        }
        if (!isset(self::IMG_MIMES[$mime])) {
            return $this->json(['error' => 'Type non supporté (JPEG, PNG, GIF ou WebP).'], 422);
        }

        $dir = BASE_PATH . '/media/content';
        if (!is_dir($dir)) {
            @mkdir($dir, 0775, true);
        }
        $name = date('Ymd') . '-' . bin2hex(random_bytes(6)) . '.' . self::IMG_MIMES[$mime];
        if (!@move_uploaded_file((string) $file['tmp_name'], $dir . '/' . $name)) {
            return $this->json(['error' => 'Enregistrement impossible.'], 500);
        }

        return $this->json(['location' => base_url('media/content/' . $name)]);
    }

    /** @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']);
    }

    /**
     * @param array<string,mixed> $page
     * @param array<string,string> $errors
     */
    private function form(array $page, array $errors, ?string $flash = null): Response
    {
        return Response::html(View::render('admin/pages/form', [
            'pageTitle' => 'Page — ' . $page['title'],
            'p'         => $page,
            'errors'    => $errors,
            'flash'     => $flash,
        ], 'layouts/admin'));
    }

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