<?php

namespace App\Http\Controllers\Admin;

use App\Core\Controller;
use App\Core\Request;
use App\Core\Response;
use App\Models\GalleryAlbum;
use App\Models\GalleryImage;
use App\Models\Media;
use App\Services\UploadService;

class GalleryController extends Controller
{
    // =========================================================================
    // ALBUMS
    // =========================================================================

    // -------------------------------------------------------------------------
    // LIST
    // -------------------------------------------------------------------------

    public function index(Request $request, array $params = []): void
    {
        $albums = GalleryAlbum::allWithImageCount();

        $this->renderAdmin('gallery/index', [
            'pageTitle' => __('admin.gallery.title'),
            'albums'    => $albums,
            'auth'      => $this->auth(),
            'csrf'      => $this->csrf(),
        ]);
    }

    // -------------------------------------------------------------------------
    // CREATE ALBUM
    // -------------------------------------------------------------------------

    public function create(Request $request, array $params = []): void
    {
        $this->renderAdmin('gallery/form', [
            'pageTitle' => __('admin.gallery.create'),
            'album'     => null,
            'auth'      => $this->auth(),
            'csrf'      => $this->csrf(),
        ]);
    }

    public function store(Request $request, array $params = []): void
    {
        $this->validateCsrf();

        $title       = trim($request->input('title', ''));
        $slug        = trim($request->input('slug', ''));
        $description = trim($request->input('description', ''));
        $isVisible   = (int) $request->input('is_visible', 1);
        $sortOrder   = (int) $request->input('sort_order', GalleryAlbum::nextSortOrder());

        if (empty($title)) {
            set_flash('error', __('messages.field_required'));
            Response::redirect(admin_url('gallery/create'));
            return;
        }

        if (empty($slug)) {
            $slug = slugify($title);
        }

        // Deduplicate slug
        $existing = GalleryAlbum::findBySlug($slug);
        if ($existing) {
            $slug = $slug . '-' . bin2hex(random_bytes(4));
        }

        $coverImage = UploadService::upload($request->file('cover_image') ?? [], 'gallery', 'cover', true, true);

        GalleryAlbum::create([
            'title'       => $title,
            'slug'        => $slug,
            'description' => $description ?: null,
            'cover_image' => $coverImage,
            'sort_order'  => $sortOrder,
            'is_visible'  => $isVisible,
            'created_at'  => date('Y-m-d H:i:s'),
        ]);

        set_flash('success', __('messages.album_created', ['title' => $title]));
        Response::redirect(admin_url('gallery'));
    }

    // -------------------------------------------------------------------------
    // EDIT ALBUM
    // -------------------------------------------------------------------------

    public function edit(Request $request, array $params = []): void
    {
        $id    = (int) ($params['id'] ?? 0);
        $album = GalleryAlbum::find($id);

        if (!$album) {
            set_flash('error', __('messages.not_found', ['item' => 'Album']));
            Response::redirect(admin_url('gallery'));
            return;
        }

        $this->renderAdmin('gallery/form', [
            'pageTitle' => __('admin.gallery.edit'),
            'album'     => $album,
            'auth'      => $this->auth(),
            'csrf'      => $this->csrf(),
        ]);
    }

    public function update(Request $request, array $params = []): void
    {
        $this->validateCsrf();

        $id    = (int) ($params['id'] ?? 0);
        $album = GalleryAlbum::find($id);

        if (!$album) {
            set_flash('error', __('messages.not_found', ['item' => 'Album']));
            Response::redirect(admin_url('gallery'));
            return;
        }

        $title       = trim($request->input('title', ''));
        $slug        = trim($request->input('slug', ''));
        $description = trim($request->input('description', ''));
        $isVisible   = (int) $request->input('is_visible', 1);
        $sortOrder   = (int) $request->input('sort_order', (int) $album['sort_order']);

        if (empty($title)) {
            set_flash('error', __('messages.field_required'));
            Response::redirect(admin_url('gallery/edit/' . $id));
            return;
        }

        if (empty($slug)) {
            $slug = slugify($title);
        }

        // Check slug uniqueness against other albums
        $slugConflict = GalleryAlbum::findBySlug($slug);
        if ($slugConflict && (int) $slugConflict['id'] !== $id) {
            $slug = $slug . '-' . bin2hex(random_bytes(4));
        }

        // Cover image handling
        $coverImage = $album['cover_image'];

        if ($request->input('remove_cover') === '1') {
            UploadService::delete($album['cover_image'], true, true);
            $coverImage = null;
        }

        $newCover = UploadService::upload($request->file('cover_image') ?? [], 'gallery', 'cover', true, true);
        if ($newCover !== null) {
            if (!empty($coverImage)) {
                UploadService::delete($coverImage, true, true);
            }
            $coverImage = $newCover;
        }

        GalleryAlbum::updateById($id, [
            'title'       => $title,
            'slug'        => $slug,
            'description' => $description ?: null,
            'cover_image' => $coverImage,
            'sort_order'  => $sortOrder,
            'is_visible'  => $isVisible,
        ]);

        set_flash('success', __('messages.album_updated'));
        Response::redirect(admin_url('gallery'));
    }

