<?php

declare(strict_types=1);

namespace App\Services\Studio\Providers;

use App\Models\NovaCard;
use App\Models\User;
use App\Services\Studio\Contracts\CreatorStudioProvider;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;

final class CardStudioProvider implements CreatorStudioProvider
{
    public function key(): string
    {
        return 'cards';
    }

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

    public function icon(): string
    {
        return 'fa-solid fa-id-card';
    }

    public function createUrl(): string
    {
        return route('studio.cards.create');
    }

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

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

        $count = (clone $baseQuery)
            ->whereNull('deleted_at')
            ->whereNotIn('status', [NovaCard::STATUS_HIDDEN, NovaCard::STATUS_REJECTED])
            ->count();

        $draftCount = (clone $baseQuery)
            ->whereNull('deleted_at')
            ->where('status', NovaCard::STATUS_DRAFT)
            ->count();

        $publishedCount = (clone $baseQuery)
            ->whereNull('deleted_at')
            ->where('status', NovaCard::STATUS_PUBLISHED)
            ->count();

        $recentPublishedCount = (clone $baseQuery)
            ->whereNull('deleted_at')
            ->where('status', NovaCard::STATUS_PUBLISHED)
            ->where('published_at', '>=', now()->subDays(30))
            ->count();

        $archivedCount = (clone $baseQuery)
            ->where(function (Builder $query): void {
                $query->whereNotNull('deleted_at')
                    ->orWhereIn('status', [NovaCard::STATUS_HIDDEN, NovaCard::STATUS_REJECTED]);
            })
            ->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 card',
            'index_url' => $this->indexUrl(),
            'create_url' => $this->createUrl(),
        ];
    }

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

        if ($bucket === 'drafts') {
            $query->whereNull('deleted_at')->where('status', NovaCard::STATUS_DRAFT);
        } elseif ($bucket === 'scheduled') {
            $query->whereNull('deleted_at')->where('status', NovaCard::STATUS_SCHEDULED);
        } elseif ($bucket === 'archived') {
            $query->where(function (Builder $builder): void {
                $builder->whereNotNull('deleted_at')
                    ->orWhereIn('status', [NovaCard::STATUS_HIDDEN, NovaCard::STATUS_REJECTED]);
            });
        } elseif ($bucket === 'published') {
            $query->whereNull('deleted_at')->where('status', NovaCard::STATUS_PUBLISHED);
        } else {
            $query->whereNull('deleted_at')->whereNotIn('status', [NovaCard::STATUS_HIDDEN, NovaCard::STATUS_REJECTED]);
        }

        return $query->get()->map(fn (NovaCard $card): array => $this->mapItem($card));
    }

    public function topItems(User $user, int $limit = 5): Collection
    {
        return NovaCard::query()
            ->where('user_id', $user->id)
            ->whereNull('deleted_at')
            ->where('status', NovaCard::STATUS_PUBLISHED)
            ->orderByDesc('trending_score')
            ->orderByDesc('views_count')
            ->limit($limit)
            ->get()
            ->map(fn (NovaCard $card): array => $this->mapItem($card));
    }

    public function analytics(User $user): array
    {
        $totals = NovaCard::query()
            ->where('user_id', $user->id)
            ->whereNull('deleted_at')
            ->selectRaw('COALESCE(SUM(views_count), 0) as views')
            ->selectRaw('COALESCE(SUM(likes_count + favorites_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): Collection
    {
        return $this->items($user, 'scheduled', $limit);
    }

    private function mapItem(NovaCard $card): array
    {
        $status = $card->deleted_at || in_array($card->status, [NovaCard::STATUS_HIDDEN, NovaCard::STATUS_REJECTED], true)
            ? 'archived'
            : $card->status;

        return [
            'id' => sprintf('%s:%d', $this->key(), (int) $card->id),
            'numeric_id' => (int) $card->id,
            'module' => $this->key(),
            'module_label' => $this->label(),
            'module_icon' => $this->icon(),
            'title' => $card->title,
            'subtitle' => $card->category?->name ?: strtoupper((string) $card->format),
            'description' => $card->description,
            'status' => $status,
            'visibility' => $card->visibility,
            'image_url' => $card->previewUrl(),
            'preview_url' => route('studio.cards.preview', ['id' => $card->id]),
            'view_url' => $card->status === NovaCard::STATUS_PUBLISHED ? $card->publicUrl() : route('studio.cards.preview', ['id' => $card->id]),
            'edit_url' => route('studio.cards.edit', ['id' => $card->id]),
            'manage_url' => route('studio.cards.edit', ['id' => $card->id]),
            'analytics_url' => route('studio.cards.analytics', ['id' => $card->id]),
            'create_url' => $this->createUrl(),
            'actions' => $this->actionsFor($card, $status),
            'created_at' => $card->created_at?->toIso8601String(),
            'updated_at' => $card->updated_at?->toIso8601String(),
            'published_at' => $card->published_at?->toIso8601String(),
            'scheduled_at' => $card->scheduled_for?->toIso8601String(),
            'schedule_timezone' => $card->scheduling_timezone,
            'featured' => (bool) $card->featured,
            'metrics' => [
                'views' => (int) $card->views_count,
                'appreciation' => (int) ($card->likes_count + $card->favorites_count),
                'shares' => (int) $card->shares_count,
                'comments' => (int) $card->comments_count,
                'saves' => (int) $card->saves_count,
            ],
            'engagement_score' => (int) $card->views_count
                + ((int) $card->likes_count * 2)
                + ((int) $card->favorites_count * 2)
                + ((int) $card->comments_count * 3)
                + ((int) $card->shares_count * 2)
                + ((int) $card->saves_count * 2),
            'taxonomies' => [
                'categories' => $card->category ? [[
                    'id' => (int) $card->category->id,
                    'name' => (string) $card->category->name,
                    'slug' => (string) $card->category->slug,
                ]] : [],
                'tags' => $card->tags->map(fn ($entry): array => [
                    'id' => (int) $entry->id,
                    'name' => (string) $entry->name,
                    'slug' => (string) $entry->slug,
                ])->values()->all(),
            ],
        ];
    }

    private function actionsFor(NovaCard $card, string $status): array
    {
        $actions = [
            [
                'key' => 'duplicate',
                'label' => 'Duplicate',
                'icon' => 'fa-solid fa-id-card',
                'type' => 'request',
                'method' => 'post',
                'url' => route('api.cards.duplicate', ['id' => $card->id]),
                'redirect_pattern' => route('studio.cards.edit', ['id' => '__ID__']),
            ],
        ];

        if ($status === NovaCard::STATUS_DRAFT) {
            $actions[] = [
                'key' => 'delete',
                'label' => 'Delete draft',
                'icon' => 'fa-solid fa-trash',
                'type' => 'request',
                'method' => 'delete',
                'url' => route('api.cards.drafts.destroy', ['id' => $card->id]),
                'confirm' => 'Delete this card draft?',
            ];
        }

        if ($status === NovaCard::STATUS_SCHEDULED) {
            $actions[] = [
                'key' => 'publish_now',
                'label' => 'Publish now',
                'icon' => 'fa-solid fa-bolt',
                'type' => 'request',
                'method' => 'post',
                'url' => route('api.studio.schedule.publishNow', ['module' => 'cards', 'id' => $card->id]),
            ];
            $actions[] = [
                'key' => 'unschedule',
                'label' => 'Unschedule',
                'icon' => 'fa-solid fa-calendar-xmark',
                'type' => 'request',
                'method' => 'post',
                'url' => route('api.studio.schedule.unschedule', ['module' => 'cards', 'id' => $card->id]),
            ];
        }

        return $actions;
    }
}