<?php

declare(strict_types=1);

namespace App\ApiClient\DTOs;

/**
 * Mirrors `GET /api/v1/admin/stats/dashboard`. The dashboard template
 * binds onto this directly — no per-page munging.
 */
final class DashboardStatsDto
{
    /**
     * @param list<array<string, mixed>>                                                 $reportsByHour entries shaped {hour, count}
     * @param list<array<string, mixed>>                                                 $topReporters  entries shaped {name, count}
     * @param list<array<string, mixed>>                                                 $topCategories entries shaped {slug, count}
     * @param array{days: list<string>, series: list<array{category: string, counts: list<int>}>} $blockedByDay
     * @param list<array<string, mixed>>                                                 $jobsStatus    entries shaped {name, last_finished_at, status, overdue}
     */
    public function __construct(
        public readonly int $activeBlocks,
        public readonly int $manualBlocksCount,
        public readonly int $allowlistCount,
        public readonly int $reports24h,
        public readonly array $reportsByHour,
        public readonly array $topReporters,
        public readonly array $topCategories,
        public readonly array $blockedByDay,
        public readonly array $jobsStatus,
        public readonly string $referencePolicy,
    ) {
    }

    /**
     * @param array<string, mixed> $payload
     */
    public static function fromArray(array $payload): self
    {
        return new self(
            activeBlocks: (int) ($payload['active_blocks'] ?? 0),
            manualBlocksCount: (int) ($payload['manual_blocks_count'] ?? 0),
            allowlistCount: (int) ($payload['allowlist_count'] ?? 0),
            reports24h: (int) ($payload['reports_24h'] ?? 0),
            reportsByHour: self::extractList($payload, 'reports_24h_by_hour'),
            topReporters: self::extractList($payload, 'top_reporters_24h'),
            topCategories: self::extractList($payload, 'top_categories_24h'),
            blockedByDay: self::extractBlocked($payload),
            jobsStatus: self::extractList($payload, 'jobs_status'),
            referencePolicy: (string) ($payload['reference_policy'] ?? 'moderate'),
        );
    }

    /**
     * @param array<string, mixed> $payload
     * @return array{days: list<string>, series: list<array{category: string, counts: list<int>}>}
     */
    private static function extractBlocked(array $payload): array
    {
        $raw = $payload['blocked_ips_by_day_7d'] ?? null;
        if (!is_array($raw)) {
            return ['days' => [], 'series' => []];
        }
        $days = [];
        foreach ((array) ($raw['days'] ?? []) as $d) {
            $days[] = (string) $d;
        }
        $series = [];
        foreach ((array) ($raw['series'] ?? []) as $row) {
            if (!is_array($row)) {
                continue;
            }
            $counts = [];
            foreach ((array) ($row['counts'] ?? []) as $c) {
                $counts[] = (int) $c;
            }
            $series[] = [
                'category' => (string) ($row['category'] ?? ''),
                'counts' => $counts,
            ];
        }

        return ['days' => $days, 'series' => $series];
    }

    /**
     * @param array<string, mixed> $payload
     * @return list<array<string, mixed>>
     */
    private static function extractList(array $payload, string $key): array
    {
        $value = $payload[$key] ?? [];
        if (!is_array($value)) {
            return [];
        }
        $out = [];
        foreach ($value as $row) {
            if (is_array($row)) {
                $out[] = $row;
            }
        }

        return $out;
    }
}