    // -------------------------------------------------------------------------
    // DELETE ALBUM
    // -------------------------------------------------------------------------

    public function delete(Request $request, array $params = []): void
    {
        $this->validateCsrf();

        $id    = (int) ($params['id'] ?? 0);
        $album = GalleryAlbum::find($id);

        if (!$album) {
            set_flash('error', __('messages.not_found', ['item' => 'Album']));
            Response::redirect(admin_url('gallery'));
            return;
        }

        // Delete all image files for this album before the DB cascade removes rows
        $images = GalleryImage::byAlbum($id);
        foreach ($images as $image) {
            UploadService::delete($image['file_path'], true, true);
        }

        // Delete cover image (cover shares file_path with a gallery image, thumb may differ)
        UploadService::delete($album['cover_image'], true, true);

        // DB cascade (ON DELETE CASCADE) handles iw_gallery_images rows
        GalleryAlbum::deleteById($id);

        set_flash('success', __('messages.album_deleted'));
        Response::redirect(admin_url('gallery'));
    }

    public function bulk(Request $request, array $params = []): void
    {
        $this->validateCsrf();
        $ids    = array_map('intval', $request->input('ids', []));
        $action = $request->input('bulk_action', '');

        if (empty($ids) || $action !== 'delete') {
            Response::redirect(admin_url('gallery'));
            return;
        }

        $count = 0;
        foreach ($ids as $id) {
            $album = GalleryAlbum::find($id);
            if (!$album) continue;
            $images = GalleryImage::byAlbum($id);
            foreach ($images as $image) {
                UploadService::delete($image['file_path'], true, true);
            }
            UploadService::delete($album['cover_image'], true, true);
            GalleryAlbum::deleteById($id);
            $count++;
        }

        set_flash('success', __('messages.bulk_action_done', ['count' => $count]));
        Response::redirect(admin_url('gallery'));
    }

    // =========================================================================
    // IMAGES
    // =========================================================================

    // -------------------------------------------------------------------------
    // LIST / MANAGE IMAGES FOR ALBUM
    // -------------------------------------------------------------------------

    public function images(Request $request, array $params = []): void
    {
        $id    = (int) ($params['id'] ?? 0);
        $album = GalleryAlbum::find($id);

        if (!$album) {
            set_flash('error', __('messages.not_found', ['item' => 'Album']));
            Response::redirect(admin_url('gallery'));
            return;
        }

        $images = GalleryImage::byAlbumForAdmin($id);

        $this->renderAdmin('gallery/images', [
            'pageTitle' => __('admin.gallery_images.title', ['album' => $album['title']]),
            'album'     => $album,
            'images'    => $images,
            'auth'      => $this->auth(),
            'csrf'      => $this->csrf(),
        ]);
    }

    // -------------------------------------------------------------------------
    // UPLOAD IMAGE (Single + Multiple files, Phase 2.2)
    // -------------------------------------------------------------------------

    public function uploadImage(Request $request, array $params = []): void
    {
        $this->validateCsrf();

        $albumId = (int) ($params['id'] ?? 0);
        $album   = GalleryAlbum::find($albumId);

        if (!$album) {
            set_flash('error', __('messages.not_found', ['item' => 'Album']));
            Response::redirect(admin_url('gallery'));
            return;
        }

        $rawFile = $request->file('image') ?? [];

        // Normalise to an array of individual file entries (supports single + multi-file input)
        $files = self::normaliseFileInput($rawFile);

        if (empty($files)) {
            // No files provided – silent skip
            Response::redirect(admin_url('gallery/album/' . $albumId . '/images'));
            return;
        }

        // Cap at 10 files per batch to prevent memory exhaustion (ADR-065)
        $files        = array_slice($files, 0, 10);
        $successCount = 0;
        $errorCount   = 0;

        $title   = trim($request->input('title', ''));
        $altText = trim($request->input('alt_text', ''));

        foreach ($files as $file) {
            $filePath = UploadService::upload($file, 'gallery', 'img', true, true);

            if ($filePath === null) {
                $errorCount++;
                continue;
            }

            // Create gallery image record with file_path (legacy) and no media_id
            GalleryImage::create([
                'album_id'    => $albumId,
                'media_id'    => null,
                'file_path'   => $filePath,
                'title'       => $title ?: null,
                'alt_text'    => $altText ?: null,
                'sort_order'  => GalleryImage::nextSortOrder($albumId),
                'created_at'  => date('Y-m-d H:i:s'),
            ]);

            $successCount++;
        }

        // Build a meaningful flash message covering all outcomes
        $total = $successCount + $errorCount;
        if ($successCount > 0 && $errorCount === 0) {
            set_flash('success', __('messages.file_uploaded'));
        } elseif ($successCount > 0 && $errorCount > 0) {
            set_flash('warning', "{$successCount} file(s) uploaded; {$errorCount} could not be processed. Check file types and sizes.");
        } else {
            if ($total > 1) {
                set_flash('error', "All {$total} uploads failed. Check file types and sizes (JPG, PNG, GIF, WEBP · max 5 MB each).");
            }
        }

        Response::redirect(admin_url('gallery/album/' . $albumId . '/images'));
    }

