<?php

declare(strict_types=1);

namespace App\Http\Controllers\Web;

use App\Http\Controllers\Controller;
use App\Models\Artwork;
use App\Models\ContentType;
use App\Services\ArtworkSearchService;
use App\Services\EarlyGrowth\EarlyGrowth;
use App\Services\EarlyGrowth\GridFiller;
use App\Services\EarlyGrowth\SpotlightEngineInterface;
use App\Services\ThumbnailPresenter;
use Illuminate\Http\Request;
use Illuminate\Pagination\AbstractCursorPaginator;
use Illuminate\Pagination\AbstractPaginator;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Cache;

/**
 * ExploreController
 *
 * Powers the /explore/* structured catalog pages (§3.2 of routing spec).
 * Delegates to the same Meilisearch pipeline as BrowseGalleryController but
 * uses canonical /explore/* URLs with the ExploreLayout blade template.
 */
final class ExploreController extends Controller
{
    private const CONTENT_TYPE_SLUGS = ['artworks', 'wallpapers', 'skins', 'photography', 'other'];

    /** Meilisearch sort-field arrays per sort alias. */
    private const SORT_MAP = [
        'trending'   => ['trending_score_24h:desc', 'trending_score_7d:desc', 'favorites_count:desc', 'created_at:desc'],
        'fresh'      => ['trending_score_7d:desc', 'favorites_count:desc', 'created_at:desc'],
        'top-rated'  => ['awards_received_count:desc', 'favorites_count:desc'],
        'latest'     => ['created_at:desc'],
        // Legacy aliases kept for backward compatibility.
        'new-hot'    => ['trending_score_7d:desc', 'favorites_count:desc', 'created_at:desc'],
        'best'       => ['awards_received_count:desc', 'favorites_count:desc'],
    ];

    private const SORT_TTL = [
        'trending' => 300,
        'fresh'    => 120,
        'top-rated'=> 600,
        'latest'   => 120,
        'new-hot'  => 120,
        'best'     => 600,
    ];

    private const SORT_OPTIONS = [
        ['value' => 'trending',  'label' => '🔥 Trending'],
        ['value' => 'fresh',     'label' => '🚀 New & Hot'],
        ['value' => 'top-rated', 'label' => '⭐ Best'],
        ['value' => 'latest',    'label' => '🕐 Latest'],
    ];

    private const SORT_ALIASES = [
        'new-hot' => 'fresh',
        'best' => 'top-rated',
    ];

    public function __construct(
        private readonly ArtworkSearchService  $search,
        private readonly GridFiller            $gridFiller,
        private readonly SpotlightEngineInterface $spotlight,
    ) {}

    // ── /explore (hub) ──────────────────────────────────────────────────

    public function index(Request $request)
    {
        $sort    = $this->resolveSort($request);
        $perPage = $this->resolvePerPage($request);
        $page    = max(1, (int) $request->query('page', 1));
        $ttl     = self::SORT_TTL[$sort] ?? 300;

        $artworks = Cache::remember("explore.all.{$sort}.{$page}", $ttl, fn () =>
            Artwork::search('')->options([
                'filter' => 'is_public = true AND is_approved = true',
                'sort'   => self::SORT_MAP[$sort] ?? ['created_at:desc'],
            ])->paginate($perPage)
        );
        // EGS: fill grid to minimum when uploads are sparse
        $artworks = $this->gridFiller->fill($artworks, 0, $page);
        $artworks->getCollection()->transform(fn ($a) => $this->presentArtwork($a));

        // EGS §11: featured spotlight row on page 1 only
        $spotlightItems = ($page === 1 && EarlyGrowth::spotlightEnabled())
            ? $this->spotlight->getSpotlight(6)->map(fn ($a) => $this->presentArtwork($a))
            : collect();

        $mainCategories = $this->mainCategories();
        $seo = $this->paginationSeo($request, url('/explore'), $artworks);

        return view('gallery.index', [
            'gallery_type'          => 'browse',
            'mainCategories'        => $mainCategories,
            'subcategories'         => $mainCategories,
            'contentType'           => null,
            'category'              => null,
            'artworks'              => $artworks,
            'spotlight'             => $spotlightItems,
            'current_sort'          => $sort,
            'sort_options'          => self::SORT_OPTIONS,
            'hero_title'            => 'Explore',
            'hero_description'      => 'Browse the full Skinbase catalog — wallpapers, skins, photography and more.',
            'breadcrumbs'           => collect([(object) ['name' => 'Explore', 'url' => '/explore']]),
            'page_title'            => 'Explore Artworks - Skinbase',
            'page_meta_description' => 'Explore the full catalog of wallpapers, skins, photography and other artworks on Skinbase.',
            'page_meta_keywords'    => 'explore, wallpapers, skins, photography, artworks, skinbase',
            'page_canonical'        => $seo['canonical'],
            'page_rel_prev'         => $seo['prev'],
            'page_rel_next'         => $seo['next'],
            'page_robots'           => 'index,follow',
        ]);
    }

