<?php

declare(strict_types=1);

namespace App\Services;

use App\Models\Collection;

class CollectionObservabilityService
{
    public function surfaceCacheKey(string $surfaceKey, int $limit): string
    {
        return sprintf('collections:surface:%s:%d', $surfaceKey, $limit);
    }

    public function searchCacheKey(string $scope, array $filters): string
    {
        ksort($filters);

        return sprintf('collections:search:%s:%s', $scope, md5(json_encode($filters, JSON_THROW_ON_ERROR)));
    }

    public function diagnostics(Collection $collection): array
    {
        return [
            'collection_id' => (int) $collection->id,
            'workflow_state' => $collection->workflow_state,
            'health_state' => $collection->health_state,
            'placement_eligibility' => (bool) $collection->placement_eligibility,
            'experiment_key' => $collection->experiment_key,
            'experiment_treatment' => $collection->experiment_treatment,
            'placement_variant' => $collection->placement_variant,
            'ranking_mode_variant' => $collection->ranking_mode_variant,
            'collection_pool_version' => $collection->collection_pool_version,
            'test_label' => $collection->test_label,
            'partner_key' => $collection->partner_key,
            'trust_tier' => $collection->trust_tier,
            'promotion_tier' => $collection->promotion_tier,
            'sponsorship_state' => $collection->sponsorship_state,
            'ownership_domain' => $collection->ownership_domain,
            'commercial_review_state' => $collection->commercial_review_state,
            'legal_review_state' => $collection->legal_review_state,
            'ranking_bucket' => $collection->ranking_bucket,
            'recommendation_tier' => $collection->recommendation_tier,
            'last_health_check_at' => optional($collection->last_health_check_at)?->toISOString(),
            'last_recommendation_refresh_at' => optional($collection->last_recommendation_refresh_at)?->toISOString(),
        ];
    }

    public function summary(): array
    {
        $staleHealthCutoff = now()->subHours((int) config('collections.v5.queue.health_stale_after_hours', 24));
        $staleRecommendationCutoff = now()->subHours((int) config('collections.v5.queue.recommendation_stale_after_hours', 12));

        $watchlist = Collection::query()
            ->with([
                'user:id,username,name',
                'coverArtwork:id,user_id,title,slug,hash,thumb_ext,published_at,is_public,is_approved,deleted_at',
            ])
            ->whereIn('health_state', [
                Collection::HEALTH_NEEDS_REVIEW,
                Collection::HEALTH_DUPLICATE_RISK,
                Collection::HEALTH_MERGE_CANDIDATE,
                Collection::HEALTH_STALE,
            ])
            ->orderByDesc('updated_at')
            ->limit(6)
            ->get();

        return [
            'counts' => [
                'stale_health' => Collection::query()
                    ->where(function ($query) use ($staleHealthCutoff): void {
                        $query->whereNull('last_health_check_at')
                            ->orWhere('last_health_check_at', '<=', $staleHealthCutoff);
                    })
                    ->count(),
                'stale_recommendations' => Collection::query()
                    ->where('placement_eligibility', true)
                    ->where(function ($query) use ($staleRecommendationCutoff): void {
                        $query->whereNull('last_recommendation_refresh_at')
                            ->orWhere('last_recommendation_refresh_at', '<=', $staleRecommendationCutoff);
                    })
                    ->count(),
                'placement_blocked' => Collection::query()->where('placement_eligibility', false)->count(),
                'duplicate_risk' => Collection::query()->where('health_state', Collection::HEALTH_DUPLICATE_RISK)->count(),
            ],
            'watchlist' => app(CollectionService::class)->mapCollectionCardPayloads($watchlist, true),
            'generated_at' => now()->toISOString(),
        ];
    }
}