<?php

declare(strict_types=1);

namespace App\Http\Controllers\User;

use App\Events\Collections\CollectionViewed;
use App\Http\Controllers\Controller;
use App\Models\Collection;
use App\Models\User;
use App\Services\CollectionCollaborationService;
use App\Services\CollectionCommentService;
use App\Services\CollectionDiscoveryService;
use App\Services\CollectionFollowService;
use App\Services\CollectionLinkService;
use App\Services\CollectionLikeService;
use App\Services\CollectionLinkedCollectionsService;
use App\Services\CollectionRecommendationService;
use App\Services\CollectionSaveService;
use App\Services\CollectionSeriesService;
use App\Services\CollectionSubmissionService;
use App\Services\CollectionService;
use App\Support\Seo\SeoFactory;
use App\Support\UsernamePolicy;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Inertia\Inertia;

class ProfileCollectionController extends Controller
{
    public function __construct(
        private readonly CollectionService $collections,
        private readonly CollectionLikeService $likes,
        private readonly CollectionFollowService $follows,
        private readonly CollectionSaveService $saves,
        private readonly CollectionCollaborationService $collaborators,
        private readonly CollectionSubmissionService $submissions,
        private readonly CollectionCommentService $comments,
        private readonly CollectionDiscoveryService $discovery,
        private readonly CollectionRecommendationService $recommendations,
        private readonly CollectionLinkService $entityLinks,
        private readonly CollectionLinkedCollectionsService $linkedCollections,
        private readonly CollectionSeriesService $series,
    ) {
    }

    public function show(Request $request, string $username, string $slug)
    {
        $normalized = UsernamePolicy::normalize($username);
        $user = User::query()->whereRaw('LOWER(username) = ?', [$normalized])->first();

        if (! $user) {
            $redirect = DB::table('username_redirects')
                ->whereRaw('LOWER(old_username) = ?', [$normalized])
                ->value('new_username');

            if ($redirect) {
                return redirect()->route('profile.collections.show', [
                    'username' => strtolower((string) $redirect),
                    'slug' => $slug,
                ], 301);
            }

            abort(404);
        }

        if ($username !== strtolower((string) $user->username)) {
            return redirect()->route('profile.collections.show', [
                'username' => strtolower((string) $user->username),
                'slug' => $slug,
            ], 301);
        }

        $collection = Collection::query()
            ->with([
                'user.profile',
                'coverArtwork:id,user_id,title,slug,hash,thumb_ext,published_at,is_public,is_approved,deleted_at',
                'canonicalCollection.user.profile',
            ])
            ->where('user_id', $user->id)
            ->where('slug', $slug)
            ->firstOrFail();

        $viewer = $request->user();
        $ownerView = $viewer && (int) $viewer->id === (int) $user->id;

        if ($collection->canonical_collection_id) {
            $canonicalTarget = $collection->canonicalCollection;

            if ($canonicalTarget instanceof Collection
                && (int) $canonicalTarget->id !== (int) $collection->id
                && $canonicalTarget->user instanceof User
                && $canonicalTarget->canBeViewedBy($viewer)) {
                return redirect()->route('profile.collections.show', [
                    'username' => strtolower((string) $canonicalTarget->user->username),
                    'slug' => $canonicalTarget->slug,
                ], 301);
            }
        }

        if (! $collection->canBeViewedBy($viewer)) {
            abort(404);
        }

        $collection = $this->collections->recordView($collection);
        $this->saves->touchSavedCollectionView($viewer, $collection);
        $artworks = $this->collections->getCollectionDetailArtworks($collection, $ownerView, 24);
        $collectionPayload = $this->collections->mapCollectionDetailPayload($collection, $ownerView);
        $manualRelatedCollections = $this->linkedCollections->publicLinkedCollections($collection, 6);
        $recommendedCollections = $this->recommendations->relatedPublicCollections($collection, 6);
        $seriesContext = $collection->inSeries()
            ? $this->series->seriesContext($collection)
            : ['previous' => null, 'next' => null, 'items' => [], 'title' => null, 'description' => null];

        event(new CollectionViewed($collection, $viewer?->id));

        $seo = app(SeoFactory::class)->collectionPage(
            $collection->is_featured
                ? sprintf('Featured: %s by %s — Skinbase', $collection->title, $collection->displayOwnerName())
                : sprintf('%s by %s — Skinbase', $collection->title, $collection->displayOwnerName()),
            $collection->summary ?: $collection->description ?: sprintf('Explore the %s collection by %s on Skinbase.', $collection->title, $collection->displayOwnerName()),
            $collectionPayload['public_url'],
            $collectionPayload['cover_image'],
            $collection->visibility === Collection::VISIBILITY_PUBLIC,
        )->toArray();

        return Inertia::render('Collection/CollectionShow', [
            'collection' => $collectionPayload,
            'artworks' => $this->collections->mapArtworkPaginator($artworks),
            'owner' => $collectionPayload['owner'],
            'isOwner' => $ownerView,
            'manageUrl' => $ownerView ? route('settings.collections.show', ['collection' => $collection->id]) : null,
            'editUrl' => $ownerView ? route('settings.collections.edit', ['collection' => $collection->id]) : null,
            'analyticsUrl' => $ownerView && $collection->supportsAnalytics() ? route('settings.collections.analytics', ['collection' => $collection->id]) : null,
            'historyUrl' => $ownerView ? route('settings.collections.history', ['collection' => $collection->id]) : null,
            'engagement' => [
                'liked' => $this->likes->isLiked($viewer, $collection),
                'following' => $this->follows->isFollowing($viewer, $collection),
                'saved' => $this->saves->isSaved($viewer, $collection),
                'can_interact' => ! $ownerView && $collection->isPubliclyEngageable(),
                'like_url' => route('collections.like', ['collection' => $collection->id]),
                'unlike_url' => route('collections.unlike', ['collection' => $collection->id]),
                'follow_url' => route('collections.follow', ['collection' => $collection->id]),
                'unfollow_url' => route('collections.unfollow', ['collection' => $collection->id]),
                'save_url' => route('collections.save', ['collection' => $collection->id]),
                'unsave_url' => route('collections.unsave', ['collection' => $collection->id]),
                'share_url' => route('collections.share', ['collection' => $collection->id]),
                'login_url' => route('login'),
            ],
            'members' => $this->collaborators->mapMembers($collection, $viewer),
            'submissions' => $this->submissions->mapSubmissions($collection, $viewer),
            'comments' => $this->comments->mapComments($collection, $viewer),
            'entityLinks' => $this->entityLinks->links($collection, true),
            'relatedCollections' => $this->collections->mapCollectionCardPayloads(
                $manualRelatedCollections
                    ->concat($recommendedCollections)
                    ->unique('id')
                    ->take(6)
                    ->values(),
                false
            ),
            'seriesContext' => [
                'key' => $seriesContext['key'] ?? $collection->series_key,
                'title' => $seriesContext['title'] ?? $collection->series_title,
                'description' => $seriesContext['description'] ?? $collection->series_description,
                'url' => ! empty($seriesContext['key']) ? route('collections.series.show', ['seriesKey' => $seriesContext['key']]) : null,
                'previous' => $seriesContext['previous'] ? ($this->collections->mapCollectionCardPayloads(collect([$seriesContext['previous']]), false)[0] ?? null) : null,
                'next' => $seriesContext['next'] ? ($this->collections->mapCollectionCardPayloads(collect([$seriesContext['next']]), false)[0] ?? null) : null,
                'siblings' => $this->collections->mapCollectionCardPayloads(collect($seriesContext['items'] ?? [])->filter(fn (Collection $item) => (int) $item->id !== (int) $collection->id), false),
            ],
            'submitEndpoint' => route('collections.submissions.store', ['collection' => $collection->id]),
            'commentsEndpoint' => route('collections.comments.store', ['collection' => $collection->id]),
            'submissionArtworkOptions' => $viewer ? $this->collections->getSubmissionArtworkOptions($viewer) : [],
            'canSubmit' => $collection->canReceiveSubmissionsFrom($viewer),
            'canComment' => $collection->canReceiveCommentsFrom($viewer),
            'profileCollectionsUrl' => route('profile.tab', [
                'username' => strtolower((string) $user->username),
                'tab' => 'collections',
            ]),
            'featuredCollectionsUrl' => route('collections.featured'),
            'reportEndpoint' => $viewer ? route('api.reports.store') : null,
            'seo' => $seo,
        ])->rootView('collections');
    }

