<?php

namespace App\Livewire;

use App\Models\Ride;
use App\Models\Park;
use App\Enums\RideCategory;
use App\Enums\RideStatus;
use Livewire\Component;
use Livewire\WithPagination;
use Livewire\Attributes\Url;
use Illuminate\Support\Facades\Cache;
use Illuminate\Database\Eloquent\Builder;

class ParkRidesListing extends Component
{
    use WithPagination;

    // Required park context
    public Park $park;

    // URL-bound search and filter properties
    #[Url(as: 'search')]
    public string $searchTerm = '';

    #[Url(as: 'category')]
    public ?string $selectedCategory = null;

    #[Url(as: 'status')]
    public ?string $selectedStatus = null;

    #[Url(as: 'sort')]
    public string $sortBy = 'name';

    #[Url(as: 'direction')]
    public string $sortDirection = 'asc';

    // UI state
    public bool $showFilters = false;
    public int $perPage = 12;

    // Cached data
    public array $categories = [];
    public array $statuses = [];
    public array $sortOptions = [];

    /**
     * Component initialization
     */
    public function mount(Park $park): void
    {
        $this->park = $park;
        $this->loadFilterOptions();
        $this->setupSortOptions();
    }

    /**
     * Load filter options specific to this park
     */
    protected function loadFilterOptions(): void
    {
        $cacheKey = "park_rides_filters_{$this->park->id}";
        
        $filterData = Cache::remember($cacheKey, 3600, function() {
            // Categories available in this park
            $categories = $this->park->rides()
                ->select('category')
                ->groupBy('category')
                ->get()
                ->map(function($ride) {
                    $category = RideCategory::from($ride->category);
                    return [
                        'value' => $category->value,
                        'label' => $category->name,
                        'count' => $this->park->rides()->where('category', $category->value)->count()
                    ];
                })
                ->toArray();

            // Statuses available in this park
            $statuses = $this->park->rides()
                ->select('status')
                ->groupBy('status')
                ->get()
                ->map(function($ride) {
                    $status = RideStatus::from($ride->status);
                    return [
                        'value' => $status->value,
                        'label' => $status->name,
                        'count' => $this->park->rides()->where('status', $status->value)->count()
                    ];
                })
                ->toArray();

            return compact('categories', 'statuses');
        });

        $this->categories = $filterData['categories'];
        $this->statuses = $filterData['statuses'];
    }

    /**
     * Setup sort options
     */
    protected function setupSortOptions(): void
    {
        $this->sortOptions = [
            'name' => 'Name',
            'opening_year' => 'Opening Year',
            'height_requirement' => 'Height Requirement',
            'created_at' => 'Date Added',
            'updated_at' => 'Last Updated'
        ];
    }

    /**
     * Update search term and reset pagination
     */
    public function updatedSearchTerm(): void
    {
        $this->resetPage();
    }

    /**
     * Update category filter
     */
    public function updatedSelectedCategory(): void
    {
        $this->resetPage();
    }

    /**
     * Update status filter
     */
    public function updatedSelectedStatus(): void
    {
        $this->resetPage();
    }

    /**
     * Update sort options
     */
    public function updatedSortBy(): void
    {
        $this->resetPage();
    }

    /**
     * Update sort direction
     */
    public function updatedSortDirection(): void
    {
        $this->resetPage();
    }

    /**
     * Set category filter
     */
    public function setCategory(?string $category): void
    {
        $this->selectedCategory = $category === $this->selectedCategory ? null : $category;
        $this->resetPage();
    }

    /**
     * Set status filter
     */
    public function setStatus(?string $status): void
    {
        $this->selectedStatus = $status === $this->selectedStatus ? null : $status;
        $this->resetPage();
    }

    /**
     * Set sort parameters
     */
    public function setSortBy(string $field): void
    {
        if ($this->sortBy === $field) {
            $this->sortDirection = $this->sortDirection === 'asc' ? 'desc' : 'asc';
        } else {
            $this->sortBy = $field;
            $this->sortDirection = 'asc';
        }
        $this->resetPage();
    }

    /**
     * Toggle filters visibility
     */
    public function toggleFilters(): void
    {
        $this->showFilters = !$this->showFilters;
    }

    /**
     * Clear all filters
     */
    public function clearFilters(): void
    {
        $this->searchTerm = '';
        $this->selectedCategory = null;
        $this->selectedStatus = null;
        $this->sortBy = 'name';
        $this->sortDirection = 'asc';
        $this->resetPage();
    }

