<?php

declare(strict_types=1);

namespace App\Services\Studio;

use App\Models\User;
use App\Services\Studio\Contracts\CreatorStudioProvider;
use App\Services\Studio\Providers\ArtworkStudioProvider;
use App\Services\Studio\Providers\CardStudioProvider;
use App\Services\Studio\Providers\CollectionStudioProvider;
use App\Services\Studio\Providers\StoryStudioProvider;
use Carbon\Carbon;
use Illuminate\Support\Collection as SupportCollection;

final class CreatorStudioContentService
{
    public function __construct(
        private readonly ArtworkStudioProvider $artworks,
        private readonly CardStudioProvider $cards,
        private readonly CollectionStudioProvider $collections,
        private readonly StoryStudioProvider $stories,
    ) {
    }

    public function moduleSummaries(User $user): array
    {
        return SupportCollection::make($this->providers())
            ->map(fn (CreatorStudioProvider $provider): array => $provider->summary($user))
            ->values()
            ->all();
    }

    public function quickCreate(): array
    {
        $preferredOrder = ['artworks', 'cards', 'stories', 'collections'];

        return SupportCollection::make($this->providers())
            ->sortBy(fn (CreatorStudioProvider $provider): int => array_search($provider->key(), $preferredOrder, true))
            ->map(fn (CreatorStudioProvider $provider): array => [
                'key' => $provider->key(),
                'label' => rtrim($provider->label(), 's'),
                'icon' => $provider->icon(),
                'url' => $provider->createUrl(),
            ])
            ->values()
            ->all();
    }