    /**
     * Normalise a $_FILES entry to an array of individual file arrays.
     * Handles both single-file (string 'name') and multi-file (array 'name') inputs.
     * (Phase 2.2 – reused from MediaController)
     *
     * @param  array   $rawFile  Entry from $_FILES / $request->file()
     * @return array[]           Array of individual per-file arrays
     */
    private static function normaliseFileInput(array $rawFile): array
    {
        if (empty($rawFile)) {
            return [];
        }

        // Multi-file input: PHP delivers parallel arrays for each key
        if (is_array($rawFile['name'] ?? null)) {
            $files = [];
            foreach ($rawFile['name'] as $i => $name) {
                $error = $rawFile['error'][$i] ?? UPLOAD_ERR_NO_FILE;
                // Skip entries with no file selected
                if ($error === UPLOAD_ERR_NO_FILE || empty($name)) {
                    continue;
                }
                $files[] = [
                    'name'     => $name,
                    'tmp_name' => $rawFile['tmp_name'][$i] ?? '',
                    'error'    => $error,
                    'size'     => $rawFile['size'][$i]     ?? 0,
                    'type'     => $rawFile['type'][$i]     ?? '',
                ];
            }
            return $files;
        }

        // Single-file input: return as a one-element array
        return [$rawFile];
    }

    // -------------------------------------------------------------------------
    // ADD IMAGE FROM MEDIA MANAGER (Phase 2.2)
    // -------------------------------------------------------------------------

    /**
     * Add one or more images from the Media Manager to the gallery.
     * Accepts JSON POST with { mediaIds: [1, 2, 3] } and creates gallery_images
     * that reference these Media records via media_id FK.
     * (Phase 2.2 – avoids file duplication by referencing existing Media assets)
     */
    public function addFromMedia(Request $request, array $params = []): void
    {
        // JSON-Request: CSRF-Token muss aus dem Body gelesen werden,
        // da PHP JSON nicht in $_POST parst und validateCsrf() nur $_POST prüft.
        $body    = file_get_contents('php://input');
        $payload = json_decode($body, true);

        $csrfToken = $payload['_csrf_token'] ?? '';
        if (!$this->csrf()->validate($csrfToken)) {
            http_response_code(403);
            echo json_encode(['error' => 'Invalid CSRF token']);
            return;
        }

        $albumId = (int) ($params['id'] ?? 0);
        $album   = GalleryAlbum::find($albumId);

        if (!$album) {
            http_response_code(404);
            echo json_encode(['error' => 'Album not found']);
            return;
        }

        $mediaIds = $payload['mediaIds'] ?? [];

        if (!is_array($mediaIds) || empty($mediaIds)) {
            http_response_code(400);
            echo json_encode(['error' => 'Invalid mediaIds payload']);
            return;
        }

        // Filter and validate media IDs (max 10 to prevent abuse)
        $mediaIds = array_unique(array_map('intval', array_slice($mediaIds, 0, 10)));
        $successCount = 0;

        foreach ($mediaIds as $mediaId) {
            $media = Media::find($mediaId);

            // Validate: must exist, must be an image, must not already be in this album
            if (!$media || strpos($media['file_type'], 'image') !== 0) {
                continue;
            }

            $exists = $this->db()->fetchColumn(
                "SELECT id FROM iw_gallery_images WHERE album_id = :album_id AND media_id = :media_id",
                ['album_id' => $albumId, 'media_id' => $mediaId]
            );

            if ($exists) {
                continue; // Already in album, skip
            }

            // Create gallery image record linking to media (Phase 2.2)
            GalleryImage::create([
                'album_id'    => $albumId,
                'media_id'    => $mediaId,
                'file_path'   => $media['file_path'],
                'title'       => $media['title'] ?: null,
                'alt_text'    => $media['alt_text'] ?: null,
                'sort_order'  => GalleryImage::nextSortOrder($albumId),
                'created_at'  => date('Y-m-d H:i:s'),
            ]);

            $successCount++;
        }

        http_response_code(200);
        echo json_encode([
            'ok' => true,
            'added' => $successCount,
            'message' => $successCount > 0
                ? __('messages.images_added', [':count' => $successCount])
                : __('messages.error.no_images_added')
        ]);
    }