    // ── /explore/:type ──────────────────────────────────────────────────

    public function byType(Request $request, string $type)
    {
        $type = strtolower($type);
        if (!in_array($type, self::CONTENT_TYPE_SLUGS, true)) {
            abort(404);
        }

        // "artworks" is the umbrella — search all types
        $isAll = $type === 'artworks';

        // Canonical URLs for content types are /skins, /wallpapers, /photography, /other.
        if (! $isAll) {
            return redirect()->to($this->canonicalTypeUrl($request, $type), 301);
        }

        $sort    = $this->resolveSort($request);
        $perPage = $this->resolvePerPage($request);
        $page    = max(1, (int) $request->query('page', 1));
        $ttl     = self::SORT_TTL[$sort] ?? 300;

        $filter = 'is_public = true AND is_approved = true';
        if (!$isAll) {
            $filter .= ' AND content_type = "' . $type . '"';
        }

        $artworks = Cache::remember("explore.{$type}.{$sort}.{$page}", $ttl, fn () =>
            Artwork::search('')->options([
                'filter' => $filter,
                'sort'   => self::SORT_MAP[$sort] ?? ['created_at:desc'],
            ])->paginate($perPage)
        );
        // EGS: fill grid to minimum when uploads are sparse
        $artworks = $this->gridFiller->fill($artworks, 0, $page);
        $artworks->getCollection()->transform(fn ($a) => $this->presentArtwork($a));

        // EGS §11: featured spotlight row on page 1 only
        $spotlightItems = ($page === 1 && EarlyGrowth::spotlightEnabled())
            ? $this->spotlight->getSpotlight(6)->map(fn ($a) => $this->presentArtwork($a))
            : collect();

        $mainCategories = $this->mainCategories();
        $contentType = null;
        $subcategories = $mainCategories;
        if (! $isAll) {
            $contentType = ContentType::where('slug', $type)->first();
            $subcategories = $contentType
                ? $contentType->rootCategories()->orderBy('sort_order')->orderBy('name')->get()
                : collect();
        }

        if ($isAll) {
            $humanType = 'Artworks';
        } else {
            $humanType = $contentType?->name ?? ucfirst($type);
        }

        $baseUrl = url('/explore/' . $type);
        $seo = $this->paginationSeo($request, $baseUrl, $artworks);

        return view('gallery.index', [
            'gallery_type'          => $isAll ? 'browse' : 'content-type',
            'mainCategories'        => $mainCategories,
            'subcategories'         => $subcategories,
            'contentType'           => $contentType,
            'category'              => null,
            'artworks'              => $artworks,
            'spotlight'             => $spotlightItems,
            'current_sort'          => $sort,
            'sort_options'          => self::SORT_OPTIONS,
            'hero_title'            => $humanType,
            'hero_description'      => "Browse {$humanType} on Skinbase.",
            'breadcrumbs'           => collect([
                (object) ['name' => 'Explore', 'url' => '/explore'],
                (object) ['name' => $humanType, 'url' => "/explore/{$type}"],
            ]),
            'page_title'            => "{$humanType} - Explore - Skinbase",
            'page_meta_description' => "Discover the best {$humanType} artworks on Skinbase. Browse trending, new and top-rated.",
            'page_meta_keywords'    => strtolower($type) . ', explore, skinbase, artworks, wallpapers, skins, photography',
            'page_canonical'        => $seo['canonical'],
            'page_rel_prev'         => $seo['prev'],
            'page_rel_next'         => $seo['next'],
            'page_robots'           => 'index,follow',
        ]);
    }