    public function list(User $user, array $filters = [], ?string $fixedBucket = null, ?string $fixedModule = null): array
    {
        $module = $fixedModule ?: $this->normalizeModule((string) ($filters['module'] ?? 'all'));
        $bucket = $fixedBucket ?: $this->normalizeBucket((string) ($filters['bucket'] ?? 'all'));
        $search = trim((string) ($filters['q'] ?? ''));
        $sort = $this->normalizeSort((string) ($filters['sort'] ?? 'updated_desc'));
        $category = (string) ($filters['category'] ?? 'all');
        $tag = trim((string) ($filters['tag'] ?? ''));
        $visibility = (string) ($filters['visibility'] ?? 'all');
        $activityState = (string) ($filters['activity_state'] ?? 'all');
        $stale = (string) ($filters['stale'] ?? 'all');
        $page = max(1, (int) ($filters['page'] ?? 1));
        $perPage = min(max((int) ($filters['per_page'] ?? 24), 12), 48);

        $items = $module === 'all'
            ? SupportCollection::make($this->providers())->flatMap(fn (CreatorStudioProvider $provider) => $provider->items($user, $this->providerBucket($bucket), 200))
            : $this->provider($module)?->items($user, $this->providerBucket($bucket), 240) ?? SupportCollection::make();

        if ($bucket === 'featured') {
            $items = $items->filter(fn (array $item): bool => (bool) ($item['featured'] ?? false));
        } elseif ($bucket === 'recent') {
            $items = $items->filter(function (array $item): bool {
                $date = $item['published_at'] ?? $item['updated_at'] ?? $item['created_at'] ?? null;

                return $date !== null && strtotime((string) $date) >= Carbon::now()->subDays(30)->getTimestamp();
            });
        }

        if ($search !== '') {
            $needle = mb_strtolower($search);
            $items = $items->filter(function (array $item) use ($needle): bool {
                $haystacks = [
                    $item['title'] ?? '',
                    $item['subtitle'] ?? '',
                    $item['description'] ?? '',
                    $item['module_label'] ?? '',
                ];

                return SupportCollection::make($haystacks)
                    ->filter(fn ($value): bool => is_string($value) && $value !== '')
                    ->contains(fn (string $value): bool => str_contains(mb_strtolower($value), $needle));
            });
        }

        if ($module === 'artworks' && $category !== 'all') {
            $items = $items->filter(function (array $item) use ($category): bool {
                return SupportCollection::make($item['taxonomies']['categories'] ?? [])
                    ->contains(fn (array $entry): bool => (string) ($entry['slug'] ?? '') === $category);
            });
        }

        if ($module === 'artworks' && $tag !== '') {
            $needle = mb_strtolower($tag);
            $items = $items->filter(function (array $item) use ($needle): bool {
                return SupportCollection::make($item['taxonomies']['tags'] ?? [])
                    ->contains(fn (array $entry): bool => str_contains(mb_strtolower((string) ($entry['name'] ?? '')), $needle));
            });
        }

        if ($module === 'collections' && $visibility !== 'all') {
            $items = $items->filter(fn (array $item): bool => (string) ($item['visibility'] ?? '') === $visibility);
        }

        if ($module === 'stories' && $activityState !== 'all') {
            $items = $items->filter(fn (array $item): bool => (string) ($item['activity_state'] ?? 'all') === $activityState);
        }

        if ($stale === 'only') {
            $threshold = Carbon::now()->subDays(3)->getTimestamp();
            $items = $items->filter(function (array $item) use ($threshold): bool {
                $updatedAt = strtotime((string) ($item['updated_at'] ?? $item['created_at'] ?? ''));

                return $updatedAt > 0 && $updatedAt <= $threshold;
            });
        }

        $items = $this->annotateItems($this->sortItems($items, $sort)->values());
        $total = $items->count();
        $lastPage = max(1, (int) ceil($total / $perPage));
        $page = min($page, $lastPage);

        return [
            'items' => $items->forPage($page, $perPage)->values()->all(),
            'meta' => [
                'current_page' => $page,
                'last_page' => $lastPage,
                'per_page' => $perPage,
                'total' => $total,
            ],
            'filters' => [
                'module' => $module,
                'bucket' => $bucket,
                'q' => $search,
                'sort' => $sort,
                'category' => $category,
                'tag' => $tag,
                'visibility' => $visibility,
                'activity_state' => $activityState,
                'stale' => $stale,
            ],
            'module_options' => array_merge([
                ['value' => 'all', 'label' => 'All content'],
            ], SupportCollection::make($this->moduleSummaries($user))->map(fn (array $summary): array => [
                'value' => $summary['key'],
                'label' => $summary['label'],
            ])->all()),
            'bucket_options' => [
                ['value' => 'all', 'label' => 'All'],
                ['value' => 'published', 'label' => 'Published'],
                ['value' => 'drafts', 'label' => 'Drafts'],
                ['value' => 'scheduled', 'label' => 'Scheduled'],
                ['value' => 'archived', 'label' => 'Archived'],
                ['value' => 'featured', 'label' => 'Featured'],
                ['value' => 'recent', 'label' => 'Recent'],
            ],
            'sort_options' => [
                ['value' => 'updated_desc', 'label' => 'Recently updated'],
                ['value' => 'updated_asc', 'label' => 'Oldest untouched'],
                ['value' => 'created_desc', 'label' => 'Newest created'],
                ['value' => 'published_desc', 'label' => 'Newest published'],
                ['value' => 'views_desc', 'label' => 'Most viewed'],
                ['value' => 'appreciation_desc', 'label' => 'Most liked'],
                ['value' => 'comments_desc', 'label' => 'Most commented'],
                ['value' => 'engagement_desc', 'label' => 'Best engagement'],
                ['value' => 'title_asc', 'label' => 'Title A-Z'],
            ],
            'advanced_filters' => $this->advancedFilters($module, $items, [
                'category' => $category,
                'tag' => $tag,
                'visibility' => $visibility,
                'activity_state' => $activityState,
                'stale' => $stale,
            ]),
        ];
    }

    public function draftReminders(User $user, int $limit = 4): array
    {
        return $this->annotateItems(SupportCollection::make($this->providers())
            ->flatMap(fn (CreatorStudioProvider $provider) => $provider->items($user, 'drafts', $limit))
            ->sortByDesc(fn (array $item): int => strtotime((string) ($item['updated_at'] ?? $item['created_at'] ?? Carbon::now()->toIso8601String())))
            ->take($limit)
            ->values())
            ->all();
    }