    // -------------------------------------------------------------------------
    // UPDATE IMAGE METADATA
    // -------------------------------------------------------------------------

    public function updateImage(Request $request, array $params = []): void
    {
        $this->validateCsrf();

        $imageId = (int) ($params['id'] ?? 0);
        $image   = GalleryImage::find($imageId);

        if (!$image) {
            set_flash('error', __('messages.not_found', ['item' => 'Image']));
            Response::redirect(admin_url('gallery'));
            return;
        }

        $title      = trim($request->input('title', ''));
        $altText    = trim($request->input('alt_text', ''));
        $sortOrder  = (int) $request->input('sort_order', (int) $image['sort_order']);

        GalleryImage::updateById($imageId, [
            'title'      => $title ?: null,
            'alt_text'   => $altText ?: null,
            'sort_order' => $sortOrder,
        ]);

        set_flash('success', __('messages.file_updated'));
        Response::redirect(admin_url('gallery/album/' . (int) $image['album_id'] . '/images'));
    }

    // -------------------------------------------------------------------------
    // DELETE IMAGE
    // -------------------------------------------------------------------------

    public function deleteImage(Request $request, array $params = []): void
    {
        $this->validateCsrf();

        $imageId = (int) ($params['id'] ?? 0);
        $image   = GalleryImage::find($imageId);

        if (!$image) {
            set_flash('error', __('messages.not_found', ['item' => 'Image']));
            Response::redirect(admin_url('gallery'));
            return;
        }

        $albumId = (int) $image['album_id'];

        // If this is the album cover, clear the cover reference
        $album = GalleryAlbum::find($albumId);
        if ($album && $album['cover_image'] === $image['file_path']) {
            GalleryAlbum::updateById($albumId, ['cover_image' => null]);
        }

        // Only delete physical file if no media_id (legacy direct upload)
        // If media_id is set, the file belongs to Media Manager and should not be deleted
        if (empty($image['media_id'])) {
            UploadService::delete($image['file_path'], true, true);
        }

        GalleryImage::deleteById($imageId);

        set_flash('success', __('messages.image_deleted'));
        Response::redirect(admin_url('gallery/album/' . $albumId . '/images'));
    }

    // -------------------------------------------------------------------------
    // SET ALBUM COVER FROM EXISTING IMAGE
    // -------------------------------------------------------------------------

    public function setCover(Request $request, array $params = []): void
    {
        $this->validateCsrf();

        $albumId = (int) ($params['id'] ?? 0);
        $imageId = (int) ($params['imageId'] ?? 0);

        $album = GalleryAlbum::find($albumId);
        $image = GalleryImage::find($imageId);

        if (!$album || !$image || (int) $image['album_id'] !== $albumId) {
            set_flash('error', __('messages.error.invalid_input'));
            Response::redirect(admin_url('gallery'));
            return;
        }

        GalleryAlbum::updateById($albumId, ['cover_image' => $image['file_path']]);

        set_flash('success', __('messages.updated'));
        Response::redirect(admin_url('gallery/album/' . $albumId . '/images'));
    }

    // -------------------------------------------------------------------------
    // REORDER IMAGES (JSON endpoint, called via fetch())
    // -------------------------------------------------------------------------

    public function reorderImages(Request $request, array $params = []): void
    {
        // JSON-Request: CSRF-Token muss aus dem Body gelesen werden,
        // da PHP JSON nicht in $_POST parst und validateCsrf() nur $_POST prüft.
        // (Gleiches Muster wie addFromMedia() – Phase 2.2)
        $body    = file_get_contents('php://input');
        $payload = json_decode($body, true);

        $csrfToken = $payload['_csrf_token'] ?? '';
        if (!$this->csrf()->validate($csrfToken)) {
            http_response_code(403);
            echo json_encode(['error' => 'Invalid CSRF token']);
            return;
        }

        $ids     = $payload['ids'] ?? [];

        if (!is_array($ids)) {
            http_response_code(400);
            echo json_encode(['error' => 'Invalid payload']);
            return;
        }

        foreach ($ids as $sortOrder => $imageId) {
            GalleryImage::updateById((int) $imageId, ['sort_order' => (int) $sortOrder]);
        }

        http_response_code(200);
        echo json_encode(['ok' => true]);
    }
}