    // ── /explore/:type/:mode ────────────────────────────────────────────

    public function byTypeMode(Request $request, string $type, string $mode)
    {
        $type = strtolower($type);
        if ($type !== 'artworks') {
            $query = $request->query();
            $query['sort'] = $this->normalizeSort((string) $mode);

            return redirect()->to($this->canonicalTypeUrl($request, $type, $query), 301);
        }

        // Rewrite the sort via the URL segment and delegate
        $request->query->set('sort', $mode);
        return $this->byType($request, $type);
    }

    // ── Helpers ──────────────────────────────────────────────────────────

    private function mainCategories(): Collection
    {
        $categories = ContentType::orderBy('id')
            ->get(['name', 'slug'])
            ->map(fn ($ct) => (object) [
                'name' => $ct->name,
                'slug' => $ct->slug,
                'url'  => '/' . strtolower($ct->slug),
            ]);

        return $categories->push((object) [
            'name' => 'Members',
            'slug' => 'members',
            'url'  => '/members',
        ]);
    }

    private function resolveSort(Request $request): string
    {
        $s = $this->normalizeSort((string) $request->query('sort', 'trending'));
        return array_key_exists($s, self::SORT_MAP) ? $s : 'trending';
    }

    private function normalizeSort(string $sort): string
    {
        $sort = strtolower($sort);
        return self::SORT_ALIASES[$sort] ?? $sort;
    }

    private function canonicalTypeUrl(Request $request, string $type, ?array $query = null): string
    {
        $query = $query ?? $request->query();

        if (isset($query['sort'])) {
            $query['sort'] = $this->normalizeSort((string) $query['sort']);
            if ($query['sort'] === 'trending') {
                unset($query['sort']);
            }
        }

        return url('/' . $type) . ($query ? ('?' . http_build_query($query)) : '');
    }

    private function resolvePerPage(Request $request): int
    {
        $v = (int) ($request->query('per_page') ?: $request->query('limit') ?: 24);
        return max(12, min($v, 80));
    }

    private function presentArtwork(Artwork $artwork): object
    {
        $primary   = $artwork->categories->sortBy('sort_order')->first();
        $present   = ThumbnailPresenter::present($artwork, 'md');
        $avatarUrl = \App\Support\AvatarUrl::forUser(
            (int) ($artwork->user_id ?? 0),
            $artwork->user?->profile?->avatar_hash ?? null,
            64
        );

        return (object) [
            'id'            => $artwork->id,
            'name'          => $artwork->title,
            'content_type_name' => $primary?->contentType?->name ?? '',
            'content_type_slug' => $primary?->contentType?->slug ?? '',
            'category_name' => $primary->name ?? '',
            'category_slug' => $primary->slug ?? '',
            'thumb_url'     => $present['url'],
            'thumb_srcset'  => $present['srcset'] ?? $present['url'],
            'uname'         => $artwork->user?->name ?? 'Skinbase',
            'username'      => $artwork->user?->username ?? '',
            'avatar_url'    => $avatarUrl,
            'published_at'  => $artwork->published_at,
            'slug'          => $artwork->slug ?? '',
            'width'         => $artwork->width  ?? null,
            'height'        => $artwork->height ?? null,
        ];
    }

    private function paginationSeo(Request $request, string $base, mixed $paginator): array
    {
        $q = $request->query();
        unset($q['grid']);
        if (($q['page'] ?? null) !== null && (int) $q['page'] <= 1) {
            unset($q['page']);
        }
        $canonical = $base . ($q ? '?' . http_build_query($q) : '');

        $prev = null;
        $next = null;
        if ($paginator instanceof AbstractPaginator || $paginator instanceof AbstractCursorPaginator) {
            $prev = $paginator->previousPageUrl();
            $next = $paginator->nextPageUrl();
        }

        return compact('canonical', 'prev', 'next');
    }
}
