<?php

declare(strict_types=1);

namespace App\Services\Studio\Providers;

use App\Models\Collection;
use App\Models\User;
use App\Services\CollectionService;
use App\Services\Studio\Contracts\CreatorStudioProvider;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Collection as SupportCollection;

final class CollectionStudioProvider implements CreatorStudioProvider
{
    public function __construct(
        private readonly CollectionService $collections,
    ) {
    }

    public function key(): string
    {
        return 'collections';
    }

    public function label(): string
    {
        return 'Collections';
    }

    public function icon(): string
    {
        return 'fa-solid fa-layer-group';
    }

    public function createUrl(): string
    {
        return route('settings.collections.create');
    }

    public function indexUrl(): string
    {
        return route('studio.collections');
    }

    public function summary(User $user): array
    {
        $baseQuery = Collection::query()->withTrashed()->where('user_id', $user->id);

        $count = (clone $baseQuery)
            ->whereNull('deleted_at')
            ->where('lifecycle_state', '!=', Collection::LIFECYCLE_ARCHIVED)
            ->count();

        $draftCount = (clone $baseQuery)
            ->whereNull('deleted_at')
            ->where(function (Builder $query): void {
                $query->where('lifecycle_state', Collection::LIFECYCLE_DRAFT)
                    ->orWhere('workflow_state', Collection::WORKFLOW_DRAFT)
                    ->orWhere('workflow_state', Collection::WORKFLOW_IN_REVIEW);
            })
            ->count();

        $publishedCount = (clone $baseQuery)
            ->whereNull('deleted_at')
            ->whereIn('lifecycle_state', [Collection::LIFECYCLE_PUBLISHED, Collection::LIFECYCLE_FEATURED, Collection::LIFECYCLE_SCHEDULED])
            ->count();

        $recentPublishedCount = (clone $baseQuery)
            ->whereNull('deleted_at')
            ->whereIn('lifecycle_state', [Collection::LIFECYCLE_PUBLISHED, Collection::LIFECYCLE_FEATURED, Collection::LIFECYCLE_SCHEDULED])
            ->where('published_at', '>=', now()->subDays(30))
            ->count();

        $archivedCount = (clone $baseQuery)
            ->where(function (Builder $query): void {
                $query->whereNotNull('deleted_at')
                    ->orWhere('lifecycle_state', Collection::LIFECYCLE_ARCHIVED);
            })
            ->count();

        return [
            'key' => $this->key(),
            'label' => $this->label(),
            'icon' => $this->icon(),
            'count' => $count,
            'draft_count' => $draftCount,
            'published_count' => $publishedCount,
            'archived_count' => $archivedCount,
            'trend_value' => $recentPublishedCount,
            'trend_label' => 'published in 30d',
            'quick_action_label' => 'Create collection',
            'index_url' => $this->indexUrl(),
            'create_url' => $this->createUrl(),
        ];
    }

    public function items(User $user, string $bucket = 'all', int $limit = 200): SupportCollection
    {
        $query = Collection::query()
            ->withTrashed()
            ->where('user_id', $user->id)
            ->with(['user.profile', 'coverArtwork'])
            ->orderByDesc('updated_at')
            ->limit($limit);

        if ($bucket === 'drafts') {
            $query->whereNull('deleted_at')
                ->where(function (Builder $builder): void {
                    $builder->where('lifecycle_state', Collection::LIFECYCLE_DRAFT)
                        ->orWhere('workflow_state', Collection::WORKFLOW_DRAFT)
                        ->orWhere('workflow_state', Collection::WORKFLOW_IN_REVIEW);
                });
        } elseif ($bucket === 'scheduled') {
            $query->whereNull('deleted_at')
                ->where('lifecycle_state', Collection::LIFECYCLE_SCHEDULED);
        } elseif ($bucket === 'archived') {
            $query->where(function (Builder $builder): void {
                $builder->whereNotNull('deleted_at')
                    ->orWhere('lifecycle_state', Collection::LIFECYCLE_ARCHIVED);
            });
        } elseif ($bucket === 'published') {
            $query->whereNull('deleted_at')
                ->whereIn('lifecycle_state', [Collection::LIFECYCLE_PUBLISHED, Collection::LIFECYCLE_FEATURED, Collection::LIFECYCLE_SCHEDULED]);
        } else {
            $query->whereNull('deleted_at')->where('lifecycle_state', '!=', Collection::LIFECYCLE_ARCHIVED);
        }

        return collect($this->collections->mapCollectionCardPayloads($query->get(), true, $user))
            ->map(fn (array $item): array => $this->mapItem($item));
    }

