<?php

declare(strict_types=1);

namespace App\Application\LiveComponents\ImageGallery;

use App\Application\LiveComponents\Services\ImageGalleryDataProvider;
use App\Framework\LiveComponents\Attributes\LiveComponent;
use App\Framework\LiveComponents\Contracts\LiveComponentContract;
use App\Framework\LiveComponents\DataProviderResolver;
use App\Framework\LiveComponents\ValueObjects\ComponentId;
use App\Framework\LiveComponents\ValueObjects\ComponentRenderData;

/**
 * ImageGalleryComponent - Real-time image gallery with filtering, sorting, and actions
 *
 * Demonstrates:
 * - Server-side filtering and sorting
 * - Real-time image updates
 * - Image selection and bulk actions
 * - Pagination with load more
 * - Search functionality
 * - Delete and update alt text actions
 */
#[LiveComponent('image-gallery')]
final readonly class ImageGalleryComponent implements LiveComponentContract
{
    public function __construct(
        public ComponentId $id,
        public ImageGalleryState $state,
        private readonly DataProviderResolver $dataProviderResolver
    ) {}

    private function getDataProvider(): ImageGalleryDataProvider
    {
        $resolvedProvider = $this->dataProviderResolver->resolve(
            ImageGalleryDataProvider::class,
            $this->state->dataSource
        );

        if ($resolvedProvider === null) {
            throw new \RuntimeException(
                "No ImageGalleryDataProvider found for data source: {$this->state->dataSource}"
            );
        }

        return $resolvedProvider;
    }

    public function getRenderData(): ComponentRenderData
    {
        $dataProvider = $this->getDataProvider();

        // Always load images from data provider for rendering
        $imagesResult = $dataProvider->getImages(
            sortBy: $this->state->sortBy,
            sortDirection: $this->state->sortDirection,
            mimeType: $this->state->filterMimeType,
            searchQuery: $this->state->searchQuery,
            page: $this->state->currentPage,
            limit: $this->state->itemsPerPage
        );

        // Update state with loaded images
        $updatedState = $this->state->withImages(
            images: $imagesResult['images'],
            totalImages: $imagesResult['total'],
            hasMore: $imagesResult['has_more']
        );

        $paginationInfo = $updatedState->getPaginationInfo();

        return new ComponentRenderData(
            templatePath: 'livecomponent-image-gallery',
            data: [
                // Raw data
                'images' => $imagesResult['images'],
                'sort_by' => $this->state->sortBy,
                'sort_direction' => $this->state->sortDirection,
                'filter_mime_type' => $this->state->filterMimeType,
                'search_query' => $this->state->searchQuery,
                'current_page' => $this->state->currentPage,
                'items_per_page' => $this->state->itemsPerPage,
                'selected_images' => $this->state->selectedImages,

                // Display-specific properties
                'prepared_images' => $updatedState->getPreparedImages(),
                'has_images' => $updatedState->hasImages(),
                'is_empty' => ! $updatedState->hasImages(),
                'mime_type_options' => $updatedState->getMimeTypeOptions(),
                'sort_options' => $updatedState->getSortOptions(),
                'sort_direction_icon' => $this->state->sortDirection === 'asc' ? '↑' : '↓',

                // Pagination
                'current_page' => $paginationInfo['current_page'],
                'displayed_count' => $paginationInfo['displayed_count'],
                'total_count' => $paginationInfo['total_count'],
                'has_more' => $paginationInfo['has_more'],
                'showing_text' => $paginationInfo['showing_text'],

                // Selection
                'selection_count' => $updatedState->getSelectionCount(),
                'has_selection' => $updatedState->getSelectionCount() > 0,

                // Actions
                'can_delete' => true,
                'can_edit' => true,
                'can_select' => true,
            ]
        );
    }

    // Action methods

    /**
     * Change sort field and direction
     */
    public function sortBy(string $field, string $direction = 'asc'): ImageGalleryState
    {
        return $this->state->withSort($field, $direction);
    }

    /**
     * Toggle sort direction for current field
     */
    public function toggleSortDirection(): ImageGalleryState
    {
        $newDirection = $this->state->sortDirection === 'asc' ? 'desc' : 'asc';
        return $this->state->withSort($this->state->sortBy, $newDirection);
    }

    /**
     * Filter by mime type
     */
    public function filterByType(string $mimetype): ImageGalleryState
    {
        // Empty string means "all types"
        $filter = $mimetype === '' ? null : $mimetype;
        return $this->state->withMimeTypeFilter($filter);
    }

    /**
     * Search images
     */
    public function search(string $query): ImageGalleryState
    {
        return $this->state->withSearch($query);
    }

    /**
     * Load more images (pagination)
     */
    public function loadMore(): ImageGalleryState
    {
        $dataProvider = $this->getDataProvider();
        $newState = $this->state->withNextPage();

        // Load additional images
        $imagesResult = $dataProvider->getImages(
            sortBy: $newState->sortBy,
            sortDirection: $newState->sortDirection,
            mimeType: $newState->filterMimeType,
            searchQuery: $newState->searchQuery,
            page: $newState->currentPage,
            limit: $newState->itemsPerPage
        );

        // Append new images to existing ones
        $allImages = array_merge($this->state->images, $imagesResult['images']);

        return $newState->withImages(
            images: $allImages,
            totalImages: $imagesResult['total'],
            hasMore: $imagesResult['has_more']
        );
    }

    /**
     * Toggle image selection
     */
    public function toggleSelection(string $imageUlid): ImageGalleryState
    {
        return $this->state->withToggledSelection($imageUlid);
    }

    /**
     * Clear all selections
     */
    public function clearSelection(): ImageGalleryState
    {
        return $this->state->withClearedSelection();
    }

    /**
     * Delete an image
     */
    public function deleteImage(string $imageUlid): ImageGalleryState
    {
        $dataProvider = $this->getDataProvider();

        // Call data provider to delete image
        $dataProvider->deleteImage($imageUlid);

        // Remove image from state
        return $this->state->withoutImage($imageUlid);
    }

    /**
     * Update image alt text
     */
    public function updateAltText(string $imageUlid, string $altText): ImageGalleryState
    {
        $dataProvider = $this->getDataProvider();

        // Call data provider to update alt text
        $dataProvider->updateAltText($imageUlid, $altText);

        // Update image in state
        $updatedImages = array_map(function ($image) use ($imageUlid, $altText) {
            if ($image['ulid'] === $imageUlid) {
                $image['alt_text'] = $altText;
            }

            return $image;
        }, $this->state->images);

        return $this->state->withImages(
            images: $updatedImages,
            totalImages: $this->state->totalImages,
            hasMore: $this->state->hasMore
        );
    }

    /**
     * Bulk delete selected images
     */
    public function deleteSelected(): ImageGalleryState
    {
        $dataProvider = $this->getDataProvider();

        // Delete each selected image
        foreach ($this->state->selectedImages as $imageUlid) {
            $dataProvider->deleteImage($imageUlid);
        }

        // Remove all selected images from state
        $remainingImages = array_filter(
            $this->state->images,
            fn ($img) => ! in_array($img['ulid'], $this->state->selectedImages, true)
        );

        return new ImageGalleryState(
            images: array_values($remainingImages),
            sortBy: $this->state->sortBy,
            sortDirection: $this->state->sortDirection,
            filterMimeType: $this->state->filterMimeType,
            searchQuery: $this->state->searchQuery,
            currentPage: $this->state->currentPage,
            itemsPerPage: $this->state->itemsPerPage,
            selectedImages: [],
            totalImages: $this->state->totalImages - count($this->state->selectedImages),
            hasMore: $this->state->hasMore,
            dataSource: $this->state->dataSource
        );
    }
}