    /**
     * Get filtered and sorted rides for this park
     */
    public function getRidesProperty()
    {
        $cacheKey = $this->getCacheKey();
        
        return Cache::remember($cacheKey, 300, function() {
            $query = $this->park->rides()
                ->with(['manufacturer', 'designer', 'photos'])
                ->when($this->searchTerm, function (Builder $query) {
                    $query->where(function (Builder $subQuery) {
                        $subQuery->where('name', 'ILIKE', "%{$this->searchTerm}%")
                                ->orWhere('description', 'ILIKE', "%{$this->searchTerm}%")
                                ->orWhereHas('manufacturer', function (Builder $manufacturerQuery) {
                                    $manufacturerQuery->where('name', 'ILIKE', "%{$this->searchTerm}%");
                                })
                                ->orWhereHas('designer', function (Builder $designerQuery) {
                                    $designerQuery->where('name', 'ILIKE', "%{$this->searchTerm}%");
                                });
                    });
                })
                ->when($this->selectedCategory, function (Builder $query) {
                    $query->where('category', $this->selectedCategory);
                })
                ->when($this->selectedStatus, function (Builder $query) {
                    $query->where('status', $this->selectedStatus);
                });

            // Apply sorting
            switch ($this->sortBy) {
                case 'name':
                    $query->orderBy('name', $this->sortDirection);
                    break;
                case 'opening_year':
                    $query->orderBy('opening_year', $this->sortDirection)
                          ->orderBy('name', 'asc');
                    break;
                case 'height_requirement':
                    $query->orderBy('height_requirement', $this->sortDirection)
                          ->orderBy('name', 'asc');
                    break;
                case 'created_at':
                    $query->orderBy('created_at', $this->sortDirection);
                    break;
                case 'updated_at':
                    $query->orderBy('updated_at', $this->sortDirection);
                    break;
                default:
                    $query->orderBy('name', 'asc');
            }

            return $query->paginate($this->perPage);
        });
    }

    /**
     * Get park statistics
     */
    public function getParkStatsProperty(): array
    {
        $cacheKey = "park_stats_{$this->park->id}";
        
        return Cache::remember($cacheKey, 3600, function() {
            $totalRides = $this->park->rides()->count();
            $operatingRides = $this->park->rides()->where('status', 'operating')->count();
            $categories = $this->park->rides()
                ->select('category')
                ->groupBy('category')
                ->get()
                ->count();
            
            $avgRating = $this->park->rides()
                ->whereHas('reviews')
                ->withAvg('reviews', 'rating')
                ->get()
                ->avg('reviews_avg_rating');

            return [
                'total_rides' => $totalRides,
                'operating_rides' => $operatingRides,
                'categories' => $categories,
                'avg_rating' => $avgRating ? round($avgRating, 1) : null
            ];
        });
    }

    /**
     * Get active filters count
     */
    public function getActiveFiltersCountProperty(): int
    {
        return collect([
            $this->searchTerm,
            $this->selectedCategory,
            $this->selectedStatus
        ])->filter()->count();
    }

    /**
     * Get cache key for current state
     */
    protected function getCacheKey(): string
    {
        return sprintf(
            'park_rides_%d_%s_%s_%s_%s_%s_%d_%d',
            $this->park->id,
            md5($this->searchTerm),
            $this->selectedCategory ?? 'all',
            $this->selectedStatus ?? 'all',
            $this->sortBy,
            $this->sortDirection,
            $this->perPage,
            $this->getPage()
        );
    }

    /**
     * Render the component
     */
    public function render()
    {
        return view('livewire.park-rides-listing', [
            'rides' => $this->rides,
            'parkStats' => $this->parkStats,
            'activeFiltersCount' => $this->activeFiltersCount
        ]);
    }

    /**
     * Reset pagination when filters change
     */
    public function resetPage($pageName = 'page'): void
    {
        $this->resetPage($pageName);
        
        // Clear cache when filters change
        $this->clearComponentCache();
    }

    /**
     * Clear component-specific cache
     */
    protected function clearComponentCache(): void
    {
        $patterns = [
            "park_rides_{$this->park->id}_*",
            "park_stats_{$this->park->id}",
            "park_rides_filters_{$this->park->id}"
        ];

        foreach ($patterns as $pattern) {
            Cache::forget($pattern);
        }
    }

    /**
     * Get pagination view
     */
    public function paginationView(): string
    {
        return 'livewire.pagination-links';
    }
}