<?php

declare(strict_types=1);

namespace App\Http\Controllers\Api\Admin;

use App\Http\Controllers\Controller;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Symfony\Component\HttpFoundation\Response;

final class SimilarArtworkReportController extends Controller
{
    public function index(Request $request): JsonResponse
    {
        $validated = $request->validate([
            'from' => ['nullable', 'date_format:Y-m-d'],
            'to' => ['nullable', 'date_format:Y-m-d'],
            'limit' => ['nullable', 'integer', 'min:1', 'max:1000'],
        ]);

        $from = (string) ($validated['from'] ?? now()->subDays(29)->toDateString());
        $to = (string) ($validated['to'] ?? now()->toDateString());
        $limit = (int) ($validated['limit'] ?? 100);

        if ($from > $to) {
            return response()->json([
                'message' => 'Invalid date range: from must be before or equal to to.',
            ], Response::HTTP_UNPROCESSABLE_ENTITY);
        }

        $byAlgoRows = DB::table('similar_artwork_events')
            ->selectRaw('algo_version')
            ->selectRaw("SUM(CASE WHEN event_type = 'impression' THEN 1 ELSE 0 END) AS impressions")
            ->selectRaw("SUM(CASE WHEN event_type = 'click' THEN 1 ELSE 0 END) AS clicks")
            ->whereBetween('event_date', [$from, $to])
            ->groupBy('algo_version')
            ->orderBy('algo_version')
            ->get();

        $byAlgo = $byAlgoRows->map(static function ($row): array {
            $impressions = (int) ($row->impressions ?? 0);
            $clicks = (int) ($row->clicks ?? 0);
            $ctr = $impressions > 0 ? $clicks / $impressions : 0.0;

            return [
                'algo_version' => (string) $row->algo_version,
                'impressions' => $impressions,
                'clicks' => $clicks,
                'ctr' => round($ctr, 6),
            ];
        })->values();

        $pairRows = DB::table('similar_artwork_events as e')
            ->leftJoin('artworks as source', 'source.id', '=', 'e.source_artwork_id')
            ->leftJoin('artworks as similar', 'similar.id', '=', 'e.similar_artwork_id')
            ->selectRaw('e.algo_version')
            ->selectRaw('e.source_artwork_id')
            ->selectRaw('e.similar_artwork_id')
            ->selectRaw('source.title as source_title')
            ->selectRaw('similar.title as similar_title')
            ->selectRaw("SUM(CASE WHEN e.event_type = 'impression' THEN 1 ELSE 0 END) AS impressions")
            ->selectRaw("SUM(CASE WHEN e.event_type = 'click' THEN 1 ELSE 0 END) AS clicks")
            ->whereBetween('e.event_date', [$from, $to])
            ->whereNotNull('e.similar_artwork_id')
            ->groupBy('e.algo_version', 'e.source_artwork_id', 'e.similar_artwork_id', 'source.title', 'similar.title')
            ->get();

        $topSimilarities = $pairRows
            ->map(static function ($row): array {
                $impressions = (int) ($row->impressions ?? 0);
                $clicks = (int) ($row->clicks ?? 0);
                $ctr = $impressions > 0 ? $clicks / $impressions : 0.0;

                return [
                    'algo_version' => (string) $row->algo_version,
                    'source_artwork_id' => (int) $row->source_artwork_id,
                    'source_title' => (string) ($row->source_title ?? ''),
                    'similar_artwork_id' => (int) $row->similar_artwork_id,
                    'similar_title' => (string) ($row->similar_title ?? ''),
                    'impressions' => $impressions,
                    'clicks' => $clicks,
                    'ctr' => round($ctr, 6),
                ];
            })
            ->sort(function (array $a, array $b): int {
                $ctrCompare = $b['ctr'] <=> $a['ctr'];
                if ($ctrCompare !== 0) {
                    return $ctrCompare;
                }

                $clickCompare = $b['clicks'] <=> $a['clicks'];
                if ($clickCompare !== 0) {
                    return $clickCompare;
                }

                return $b['impressions'] <=> $a['impressions'];
            })
            ->take($limit)
            ->values();

        return response()->json([
            'meta' => [
                'from' => $from,
                'to' => $to,
                'generated_at' => now()->toISOString(),
                'limit' => $limit,
            ],
            'by_algo_version' => $byAlgo,
            'top_similarities' => $topSimilarities,
        ], Response::HTTP_OK);
    }
}