    public function showSeries(Request $request, string $seriesKey)
    {
        $seriesCollections = $this->series->publicSeriesItems($seriesKey);

        abort_if($seriesCollections->isEmpty(), 404);

        $mappedCollections = $this->collections->mapCollectionCardPayloads($seriesCollections, false);
        $leadCollection = $mappedCollections[0] ?? null;
        $ownersCount = $seriesCollections->pluck('user_id')->unique()->count();
        $artworksCount = $seriesCollections->sum(fn (Collection $collection) => (int) $collection->artworks_count);
        $latestActivityAt = $seriesCollections->max('last_activity_at');
        $seriesMeta = $this->series->metadataFor($seriesCollections);
        $seriesTitle = $seriesMeta['title'] ?: collect($mappedCollections)
            ->pluck('campaign_label')
            ->filter()
            ->first();
        $seriesDescription = $seriesMeta['description'];

        $seo = app(SeoFactory::class)->collectionListing(
            sprintf('Series: %s — Skinbase', $seriesKey),
            sprintf('Explore the %s collection series on Skinbase.', $seriesKey),
            route('collections.series.show', ['seriesKey' => $seriesKey])
        )->toArray();

        return Inertia::render('Collection/CollectionSeriesShow', [
            'seriesKey' => $seriesKey,
            'title' => $seriesTitle ?: sprintf('Collection Series: %s', str_replace(['-', '_'], ' ', $seriesKey)),
            'description' => $seriesDescription ?: sprintf('Browse the %s collection series in sequence, with public entries ordered for smooth navigation across related curations.', $seriesKey),
            'collections' => $mappedCollections,
            'leadCollection' => $leadCollection,
            'stats' => [
                'collections' => $seriesCollections->count(),
                'owners' => $ownersCount,
                'artworks' => $artworksCount,
                'latest_activity_at' => optional($latestActivityAt)?->toISOString(),
            ],
            'seo' => $seo,
        ])->rootView('collections');
    }
}
