<?php
namespace App\Http\Controllers;

use App\Http\Controllers\Web\BrowseGalleryController;
use App\Http\Controllers\Controller;
use App\Http\Requests\ArtworkIndexRequest;
use App\Models\Artwork;
use App\Models\Category;
use App\Services\ContentTypes\ContentTypeSlugResolver;
use Illuminate\Http\Request;
use Illuminate\Http\RedirectResponse;
use Illuminate\View\View;

class ArtworkController extends Controller
{
    public function __construct(private readonly ContentTypeSlugResolver $contentTypeResolver)
    {
    }

    /**
     * Browse artworks with optional category filtering.
     * Uses cursor pagination (no offset pagination) and only returns public, approved, not-deleted items.
     */
    public function index(ArtworkIndexRequest $request, ?Category $category = null): View
    {
        $perPage = (int) ($request->get('per_page', 24));

        $query = Artwork::public()->published();

        if ($category) {
            $query->whereHas('categories', function ($q) use ($category) {
                $q->where('categories.id', $category->id);
            });
        }

        if ($request->filled('q')) {
            $q = $request->get('q');
            $query->where(function ($sub) use ($q) {
                $sub->where('title', 'like', '%' . $q . '%')
                    ->orWhere('description', 'like', '%' . $q . '%');
            });
        }

        $sort = $request->get('sort', 'latest');
        if ($sort === 'oldest') {
            $query->orderBy('published_at', 'asc');
        } else {
            $query->orderByDesc('published_at');
        }

        // Important: do NOT eager-load artwork_stats in listings
        $artworks = $query->cursorPaginate($perPage);

        return view('artworks.index', [
            'artworks' => $artworks,
            'category' => $category,
        ]);
    }

    /**
     * Show a single artwork by slug. Resolve the slug manually to avoid implicit
     * route-model binding exceptions when the slug does not correspond to an artwork.
     */
    public function show(Request $request, string $contentTypeSlug, string $categoryPath, $artwork = null)
    {
        $resolution = $this->contentTypeResolver->resolve($contentTypeSlug);
        if (! $resolution->found() || $resolution->contentType === null) {
            abort(404);
        }

        $resolvedContentTypeSlug = strtolower((string) $resolution->contentType->slug);

        if ($resolution->requiresRedirect()) {
            return $this->redirectToCanonicalArtworkPath($request, $resolvedContentTypeSlug, $categoryPath, $artwork, 301);
        }

        // Manually resolve artwork by slug when provided. The route may bind
        // the 'artwork' parameter to an Artwork model or pass the slug string.
        $foundArtwork = null;
        $artworkSlug = null;
        if ($artwork instanceof Artwork) {
            $foundArtwork = $artwork;
            $artworkSlug = $artwork->slug;
        } elseif ($artwork) {
            $artworkSlug = (string) $artwork;
            $foundArtwork = $this->findArtworkForCategoryPath($resolvedContentTypeSlug, $categoryPath, $artworkSlug);
        }

        // When the URL can represent a nested category path (e.g. /skins/audio/winamp),
        // prefer category rendering over artwork slug collisions so same-level groups
        // behave consistently.
        if (! empty($artworkSlug)) {
            $combinedPath = trim($categoryPath . '/' . $artworkSlug, '/');
            $resolvedCategory = Category::findByPath($resolvedContentTypeSlug, $combinedPath);
            if ($resolvedCategory) {
                return app(BrowseGalleryController::class)->content(request(), $resolvedContentTypeSlug, $combinedPath);
            }
        }

        // If no artwork was found, treat the request as a category path.
        // The route places the artwork slug in the last segment, so include it.
        // Delegate to BrowseGalleryController to render the same modern gallery
        // layout used by routes like /skins/audio.
        if (! $foundArtwork) {
            $combinedPath = $categoryPath;
            if ($artworkSlug) {
                $combinedPath = trim($categoryPath . '/' . $artworkSlug, '/');
            }
            return app(BrowseGalleryController::class)->content(request(), $resolvedContentTypeSlug, $combinedPath);
        }

        if (! $foundArtwork->is_public || ! $foundArtwork->is_approved || $foundArtwork->trashed()) {
            abort(404);
        }

        // Delegate to the canonical ArtworkPageController which builds all
        // required view data ($meta, thumbnails, related items, comments, etc.)
        return app(\App\Http\Controllers\Web\ArtworkPageController::class)->show(
            $request,
            (int) $foundArtwork->id,
            $foundArtwork->slug,
        );
    }

    private function findArtworkForCategoryPath(string $contentTypeSlug, string $categoryPath, string $artworkSlug): ?Artwork
    {
        $segments = array_values(array_filter(explode('/', trim($categoryPath, '/'))));
        $category = Category::findByPath(strtolower($contentTypeSlug), $segments);

        $query = Artwork::query()->where('slug', $artworkSlug);

        if ($category) {
            $query->whereHas('categories', function ($categoryQuery) use ($category): void {
                $categoryQuery->where('categories.id', $category->id);
            });
        }

        return $query
            ->orderByDesc('published_at')
            ->orderByDesc('id')
            ->first();
    }

    private function redirectToCanonicalArtworkPath(Request $request, string $contentTypeSlug, string $categoryPath, Artwork|string|null $artwork, int $status = 301): RedirectResponse
    {
        $artworkSlug = $artwork instanceof Artwork ? $artwork->slug : (string) $artwork;
        $target = url('/' . trim($contentTypeSlug . '/' . trim($categoryPath, '/') . '/' . trim($artworkSlug, '/'), '/'));
        $queryString = $request->getQueryString();

        if ($queryString) {
            $target .= '?' . $queryString;
        }

        return redirect()->to($target, $status);
    }
}