    public function staleDrafts(User $user, int $limit = 4): array
    {
        return $this->annotateItems(SupportCollection::make($this->providers())
            ->flatMap(fn (CreatorStudioProvider $provider) => $provider->items($user, 'drafts', $limit * 4))
            ->filter(function (array $item): bool {
                $updatedAt = strtotime((string) ($item['updated_at'] ?? $item['created_at'] ?? Carbon::now()->toIso8601String()));

                return $updatedAt <= Carbon::now()->subDays(3)->getTimestamp();
            })
            ->sortBy(fn (array $item): int => strtotime((string) ($item['updated_at'] ?? $item['created_at'] ?? Carbon::now()->toIso8601String())))
            ->take($limit)
                ->values())
            ->all();
    }

    public function continueWorking(User $user, string $draftBehavior = 'resume-last', int $limit = 3): array
    {
        if ($draftBehavior === 'focus-published') {
            return $this->recentPublished($user, $limit);
        }

        return $this->annotateItems(SupportCollection::make($this->providers())
            ->flatMap(fn (CreatorStudioProvider $provider) => $provider->items($user, 'drafts', $limit * 4))
            ->sortByDesc(fn (array $item): int => strtotime((string) ($item['updated_at'] ?? $item['created_at'] ?? Carbon::now()->toIso8601String())))
            ->take($limit)
            ->values())
            ->all();
    }

    public function recentPublished(User $user, int $limit = 6): array
    {
        return $this->annotateItems(SupportCollection::make($this->providers())
            ->flatMap(fn (CreatorStudioProvider $provider) => $provider->items($user, 'published', $limit * 2))
            ->sortByDesc(fn (array $item): int => strtotime((string) ($item['published_at'] ?? $item['updated_at'] ?? Carbon::now()->toIso8601String())))
            ->take($limit)
            ->values())
            ->all();
    }

    public function featuredCandidates(User $user, int $limit = 8): array
    {
        return $this->annotateItems(SupportCollection::make($this->providers())
            ->flatMap(fn (CreatorStudioProvider $provider) => $provider->items($user, 'published', $limit * 2))
            ->filter(fn (array $item): bool => ($item['status'] ?? null) === 'published')
            ->sortByDesc(fn (array $item): int => (int) ($item['engagement_score'] ?? 0))
            ->take($limit)
            ->values())
            ->all();
    }

    /**
     * @param array<string, int> $featuredContent
     * @return array<string, array<string, mixed>|null>
     */
    public function selectedItems(User $user, array $featuredContent): array
    {
        return SupportCollection::make(['artworks', 'cards', 'collections', 'stories'])
            ->mapWithKeys(function (string $module) use ($user, $featuredContent): array {
                $selectedId = (int) ($featuredContent[$module] ?? 0);
                if ($selectedId < 1) {
                    return [$module => null];
                }

                $item = $this->provider($module)?->items($user, 'all', 400)
                    ->first(fn (array $entry): bool => (int) ($entry['numeric_id'] ?? 0) === $selectedId);

                return [$module => $item ?: null];
            })
            ->all();
    }

    public function provider(string $module): ?CreatorStudioProvider
    {
        return SupportCollection::make($this->providers())->first(fn (CreatorStudioProvider $provider): bool => $provider->key() === $module);
    }

    public function providers(): array
    {
        return [
            $this->artworks,
            $this->cards,
            $this->collections,
            $this->stories,
        ];
    }

    private function normalizeModule(string $module): string
    {
        $allowed = ['all', 'artworks', 'cards', 'collections', 'stories'];

        return in_array($module, $allowed, true) ? $module : 'all';
    }

    private function normalizeBucket(string $bucket): string
    {
        $allowed = ['all', 'published', 'drafts', 'scheduled', 'archived', 'featured', 'recent'];

        return in_array($bucket, $allowed, true) ? $bucket : 'all';
    }

