<?php

declare(strict_types=1);

namespace SeoScope\Services;

/**
 * Builds LLM payload for Cannibalization report SEO AI Assistant.
 */
final class SeoAiCannibalizationPayloadService
{
    public const SCHEMA_VERSION = 1;

    public const MAX_CASES = 25;

    public const MAX_PAGES_PER_QUERY = 8;

    /**
     * @param list<array<string, mixed>> $rows From {@see \SeoScope\Repositories\GscCannibalizationRepository::listForRange()}
     * @param array{
     *   preset:string,
     *   device:string,
     *   country:string,
     *   range_start:string,
     *   range_end:string,
     *   min_impressions:int,
     *   min_pages:int,
     *   sort:string,
     *   dir:string,
     *   total_cases:int,
     * } $meta
     *
     * @return array{ready:bool, payload:array<string,mixed>}
     */
    public function build(array $rows, array $meta): array
    {
        $total = max(0, (int) ($meta['total_cases'] ?? 0));
        $normalized = [];
        foreach ($rows as $row) {
            if (!is_array($row)) {
                continue;
            }
            $q = trim((string) ($row['query'] ?? ''));
            if ($q === '') {
                continue;
            }
            $topPages = [];
            $rawPages = $row['top_pages'] ?? [];
            if (is_array($rawPages)) {
                foreach ($rawPages as $p) {
                    if (!is_array($p)) {
                        continue;
                    }
                    $page = trim((string) ($p['page'] ?? ''));
                    if ($page === '') {
                        continue;
                    }
                    $topPages[] = [
                        'page' => $page,
                        'clicks' => max(0, (int) ($p['clicks'] ?? 0)),
                        'impressions' => max(0, (int) ($p['impressions'] ?? 0)),
                        'share_clicks' => round((float) ($p['share_clicks'] ?? 0), 4),
                        'share_impressions' => round((float) ($p['share_impressions'] ?? 0), 4),
                    ];
                    if (count($topPages) >= self::MAX_PAGES_PER_QUERY) {
                        break;
                    }
                }
            }

            $normalized[] = [
                'query' => $q,
                'total_clicks' => max(0, (int) ($row['total_clicks'] ?? 0)),
                'total_impressions' => max(0, (int) ($row['total_impressions'] ?? 0)),
                'total_ctr' => round((float) ($row['total_ctr'] ?? 0), 6),
                'total_position' => round((float) ($row['total_position'] ?? 0), 4),
                'pages_count' => max(0, (int) ($row['pages_count'] ?? 0)),
                'top_pages' => $topPages,
            ];
            if (count($normalized) >= self::MAX_CASES) {
                break;
            }
        }

        $ready = $total > 0 && $normalized !== [];

        $sumImpr = 0;
        $sumClicks = 0;
        $sumPages = 0;
        foreach ($normalized as $c) {
            $sumImpr += (int) $c['total_impressions'];
            $sumClicks += (int) $c['total_clicks'];
            $sumPages += (int) $c['pages_count'];
        }

        $payload = [
            'schema_version' => self::SCHEMA_VERSION,
            'context' => 'cannibalization_report',
            'filters' => [
                'preset' => (string) ($meta['preset'] ?? 'last_28_days'),
                'device' => (string) ($meta['device'] ?? 'all'),
                'country' => (string) ($meta['country'] ?? 'all'),
            ],
            'period' => [
                'start' => (string) ($meta['range_start'] ?? ''),
                'end' => (string) ($meta['range_end'] ?? ''),
            ],
            'thresholds' => [
                'min_impressions' => (int) ($meta['min_impressions'] ?? 0),
                'min_pages' => max(2, (int) ($meta['min_pages'] ?? 2)),
            ],
            'sort' => [
                'column' => (string) ($meta['sort'] ?? 'impressions'),
                'direction' => strtoupper((string) ($meta['dir'] ?? 'DESC')) === 'ASC' ? 'ASC' : 'DESC',
            ],
            'portfolio' => [
                'total_cases' => $total,
                'rows_sent_to_model' => count($normalized),
                'sum_impressions_top' => $sumImpr,
                'sum_clicks_top' => $sumClicks,
                'avg_competing_pages_top' => count($normalized) > 0 ? round($sumPages / count($normalized), 2) : null,
            ],
            'cases' => $normalized,
            'model_notes' => [
                'cannibalization_meaning' => 'Each case is a search query with multiple landing URLs competing in the same period. Top pages show impression/click share per URL.',
                'constraints' => 'Interpret only listed queries and page URLs. Do not invent metrics beyond the JSON.',
            ],
        ];

        return ['ready' => $ready, 'payload' => $payload];
    }
}
