<?php

declare(strict_types=1);

namespace App\Services\Studio;

use App\Models\Artwork;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Facades\Log;

/**
 * Handles artwork listing queries for Studio, using Meilisearch with DB fallback.
 */
final class StudioArtworkQueryService
{
    /**
     * List artworks for a creator with search, filter, and sort via Meilisearch.
     *
     * Supported $filters keys:
     *   q           string  — free-text search
     *   status      string  — published|draft|archived
     *   category    string  — category slug
     *   tags        array   — tag slugs
     *   date_from   string  — Y-m-d
     *   date_to     string  — Y-m-d
     *   performance string  — rising|top|low
     *   sort        string  — created_at:desc (default), ranking_score:desc, heat_score:desc, etc.
     */
    public function list(int $userId, array $filters = [], int $perPage = 24): LengthAwarePaginator
    {
        // Studio is a management dashboard — DB is always authoritative.
        // Draft/unpublished artworks are never indexed in Meilisearch, so using
        // Meili as the primary source would silently hide them.
        //
        // Meilisearch is only used when the user submits a free-text query (`q`),
        // since it can provide relevance-ranked full-text search across many docs.
        // Even then, we fall back to DB on any Meili error.

        $hasTextQuery = !empty($filters['q']);
        $driver = config('scout.driver');
        $useMeili = $hasTextQuery && !empty($driver) && $driver !== 'null';

        if ($useMeili) {
            try {
                return $this->listViaMeilisearch($userId, $filters, $perPage);
            } catch (\Throwable $e) {
                Log::warning('Studio: Meilisearch unavailable during text search, falling back to DB', [
                    'error' => $e->getMessage(),
                    'user_id' => $userId,
                ]);
                // fall through to DB
            }
        }

        return $this->listViaDatabase($userId, $filters, $perPage);
    }

    private function listViaMeilisearch(int $userId, array $filters, int $perPage): LengthAwarePaginator
    {
        $q = $filters['q'] ?? '';
        $filterParts = ["author_id = {$userId}"];
        $sort = [];

        // Status filter
        $status = $filters['status'] ?? null;
        if ($status === 'published') {
            $filterParts[] = 'is_public = true AND is_approved = true';
        } elseif ($status === 'draft') {
            $filterParts[] = 'is_public = false';
        }
        // archived handled at DB level since Meili doesn't see soft-deleted

        // Category filter
        if (!empty($filters['category'])) {
            $quoted = addslashes((string) $filters['category']);
            $filterParts[] = '(category = "' . $quoted . '" OR categories = "' . $quoted . '")';
        }

        // Tag filter
        if (!empty($filters['tags'])) {
            foreach ((array) $filters['tags'] as $tag) {
                $filterParts[] = 'tags = "' . addslashes((string) $tag) . '"';
            }
        }

        // Date range
        if (!empty($filters['date_from'])) {
            $filterParts[] = 'created_at >= "' . $filters['date_from'] . '"';
        }
        if (!empty($filters['date_to'])) {
            $filterParts[] = 'created_at <= "' . $filters['date_to'] . '"';
        }

        // Performance quick filters
        if (!empty($filters['performance'])) {
            match ($filters['performance']) {
                'rising' => $filterParts[] = 'heat_score > 5',
                'top'    => $filterParts[] = 'ranking_score > 50',
                'low'    => $filterParts[] = 'views < 10',
                default  => null,
            };
        }

        // Sort
        $sortParam = $filters['sort'] ?? 'created_at:desc';
        $validSortFields = [
            'created_at', 'ranking_score', 'heat_score',
            'views', 'likes', 'shares_count',
            'downloads', 'comments_count', 'favorites_count',
        ];
        $parts = explode(':', $sortParam);
        if (count($parts) === 2 && in_array($parts[0], $validSortFields, true)) {
            $sort[] = $parts[0] . ':' . ($parts[1] === 'asc' ? 'asc' : 'desc');
        }

        $options = ['filter' => implode(' AND ', $filterParts)];
        if ($sort !== []) {
            $options['sort'] = $sort;
        }

        return Artwork::search($q ?: '')
            ->options($options)
            ->query(fn (Builder $query) => $query
                ->with(['stats', 'categories', 'tags'])
                ->withCount(['comments', 'downloads'])
            )
            ->paginate($perPage);
    }

    private function listViaDatabase(int $userId, array $filters, int $perPage): LengthAwarePaginator
    {
        $query = Artwork::where('user_id', $userId)
            ->with(['stats', 'categories', 'tags'])
            ->withCount(['comments', 'downloads']);

        $status = $filters['status'] ?? null;
        if ($status === 'published') {
            $query->where('is_public', true)->where('is_approved', true);
        } elseif ($status === 'draft') {
            $query->where('is_public', false);
        } elseif ($status === 'archived') {
            $query->onlyTrashed();
        } else {
            // Show all except archived by default
            $query->whereNull('deleted_at');
        }

        // Free-text search
        if (!empty($filters['q'])) {
            $q = $filters['q'];
            $query->where(function (Builder $w) use ($q) {
                $w->where('title', 'LIKE', "%{$q}%")
                    ->orWhereHas('tags', fn (Builder $t) => $t->where('slug', 'LIKE', "%{$q}%"));
            });
        }

        // Category
        if (!empty($filters['category'])) {
            $query->whereHas('categories', fn (Builder $c) => $c->where('slug', $filters['category']));
        }

        // Tags
        if (!empty($filters['tags'])) {
            foreach ((array) $filters['tags'] as $tag) {
                $query->whereHas('tags', fn (Builder $t) => $t->where('slug', $tag));
            }
        }

        // Date range
        if (!empty($filters['date_from'])) {
            $query->where('created_at', '>=', $filters['date_from']);
        }
        if (!empty($filters['date_to'])) {
            $query->where('created_at', '<=', $filters['date_to']);
        }

        // Performance
        if (!empty($filters['performance'])) {
            $query->whereHas('stats', function (Builder $s) use ($filters) {
                match ($filters['performance']) {
                    'rising' => $s->where('heat_score', '>', 5),
                    'top'    => $s->where('ranking_score', '>', 50),
                    'low'    => $s->where('views', '<', 10),
                    default  => null,
                };
            });
        }

        // Sort
        $sortParam = $filters['sort'] ?? 'created_at:desc';
        $parts = explode(':', $sortParam);
        $sortField = $parts[0] ?? 'created_at';
        $sortDir = ($parts[1] ?? 'desc') === 'asc' ? 'asc' : 'desc';

        $dbSortMap = [
            'created_at'      => 'artworks.created_at',
            'ranking_score'   => 'ranking_score',
            'heat_score'      => 'heat_score',
            'views'           => 'views',
            'likes'           => 'favorites',
            'shares_count'    => 'shares_count',
            'downloads'       => 'downloads',
            'comments_count'  => 'comments_count',
            'favorites_count' => 'favorites',
        ];

        $statsSortFields = ['ranking_score', 'heat_score', 'views', 'likes', 'shares_count', 'downloads', 'comments_count', 'favorites_count'];

        if (in_array($sortField, $statsSortFields, true)) {
            $dbCol = $dbSortMap[$sortField] ?? $sortField;
            $query->leftJoin('artwork_stats', 'artworks.id', '=', 'artwork_stats.artwork_id')
                ->orderBy("artwork_stats.{$dbCol}", $sortDir)
                ->select('artworks.*');
        } else {
            $query->orderBy($dbSortMap[$sortField] ?? 'artworks.created_at', $sortDir);
        }

        return $query->paginate($perPage);
    }
}
