<?php

declare(strict_types=1);

namespace SeoScope\Services;

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

    public const MAX_QUERIES = 25;

    /**
     * @param list<array<string, mixed>> $rows From {@see \SeoScope\Repositories\GscDecayRepository::listForRange()}
     * @param array{
     *   preset:string,
     *   device:string,
     *   country:string,
     *   cur_start:string,
     *   cur_end:string,
     *   prev_start:string,
     *   prev_end:string,
     *   min_impressions:int,
     *   clicks_drop_pct:float,
     *   impr_drop_pct:float,
     *   position_worsen:float,
     *   sort:string,
     *   dir:string,
     *   total_queries:int,
     * } $meta
     *
     * @return array{ready:bool, payload:array<string,mixed>}
     */
    public function build(array $rows, array $meta): array
    {
        $total = max(0, (int) ($meta['total_queries'] ?? 0));
        $normalized = [];
        foreach ($rows as $row) {
            if (!is_array($row)) {
                continue;
            }
            $q = trim((string) ($row['query'] ?? ''));
            if ($q === '') {
                continue;
            }
            $flags = $row['flags'] ?? [];
            if (!is_array($flags)) {
                $flags = [];
            }
            $flagList = [];
            foreach ($flags as $f) {
                $s = trim((string) $f);
                if ($s !== '') {
                    $flagList[] = $s;
                }
            }

            $normalized[] = [
                'query' => $q,
                'current_period' => [
                    'clicks' => max(0, (int) ($row['cur_clicks'] ?? 0)),
                    'impressions' => max(0, (int) ($row['cur_impressions'] ?? 0)),
                    'ctr' => round((float) ($row['cur_ctr'] ?? 0), 6),
                    'position' => round((float) ($row['cur_position'] ?? 0), 4),
                ],
                'previous_period' => [
                    'clicks' => max(0, (int) ($row['prev_clicks'] ?? 0)),
                    'impressions' => max(0, (int) ($row['prev_impressions'] ?? 0)),
                    'ctr' => round((float) ($row['prev_ctr'] ?? 0), 6),
                    'position' => round((float) ($row['prev_position'] ?? 0), 4),
                ],
                'change' => [
                    'clicks_pct' => round((float) ($row['d_clicks'] ?? 0), 6),
                    'impressions_pct' => round((float) ($row['d_impr'] ?? 0), 6),
                    'position_delta' => round((float) ($row['d_pos'] ?? 0), 4),
                ],
                'decay_flags' => $flagList,
            ];
            if (count($normalized) >= self::MAX_QUERIES) {
                break;
            }
        }

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

        $sumCurImpr = 0;
        $sumCurClicks = 0;
        foreach ($normalized as $k) {
            $sumCurImpr += (int) ($k['current_period']['impressions'] ?? 0);
            $sumCurClicks += (int) ($k['current_period']['clicks'] ?? 0);
        }

        $payload = [
            'schema_version' => self::SCHEMA_VERSION,
            'context' => 'decay_report',
            'filters' => [
                'preset' => (string) ($meta['preset'] ?? 'last_28_days'),
                'device' => (string) ($meta['device'] ?? 'all'),
                'country' => (string) ($meta['country'] ?? 'all'),
            ],
            'period' => [
                'current' => [
                    'start' => (string) ($meta['cur_start'] ?? ''),
                    'end' => (string) ($meta['cur_end'] ?? ''),
                ],
                'previous' => [
                    'start' => (string) ($meta['prev_start'] ?? ''),
                    'end' => (string) ($meta['prev_end'] ?? ''),
                ],
            ],
            'thresholds' => [
                'min_impressions' => max(0, (int) ($meta['min_impressions'] ?? 0)),
                'clicks_drop_pct' => round(max(0.0, (float) ($meta['clicks_drop_pct'] ?? 0)), 4),
                'impr_drop_pct' => round(max(0.0, (float) ($meta['impr_drop_pct'] ?? 0)), 4),
                'position_worsen' => round(max(0.0, (float) ($meta['position_worsen'] ?? 0)), 4),
            ],
            'sort' => [
                'column' => (string) ($meta['sort'] ?? 'd_clicks'),
                'direction' => strtoupper((string) ($meta['dir'] ?? 'ASC')) === 'ASC' ? 'ASC' : 'DESC',
            ],
            'portfolio' => [
                'total_decay_queries' => $total,
                'rows_sent_to_model' => count($normalized),
                'sum_current_impressions_top' => $sumCurImpr,
                'sum_current_clicks_top' => $sumCurClicks,
            ],
            'queries' => $normalized,
            'model_notes' => [
                'decay_meaning' => 'Each row is a query that declined vs the prior period of equal length: clicks drop, impressions drop, and/or position worsened beyond configured thresholds. decay_flags shows which rules matched.',
                'constraints' => 'Interpret only listed queries and portfolio fields. Do not invent landing URLs (not provided).',
            ],
        ];

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