    private function normalizeSort(string $sort): string
    {
        $allowed = ['updated_desc', 'updated_asc', 'created_desc', 'published_desc', 'views_desc', 'appreciation_desc', 'comments_desc', 'engagement_desc', 'title_asc'];

        return in_array($sort, $allowed, true) ? $sort : 'updated_desc';
    }

    private function providerBucket(string $bucket): string
    {
        return $bucket === 'featured' ? 'published' : $bucket;
    }

    private function sortItems(SupportCollection $items, string $sort): SupportCollection
    {
        return match ($sort) {
            'created_desc' => $items->sortByDesc(fn (array $item): int => strtotime((string) ($item['created_at'] ?? ''))),
            'updated_asc' => $items->sortBy(fn (array $item): int => strtotime((string) ($item['updated_at'] ?? $item['created_at'] ?? ''))),
            'published_desc' => $items->sortByDesc(fn (array $item): int => strtotime((string) ($item['published_at'] ?? $item['updated_at'] ?? ''))),
            'views_desc' => $items->sortByDesc(fn (array $item): int => (int) (($item['metrics']['views'] ?? 0))),
            'appreciation_desc' => $items->sortByDesc(fn (array $item): int => (int) (($item['metrics']['appreciation'] ?? 0))),
            'comments_desc' => $items->sortByDesc(fn (array $item): int => (int) (($item['metrics']['comments'] ?? 0))),
            'engagement_desc' => $items->sortByDesc(fn (array $item): int => (int) ($item['engagement_score'] ?? 0)),
            'title_asc' => $items->sortBy(fn (array $item): string => mb_strtolower((string) ($item['title'] ?? ''))),
            default => $items->sortByDesc(fn (array $item): int => strtotime((string) ($item['updated_at'] ?? $item['created_at'] ?? ''))),
        };
    }

    /**
     * @param array<string, string> $currentFilters
     */
    private function advancedFilters(string $module, SupportCollection $items, array $currentFilters): array
    {
        return match ($module) {
            'artworks' => [
                [
                    'key' => 'category',
                    'label' => 'Category',
                    'type' => 'select',
                    'value' => $currentFilters['category'] ?? 'all',
                    'options' => array_merge([
                        ['value' => 'all', 'label' => 'All categories'],
                    ], $items
                        ->flatMap(fn (array $item) => $item['taxonomies']['categories'] ?? [])
                        ->unique('slug')
                        ->sortBy('name')
                        ->map(fn (array $entry): array => [
                            'value' => (string) ($entry['slug'] ?? ''),
                            'label' => (string) ($entry['name'] ?? 'Category'),
                        ])->values()->all()),
                ],
                [
                    'key' => 'tag',
                    'label' => 'Tag',
                    'type' => 'search',
                    'value' => $currentFilters['tag'] ?? '',
                    'placeholder' => 'Filter by tag',
                ],
            ],
            'collections' => [[
                'key' => 'visibility',
                'label' => 'Visibility',
                'type' => 'select',
                'value' => $currentFilters['visibility'] ?? 'all',
                'options' => [
                    ['value' => 'all', 'label' => 'All visibility'],
                    ['value' => 'public', 'label' => 'Public'],
                    ['value' => 'unlisted', 'label' => 'Unlisted'],
                    ['value' => 'private', 'label' => 'Private'],
                ],
            ]],
            'stories' => [[
                'key' => 'activity_state',
                'label' => 'Activity',
                'type' => 'select',
                'value' => $currentFilters['activity_state'] ?? 'all',
                'options' => [
                    ['value' => 'all', 'label' => 'All states'],
                    ['value' => 'active', 'label' => 'Active'],
                    ['value' => 'inactive', 'label' => 'Inactive'],
                    ['value' => 'archived', 'label' => 'Archived'],
                ],
            ]],
            'all' => [[
                'key' => 'stale',
                'label' => 'Draft freshness',
                'type' => 'select',
                'value' => $currentFilters['stale'] ?? 'all',
                'options' => [
                    ['value' => 'all', 'label' => 'All drafts'],
                    ['value' => 'only', 'label' => 'Stale drafts'],
                ],
            ]],
            default => [[
                'key' => 'stale',
                'label' => 'Draft freshness',
                'type' => 'select',
                'value' => $currentFilters['stale'] ?? 'all',
                'options' => [
                    ['value' => 'all', 'label' => 'All drafts'],
                    ['value' => 'only', 'label' => 'Stale drafts'],
                ],
            ]],
        };
    }