    public function topItems(User $user, int $limit = 5): SupportCollection
    {
        $collections = Collection::query()
            ->where('user_id', $user->id)
            ->whereNull('deleted_at')
            ->whereIn('lifecycle_state', [Collection::LIFECYCLE_PUBLISHED, Collection::LIFECYCLE_FEATURED])
            ->with(['user.profile', 'coverArtwork'])
            ->orderByDesc('ranking_score')
            ->orderByDesc('views_count')
            ->limit($limit)
            ->get();

        return collect($this->collections->mapCollectionCardPayloads($collections, true, $user))
            ->map(fn (array $item): array => $this->mapItem($item));
    }

    public function analytics(User $user): array
    {
        $totals = Collection::query()
            ->where('user_id', $user->id)
            ->whereNull('deleted_at')
            ->selectRaw('COALESCE(SUM(views_count), 0) as views')
            ->selectRaw('COALESCE(SUM(likes_count + followers_count), 0) as appreciation')
            ->selectRaw('COALESCE(SUM(shares_count), 0) as shares')
            ->selectRaw('COALESCE(SUM(comments_count), 0) as comments')
            ->selectRaw('COALESCE(SUM(saves_count), 0) as saves')
            ->first();

        return [
            'views' => (int) ($totals->views ?? 0),
            'appreciation' => (int) ($totals->appreciation ?? 0),
            'shares' => (int) ($totals->shares ?? 0),
            'comments' => (int) ($totals->comments ?? 0),
            'saves' => (int) ($totals->saves ?? 0),
        ];
    }

    public function scheduledItems(User $user, int $limit = 50): SupportCollection
    {
        return $this->items($user, 'scheduled', $limit);
    }

    private function mapItem(array $item): array
    {
        $status = $item['lifecycle_state'] ?? 'draft';
        if ($status === Collection::LIFECYCLE_FEATURED) {
            $status = 'published';
        }

        return [
            'id' => sprintf('%s:%d', $this->key(), (int) $item['id']),
            'numeric_id' => (int) $item['id'],
            'module' => $this->key(),
            'module_label' => $this->label(),
            'module_icon' => $this->icon(),
            'title' => $item['title'],
            'subtitle' => $item['subtitle'] ?: ($item['type'] ? ucfirst((string) $item['type']) : null),
            'description' => $item['summary'] ?: $item['description'],
            'status' => $status,
            'visibility' => $item['visibility'],
            'image_url' => $item['cover_image'],
            'preview_url' => $item['url'],
            'view_url' => $item['url'],
            'edit_url' => $item['edit_url'] ?: $item['manage_url'],
            'manage_url' => $item['manage_url'],
            'analytics_url' => route('settings.collections.analytics', ['collection' => $item['id']]),
            'create_url' => $this->createUrl(),
            'actions' => $this->actionsFor($item, $status),
            'created_at' => $item['published_at'] ?? $item['updated_at'],
            'updated_at' => $item['updated_at'],
            'published_at' => $item['published_at'] ?? null,
            'scheduled_at' => $status === Collection::LIFECYCLE_SCHEDULED ? ($item['published_at'] ?? null) : null,
            'featured' => (bool) ($item['is_featured'] ?? false),
            'metrics' => [
                'views' => (int) ($item['views_count'] ?? 0),
                'appreciation' => (int) (($item['likes_count'] ?? 0) + ($item['followers_count'] ?? 0)),
                'shares' => (int) ($item['shares_count'] ?? 0),
                'comments' => (int) ($item['comments_count'] ?? 0),
                'saves' => (int) ($item['saves_count'] ?? 0),
            ],
            'engagement_score' => (int) ($item['views_count'] ?? 0)
                + ((int) ($item['likes_count'] ?? 0) * 2)
                + ((int) ($item['followers_count'] ?? 0) * 2)
                + ((int) ($item['comments_count'] ?? 0) * 3)
                + ((int) ($item['shares_count'] ?? 0) * 2)
                + ((int) ($item['saves_count'] ?? 0) * 2),
            'taxonomies' => [
                'categories' => [],
                'tags' => [],
            ],
        ];
    }

