<?php

declare(strict_types=1);

namespace App\Services\Studio\Providers;

use App\Models\Artwork;
use App\Models\ArtworkStats;
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 ArtworkStudioProvider implements CreatorStudioProvider
{
    public function key(): string
    {
        return 'artworks';
    }

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

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

    public function createUrl(): string
    {
        return '/upload';
    }

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

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

        $count = (clone $baseQuery)
            ->whereNull('deleted_at')
            ->count();

        $draftCount = (clone $baseQuery)
            ->whereNull('deleted_at')
            ->where(function (Builder $query): void {
                $query->whereNull('artwork_status')
                    ->orWhere('artwork_status', '!=', 'scheduled');
            })
            ->where('is_public', false)
            ->count();

        $publishedCount = (clone $baseQuery)
            ->whereNull('deleted_at')
            ->where('is_public', true)
            ->whereNotNull('published_at')
            ->count();

        $recentPublishedCount = (clone $baseQuery)
            ->whereNull('deleted_at')
            ->where('is_public', true)
            ->where('published_at', '>=', now()->subDays(30))
            ->count();

        $archivedCount = Artwork::onlyTrashed()
            ->where('user_id', $user->id)
            ->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' => 'Upload artwork',
            'index_url' => $this->indexUrl(),
            'create_url' => $this->createUrl(),
        ];
    }

    public function items(User $user, string $bucket = 'all', int $limit = 200): Collection
    {
        $query = Artwork::query()
            ->withTrashed()
            ->where('user_id', $user->id)
            ->with([
                'stats',
                'categories',
                'tags',
                'features' => function ($query): void {
                    $query->where('is_active', true)
                        ->whereNull('deleted_at')
                        ->where(function (Builder $builder): void {
                            $builder->whereNull('expires_at')
                                ->orWhere('expires_at', '>', now());
                        });
                },
            ])
            ->orderByDesc('updated_at')
            ->limit($limit);

        if ($bucket === 'drafts') {
            $query->whereNull('deleted_at')
                ->where(function (Builder $builder): void {
                    $builder->whereNull('artwork_status')
                        ->orWhere('artwork_status', '!=', 'scheduled');
                })
                ->where('is_public', false);
        } elseif ($bucket === 'scheduled') {
            $query->whereNull('deleted_at')
                ->where('artwork_status', 'scheduled');
        } elseif ($bucket === 'archived') {
            $query->onlyTrashed();
        } elseif ($bucket === 'published') {
            $query->whereNull('deleted_at')
                ->where('is_public', true)
                ->whereNotNull('published_at');
        } else {
            $query->whereNull('deleted_at');
        }

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

    public function topItems(User $user, int $limit = 5): Collection
    {
        return Artwork::query()
            ->where('user_id', $user->id)
            ->whereNull('deleted_at')
            ->where('is_public', true)
            ->with(['stats', 'categories', 'tags'])
            ->whereHas('stats')
            ->orderByDesc(
                ArtworkStats::select('ranking_score')
                    ->whereColumn('artwork_stats.artwork_id', 'artworks.id')
                    ->limit(1)
            )
            ->limit($limit)
            ->get()
            ->map(fn (Artwork $artwork): array => $this->mapItem($artwork));
    }

    public function analytics(User $user): array
    {
        $totals = DB::table('artwork_stats')
            ->join('artworks', 'artworks.id', '=', 'artwork_stats.artwork_id')
            ->where('artworks.user_id', $user->id)
            ->whereNull('artworks.deleted_at')
            ->selectRaw('COALESCE(SUM(artwork_stats.views), 0) as views')
            ->selectRaw('COALESCE(SUM(artwork_stats.favorites), 0) as appreciation')
            ->selectRaw('COALESCE(SUM(artwork_stats.shares_count), 0) as shares')
            ->selectRaw('COALESCE(SUM(artwork_stats.comments_count), 0) as comments')
            ->selectRaw('COALESCE(SUM(artwork_stats.downloads), 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(Artwork $artwork): array
    {
        $stats = $artwork->stats;
        $status = $artwork->deleted_at
            ? 'archived'
            : ($artwork->artwork_status === 'scheduled'
                ? 'scheduled'
                : ((bool) $artwork->is_public ? 'published' : 'draft'));

        $category = $artwork->categories->first();
        $visibility = $artwork->visibility ?: ((bool) $artwork->is_public ? Artwork::VISIBILITY_PUBLIC : Artwork::VISIBILITY_PRIVATE);

        return [
            'id' => sprintf('%s:%d', $this->key(), (int) $artwork->id),
            'numeric_id' => (int) $artwork->id,
            'module' => $this->key(),
            'module_label' => $this->label(),
            'module_icon' => $this->icon(),
            'title' => $artwork->title,
            'subtitle' => $category?->name,
            'description' => $artwork->description,
            'status' => $status,
            'visibility' => $visibility,
            'image_url' => $artwork->thumbUrl('md'),
            'preview_url' => $artwork->published_at ? route('art.show', ['id' => $artwork->id, 'slug' => $artwork->slug]) : route('studio.artworks.edit', ['id' => $artwork->id]),
            'view_url' => $artwork->published_at ? route('art.show', ['id' => $artwork->id, 'slug' => $artwork->slug]) : route('studio.artworks.edit', ['id' => $artwork->id]),
            'edit_url' => route('studio.artworks.edit', ['id' => $artwork->id]),
            'manage_url' => route('studio.artworks.edit', ['id' => $artwork->id]),
            'analytics_url' => route('studio.artworks.analytics', ['id' => $artwork->id]),
            'create_url' => $this->createUrl(),
            'actions' => $this->actionsFor($artwork, $status),
            'created_at' => $artwork->created_at?->toIso8601String(),
            'updated_at' => $artwork->updated_at?->toIso8601String(),
            'published_at' => $artwork->published_at?->toIso8601String(),
            'scheduled_at' => $artwork->publish_at?->toIso8601String(),
            'schedule_timezone' => $artwork->artwork_timezone,
            'featured' => $artwork->features->isNotEmpty(),
            'metrics' => [
                'views' => (int) ($stats?->views ?? 0),
                'appreciation' => (int) ($stats?->favorites ?? 0),
                'shares' => (int) ($stats?->shares_count ?? 0),
                'comments' => (int) ($stats?->comments_count ?? 0),
                'saves' => (int) ($stats?->downloads ?? 0),
            ],
            'engagement_score' => (int) ($stats?->views ?? 0)
                + ((int) ($stats?->favorites ?? 0) * 2)
                + ((int) ($stats?->comments_count ?? 0) * 3)
                + ((int) ($stats?->shares_count ?? 0) * 2),
            'taxonomies' => [
                'categories' => $artwork->categories->map(fn ($entry): array => [
                    'id' => (int) $entry->id,
                    'name' => (string) $entry->name,
                    'slug' => (string) $entry->slug,
                ])->values()->all(),
                'tags' => $artwork->tags->map(fn ($entry): array => [
                    'id' => (int) $entry->id,
                    'name' => (string) $entry->name,
                    'slug' => (string) $entry->slug,
                ])->values()->all(),
            ],
        ];
    }

    private function actionsFor(Artwork $artwork, string $status): array
    {
        $actions = [];

        if ($status === 'draft') {
            $actions[] = $this->requestAction('publish', 'Publish', 'fa-solid fa-rocket', route('api.studio.artworks.toggle', ['id' => $artwork->id]), ['action' => 'publish']);
        }

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

        if ($status === 'published') {
            $actions[] = $this->requestAction('unpublish', 'Unpublish', 'fa-solid fa-eye-slash', route('api.studio.artworks.toggle', ['id' => $artwork->id]), ['action' => 'unpublish']);
            $actions[] = $this->requestAction('archive', 'Archive', 'fa-solid fa-box-archive', route('api.studio.artworks.toggle', ['id' => $artwork->id]), ['action' => 'archive']);
        }

        if ($status === 'archived') {
            $actions[] = $this->requestAction('restore', 'Restore', 'fa-solid fa-rotate-left', route('api.studio.artworks.toggle', ['id' => $artwork->id]), ['action' => 'unarchive']);
        }

        $actions[] = $this->requestAction(
            'delete',
            'Delete',
            'fa-solid fa-trash',
            route('api.studio.artworks.bulk'),
            [
                'action' => 'delete',
                'artwork_ids' => [$artwork->id],
                'confirm' => 'DELETE',
            ],
            'Delete this artwork permanently?'
        );

        return $actions;
    }

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