    private function annotateItems(SupportCollection $items): SupportCollection
    {
        return $items->map(fn (array $item): array => $this->annotateItem($item))->values();
    }

    private function annotateItem(array $item): array
    {
        $now = Carbon::now();
        $updatedAt = Carbon::parse((string) ($item['updated_at'] ?? $item['created_at'] ?? $now->toIso8601String()));
        $status = (string) ($item['status'] ?? '');
        $isDraft = ($item['status'] ?? null) === 'draft';
        $missing = [];
        $score = 0;

        if ($this->hasValue($item['title'] ?? null)) {
            $score++;
        } else {
            $missing[] = 'Add a title';
        }

        if ($this->hasValue($item['description'] ?? null)) {
            $score++;
        } else {
            $missing[] = 'Add a description';
        }

        if ($this->hasValue($item['image_url'] ?? null)) {
            $score++;
        } else {
            $missing[] = 'Add a preview image';
        }

        if (! empty($item['taxonomies']['categories'] ?? []) || $this->hasValue($item['subtitle'] ?? null)) {
            $score++;
        } else {
            $missing[] = 'Choose a category or content context';
        }

        $label = match (true) {
            $score >= 4 => 'Ready to publish',
            $score === 3 => 'Almost ready',
            default => 'Needs more work',
        };

        $readiness = $status === 'published'
            ? null
            : [
                'score' => $score,
                'max' => 4,
                'label' => $label,
                'can_publish' => $score >= 3,
                'missing' => $missing,
            ];

        $workflowActions = match ((string) ($item['module'] ?? '')) {
            'artworks' => [
                ['label' => 'Create card', 'href' => route('studio.cards.create'), 'icon' => 'fa-solid fa-id-card'],
                ['label' => 'Curate collection', 'href' => route('settings.collections.create'), 'icon' => 'fa-solid fa-layer-group'],
                ['label' => 'Tell story', 'href' => route('creator.stories.create'), 'icon' => 'fa-solid fa-feather-pointed'],
            ],
            'cards' => [
                ['label' => 'Build collection', 'href' => route('settings.collections.create'), 'icon' => 'fa-solid fa-layer-group'],
                ['label' => 'Open stories', 'href' => route('studio.stories'), 'icon' => 'fa-solid fa-feather-pointed'],
            ],
            'stories' => [
                ['label' => 'Create card', 'href' => route('studio.cards.create'), 'icon' => 'fa-solid fa-id-card'],
                ['label' => 'Curate collection', 'href' => route('settings.collections.create'), 'icon' => 'fa-solid fa-layer-group'],
            ],
            'collections' => [
                ['label' => 'Review artworks', 'href' => route('studio.artworks'), 'icon' => 'fa-solid fa-images'],
                ['label' => 'Review cards', 'href' => route('studio.cards.index'), 'icon' => 'fa-solid fa-id-card'],
            ],
            default => [],
        };

        $item['workflow'] = [
            'is_stale_draft' => $isDraft && $updatedAt->lte($now->copy()->subDays(3)),
            'last_touched_days' => max(0, $updatedAt->diffInDays($now)),
            'resume_label' => $isDraft ? 'Resume draft' : 'Open item',
            'readiness' => $readiness,
            'cross_module_actions' => $workflowActions,
        ];

        return $item;
    }

    private function hasValue(mixed $value): bool
    {
        return is_string($value) ? trim($value) !== '' : ! empty($value);
    }
}