    private function actionsFor(array $item, string $status): array
    {
        $collectionId = (int) $item['id'];
        $actions = [];
        $featured = (bool) ($item['is_featured'] ?? false);

        if ($status === 'draft') {
            $actions[] = $this->requestAction(
                'publish',
                'Publish',
                'fa-solid fa-rocket',
                route('settings.collections.lifecycle', ['collection' => $collectionId]),
                [
                    'lifecycle_state' => Collection::LIFECYCLE_PUBLISHED,
                    'visibility' => Collection::VISIBILITY_PUBLIC,
                    'published_at' => now()->toIso8601String(),
                ]
            );
        }

        if (in_array($status, ['published', 'scheduled'], true)) {
            $actions[] = $this->requestAction(
                'archive',
                'Archive',
                'fa-solid fa-box-archive',
                route('settings.collections.lifecycle', ['collection' => $collectionId]),
                [
                    'lifecycle_state' => Collection::LIFECYCLE_ARCHIVED,
                    'archived_at' => now()->toIso8601String(),
                ]
            );

            $actions[] = $featured
                ? $this->requestAction('unfeature', 'Remove feature', 'fa-solid fa-star-half-stroke', route('settings.collections.unfeature', ['collection' => $collectionId]), [], null, 'delete')
                : $this->requestAction('feature', 'Feature', 'fa-solid fa-star', route('settings.collections.feature', ['collection' => $collectionId]), []);

            if ($status === 'scheduled') {
                $actions[] = $this->requestAction('publish_now', 'Publish now', 'fa-solid fa-bolt', route('api.studio.schedule.publishNow', ['module' => 'collections', 'id' => $collectionId]), []);
                $actions[] = $this->requestAction('unschedule', 'Unschedule', 'fa-solid fa-calendar-xmark', route('api.studio.schedule.unschedule', ['module' => 'collections', 'id' => $collectionId]), []);
            }
        }

        if ($status === 'archived') {
            $actions[] = $this->requestAction(
                'restore',
                'Restore',
                'fa-solid fa-rotate-left',
                route('settings.collections.lifecycle', ['collection' => $collectionId]),
                [
                    'lifecycle_state' => Collection::LIFECYCLE_DRAFT,
                    'visibility' => Collection::VISIBILITY_PRIVATE,
                    'archived_at' => null,
                ]
            );
        }

        $actions[] = $this->requestAction(
            'delete',
            'Delete',
            'fa-solid fa-trash',
            route('settings.collections.destroy', ['collection' => $collectionId]),
            [],
            'Delete this collection permanently?',
            'delete'
        );

        return $actions;
    }

    private function requestAction(string $key, string $label, string $icon, string $url, array $payload = [], ?string $confirm = null, string $method = 'post'): array
    {
        return [
            'key' => $key,
            'label' => $label,
            'icon' => $icon,
            'type' => 'request',
            'method' => $method,
            'url' => $url,
            'payload' => $payload,
            'confirm' => $confirm,
        ];
    }
}