<?php

namespace App\Services;

use CodeIgniter\Shield\Entities\User;
use DateTimeImmutable;

class ReportService
{
    private AttendanceService $attendanceService;
    private AuthorizationService $authorizationService;

    public function __construct()
    {
        helper(['academy', 'url']);

        $this->attendanceService    = service('attendance');
        $this->authorizationService = service('authorization');
    }

    /**
     * @param array<string, mixed> $input
     * @return array<string, mixed>
     */
    public function getIndexData(array $input, User $user): array
    {
        $payload = $this->buildPayload($input, (int) $user->id);

        return [
            'pageTitle' => 'Rapoarte',
            'pageDescription' => 'Set de rapoarte operationale filtrabile pentru administratie, training si discutii de promovare.',
            'filters' => $payload['filters'],
            'report' => $payload['report'],
            'appliedFilters' => $payload['applied_filters'],
            'exportUrls' => $this->buildExportUrls($payload['filters']),
        ];
    }

    /**
     * @param array<string, mixed> $input
     * @return array<string, mixed>
     */
    public function getExportData(array $input, User $user): array
    {
        $payload     = $this->buildPayload($input, (int) $user->id);
        $generatedAt = new DateTimeImmutable('now');

        return array_merge($payload, [
            'generated_at_label' => $generatedAt->format('d.m.Y H:i'),
            'file_basename' => $this->buildFileBasename($payload['filters'], $generatedAt),
        ]);
    }

    /**
     * @param array<string, mixed> $exportData
     */
    public function buildCsv(array $exportData): string
    {
        $stream = fopen('php://temp', 'r+');
        if ($stream === false) {
            return '';
        }

        fwrite($stream, "\xEF\xBB\xBF");

        fputcsv($stream, [$exportData['report']['title'] ?? 'Raport'], ';');
        fputcsv($stream, ['Descriere', (string) ($exportData['report']['description'] ?? '')], ';');
        fputcsv($stream, ['Generat la', (string) ($exportData['generated_at_label'] ?? '')], ';');

        foreach ((array) ($exportData['applied_filters'] ?? []) as $filter) {
            fputcsv($stream, [(string) ($filter['label'] ?? ''), (string) ($filter['value'] ?? '')], ';');
        }

        if (! empty($exportData['report']['summary'])) {
            fwrite($stream, PHP_EOL);
            fputcsv($stream, ['Rezumat'], ';');
            foreach ($exportData['report']['summary'] as $item) {
                fputcsv($stream, [
                    (string) ($item['label'] ?? ''),
                    $this->stringValue($item['value'] ?? null),
                    (string) ($item['meta'] ?? ''),
                ], ';');
            }
        }

        fwrite($stream, PHP_EOL);

        $columns = (array) ($exportData['report']['columns'] ?? []);
        $rows    = (array) ($exportData['report']['rows'] ?? []);

        if ($rows === []) {
            $columns = $columns !== [] ? $columns : ['Mesaj'];
            fputcsv($stream, $columns, ';');
            fputcsv($stream, [(string) ($exportData['report']['empty'] ?? 'Nu exista date pentru export.')], ';');
        } else {
            fputcsv($stream, $columns, ';');
            foreach ($rows as $row) {
                $line = [];
                foreach ($columns as $column) {
                    $line[] = $this->stringValue($row[$column] ?? '-');
                }

                fputcsv($stream, $line, ';');
            }
        }

        rewind($stream);
        $csv = stream_get_contents($stream) ?: '';
        fclose($stream);

        return $csv;
    }

    /**
     * @param array<string, mixed> $input
     * @return array<string, mixed>
     */
    private function buildPayload(array $input, int $userId): array
    {
        $filters = $this->buildFilters($input, $userId);
        $report  = $this->buildReport($filters);

        return [
            'filters' => $filters,
            'report' => $report,
            'applied_filters' => $this->buildAppliedFilters($filters),
        ];
    }

    /**
     * @param array<string, mixed> $input
     * @return array<string, mixed>
     */
    private function buildFilters(array $input, int $userId): array
    {
        $settings       = $this->settingsMap();
        $role           = $this->authorizationService->getPrimaryRole($userId);
        $lockedTrainerId  = $role === 'coach' ? $this->authorizationService->getCoachIdForUser($userId) : null;
        $selectedReport = (string) ($input['report'] ?? 'children-by-level');
        $selectedPeriod = (string) ($input['period'] ?? ($settings['default_dashboard_period'] ?? '30'));
        if ($selectedPeriod !== 'month' && ! in_array((int) $selectedPeriod, [7, 30, 90], true)) {
            $selectedPeriod = '30';
        }
        [$dateStart, $dateEnd] = $this->resolveDates($selectedPeriod, new DateTimeImmutable('today'));
        $selectedTrainer  = $lockedTrainerId ?: (int) ($input['coach_id'] ?? 0);
        $selectedLevel  = (int) ($input['level_id'] ?? 0);
        $selectedStatus = (string) ($input['child_status'] ?? 'all');
        $selectedChild  = (int) ($input['child_id'] ?? 0);

        if (! in_array($selectedReport, ['children-by-level', 'children-by-coach', 'ready-for-promotion', 'almost-ready', 'high-absence', 'evaluations-period', 'child-progress'], true)) {
            $selectedReport = 'children-by-level';
        }

        if (! in_array($selectedStatus, ['all', 'active', 'pause', 'left'], true)) {
            $selectedStatus = 'all';
        }

        return [
            'current_role' => $role,
            'coach_locked' => $lockedTrainerId !== null,
            'selected_report' => $selectedReport,
            'selected_period' => $selectedPeriod,
            'selected_coach_id' => $selectedTrainer,
            'selected_level_id' => $selectedLevel,
            'selected_child_status' => $selectedStatus,
            'selected_child_id' => $selectedChild,
            'date_start' => $dateStart,
            'date_end' => $dateEnd,
            'report_options' => [
                'children-by-level' => 'Copii pe nivel',
                'children-by-coach' => 'Copii pe trainer',
                'ready-for-promotion' => 'Ready pentru avansare',
                'almost-ready' => 'Aproape gata',
                'high-absence' => 'Absente ridicate',
                'evaluations-period' => 'Evaluari pe perioada',
                'child-progress' => 'Progres pe copil',
            ],
            'period_options' => [
                '7' => 'Ultimele 7 zile',
                '30' => 'Ultimele 30 zile',
                '90' => 'Ultimele 90 zile',
                'month' => 'Luna curenta',
            ],
            'status_options' => [
                'all' => 'Toate statusurile',
                'active' => 'Activ',
                'pause' => 'Pauza',
                'left' => 'Plecat',
            ],
            'coach_options' => $this->coachOptions($lockedTrainerId),
            'level_options' => $this->levelOptions(),
            'child_options' => $this->childOptions($lockedTrainerId),
            'absence_alert_threshold' => (int) ($settings['absence_alert_threshold'] ?? 25),
        ];
    }

    /**
     * @return array{0: string, 1: string}
     */
    private function resolveDates(string $selectedPeriod, DateTimeImmutable $today): array
    {
        if ($selectedPeriod === 'month') {
            return [
                $today->modify('first day of this month')->format('Y-m-d'),
                $today->format('Y-m-d'),
            ];
        }

        $days = (int) $selectedPeriod;
        if (! in_array($days, [7, 30, 90], true)) {
            $days = 30;
        }

        return [
            $today->modify('-' . ($days - 1) . ' days')->format('Y-m-d'),
            $today->format('Y-m-d'),
        ];
    }

    /**
     * @param array<string, mixed> $filters
     * @return array<string, mixed>
     */
    private function buildReport(array $filters): array
    {
        $children = $this->scopedChildren($filters);

        return match ($filters['selected_report']) {
            'children-by-coach' => $this->reportChildrenByCoach($children),
            'ready-for-promotion' => $this->reportPromotionStatus($children, 'READY'),
            'almost-ready' => $this->reportPromotionStatus($children, 'ALMOST READY'),
            'high-absence' => $this->reportHighAbsence($children, $filters),
            'evaluations-period' => $this->reportEvaluations($children, $filters),
            'child-progress' => $this->reportChildProgress($children, $filters),
            default => $this->reportChildrenByLevel($children),
        };
    }

    /**
     * @param array<string, mixed> $filters
     * @return list<array<string, mixed>>
     */
    private function scopedChildren(array $filters): array
    {
        $builder = db_connect()
            ->table('children c')
            ->select('c.id, c.full_name, c.status, levels.name as level_name, groups.name as group_name, coaches.full_name as coach_name')
            ->join('academy_levels levels', 'levels.id = c.academy_level_id', 'left')
            ->join('academy_groups groups', 'groups.id = c.academy_group_id', 'left')
            ->join('coaches', 'coaches.id = c.primary_coach_id', 'left')
            ->orderBy('c.full_name', 'ASC');

        if ($filters['selected_coach_id'] > 0) {
            $builder->where('c.primary_coach_id', $filters['selected_coach_id']);
        }

        if ($filters['selected_level_id'] > 0) {
            $builder->where('c.academy_level_id', $filters['selected_level_id']);
        }

        if ($filters['selected_child_status'] !== 'all') {
            $builder->where('c.status', $filters['selected_child_status']);
        }

        return $builder->get()->getResultArray();
    }

    /**
     * @param list<array<string, mixed>> $children
     * @return array<string, mixed>
     */
    private function reportChildrenByLevel(array $children): array
    {
        $grouped = [];
        foreach ($children as $child) {
            $level = $child['level_name'] ?: 'Neasignat';
            if (! isset($grouped[$level])) {
                $grouped[$level] = ['level_name' => $level, 'children' => 0, 'active' => 0];
            }

            $grouped[$level]['children']++;
            if ($child['status'] === 'active') {
                $grouped[$level]['active']++;
            }
        }
        ksort($grouped);

        return [
            'title' => 'Copii pe nivel',
            'description' => 'Structura curenta a academiei pe niveluri active si statusuri operationale.',
            'columns' => ['Nivel', 'Total copii', 'Activi'],
            'rows' => array_values(array_map(static fn (array $row): array => [
                'Nivel' => $row['level_name'],
                'Total copii' => (string) $row['children'],
                'Activi' => (string) $row['active'],
            ], $grouped)),
            'summary' => [
                ['label' => 'Niveluri cu copii', 'value' => count($grouped), 'meta' => 'Doar niveluri cu date in selectie'],
                ['label' => 'Copii in raport', 'value' => count($children), 'meta' => 'Total randuri incluse'],
            ],
            'empty' => 'Nu exista copii pentru filtrele selectate.',
        ];
    }

    /**
     * @param list<array<string, mixed>> $children
     * @return array<string, mixed>
     */
    private function reportChildrenByCoach(array $children): array
    {
        $grouped = [];
        foreach ($children as $child) {
            $coach = $child['coach_name'] ?: 'Neasignat';
            if (! isset($grouped[$coach])) {
                $grouped[$coach] = ['coach_name' => $coach, 'children' => 0, 'active' => 0];
            }

            $grouped[$coach]['children']++;
            if ($child['status'] === 'active') {
                $grouped[$coach]['active']++;
            }
        }
        ksort($grouped);

        return [
            'title' => 'Copii pe trainer',
            'description' => 'Incarcarea actuala pe trainer, folosind asignarea principala a copilului.',
            'columns' => ['Trainer', 'Total copii', 'Activi'],
            'rows' => array_values(array_map(static fn (array $row): array => [
                'Trainer' => $row['coach_name'],
                'Total copii' => (string) $row['children'],
                'Activi' => (string) $row['active'],
            ], $grouped)),
            'summary' => [
                ['label' => 'Traineri in selectie', 'value' => count($grouped), 'meta' => 'Cu cel putin un copil in raport'],
                ['label' => 'Copii activi', 'value' => count(array_filter($children, static fn (array $child): bool => $child['status'] === 'active')), 'meta' => 'Activi in selectie'],
            ],
            'empty' => 'Nu exista copii pentru filtrele selectate.',
        ];
    }

    /**
     * @param list<array<string, mixed>> $children
     * @return array<string, mixed>
     */
    private function reportPromotionStatus(array $children, string $targetStatus): array
    {
        $childIds = array_values(array_map(static fn (array $child): int => (int) $child['id'], $children));
        $latest   = $this->latestFullEvaluations($childIds);
        $rows     = [];

        foreach ($children as $child) {
            $evaluation = $latest[(int) $child['id']] ?? null;
            if ($evaluation === null || $evaluation['final_status'] !== $targetStatus) {
                continue;
            }

            $rows[] = [
                'Copil' => $child['full_name'],
                'Nivel' => $child['level_name'] ?: '-',
                'Trainer' => $child['coach_name'] ?: '-',
                'Data evaluarii' => $evaluation['evaluation_date'],
                'Scor final' => format_score($evaluation['final_score']),
            ];
        }

        return [
            'title' => $targetStatus === 'READY' ? 'Copii ready pentru avansare' : 'Copii aproape gata',
            'description' => 'Ultimul full evaluation este folosit ca sursa de adevar pentru statusul de promovare.',
            'columns' => ['Copil', 'Nivel', 'Trainer', 'Data evaluarii', 'Scor final'],
            'rows' => $rows,
            'summary' => [
                ['label' => 'Copii in raport', 'value' => count($rows), 'meta' => $targetStatus],
            ],
            'empty' => 'Nu exista copii care sa corespunda acestui status in selectie.',
        ];
    }

    /**
     * @param list<array<string, mixed>> $children
     * @param array<string, mixed> $filters
     * @return array<string, mixed>
     */
    private function reportHighAbsence(array $children, array $filters): array
    {
        $childIds = array_values(array_map(static fn (array $child): int => (int) $child['id'], $children));
        $rows     = db_connect()
            ->table('attendance_records ar')
            ->select('ar.child_id, ar.status')
            ->join('attendance_sessions sessions', 'sessions.id = ar.attendance_session_id')
            ->whereIn('ar.child_id', $childIds === [] ? [0] : $childIds)
            ->where('sessions.is_cancelled', 0)
            ->where('sessions.session_date >=', $filters['date_start'])
            ->where('sessions.session_date <=', $filters['date_end'])
            ->get()
            ->getResultArray();

        $byChild = [];
        foreach ($rows as $row) {
            $childId = (int) $row['child_id'];
            if (! isset($byChild[$childId])) {
                $byChild[$childId] = ['present' => 0, 'recovery' => 0, 'absent_excused' => 0, 'absent_unexcused' => 0];
            }

            $byChild[$childId][$row['status']]++;
        }

        $reportRows = [];
        foreach ($children as $child) {
            $breakdown = $byChild[(int) $child['id']] ?? ['present' => 0, 'recovery' => 0, 'absent_excused' => 0, 'absent_unexcused' => 0];
            if (array_sum($breakdown) === 0) {
                continue;
            }

            $attendance = $this->attendanceService->calculateRateFromBreakdown($breakdown);
            $absence    = 100 - $attendance;

            if ($absence < (float) $filters['absence_alert_threshold']) {
                continue;
            }

            $reportRows[] = [
                'Copil' => $child['full_name'],
                'Grupa' => $child['group_name'] ?: '-',
                'Trainer' => $child['coach_name'] ?: '-',
                'Prezenta' => format_percentage($attendance, 1),
                'Absenta' => format_percentage($absence, 1),
            ];
        }

        return [
            'title' => 'Copii cu absente ridicate',
            'description' => 'Absenta este calculata in perioada filtrata, excluzand sesiunile anulate.',
            'columns' => ['Copil', 'Grupa', 'Trainer', 'Prezenta', 'Absenta'],
            'rows' => $reportRows,
            'summary' => [
                ['label' => 'Peste prag', 'value' => count($reportRows), 'meta' => 'Prag ' . format_percentage((float) $filters['absence_alert_threshold'], 0)],
            ],
            'empty' => 'Nu exista copii cu absente peste prag in perioada filtrata.',
        ];
    }

    /**
     * @param list<array<string, mixed>> $children
     * @param array<string, mixed> $filters
     * @return array<string, mixed>
     */
    private function reportEvaluations(array $children, array $filters): array
    {
        $childIds = array_values(array_map(static fn (array $child): int => (int) $child['id'], $children));
        $rows     = db_connect()
            ->table('evaluations e')
            ->select('e.evaluation_date, e.final_score, e.final_status, children.full_name as child_name, types.name as type_name, coaches.full_name as evaluator_name')
            ->join('children', 'children.id = e.child_id')
            ->join('evaluation_types types', 'types.id = e.evaluation_type_id')
            ->join('coaches', 'coaches.id = e.evaluator_coach_id', 'left')
            ->whereIn('e.child_id', $childIds === [] ? [0] : $childIds)
            ->where('e.evaluation_date >=', $filters['date_start'])
            ->where('e.evaluation_date <=', $filters['date_end'])
            ->orderBy('e.evaluation_date', 'DESC')
            ->orderBy('e.id', 'DESC')
            ->get()
            ->getResultArray();

        return [
            'title' => 'Evaluari pe perioada',
            'description' => 'Lista cronologica de evaluari quick si full pentru perioada selectata.',
            'columns' => ['Data', 'Copil', 'Tip', 'Evaluator', 'Scor', 'Status'],
            'rows' => array_map(static fn (array $row): array => [
                'Data' => $row['evaluation_date'],
                'Copil' => $row['child_name'],
                'Tip' => $row['type_name'],
                'Evaluator' => $row['evaluator_name'] ?: '-',
                'Scor' => format_score($row['final_score']),
                'Status' => status_label($row['final_status']),
            ], $rows),
            'summary' => [
                ['label' => 'Evaluari in raport', 'value' => count($rows), 'meta' => $filters['date_start'] . ' - ' . $filters['date_end']],
            ],
            'empty' => 'Nu exista evaluari in perioada selectata.',
        ];
    }

    /**
     * @param list<array<string, mixed>> $children
     * @param array<string, mixed> $filters
     * @return array<string, mixed>
     */
    private function reportChildProgress(array $children, array $filters): array
    {
        $selectedChildId = (int) $filters['selected_child_id'];
        if ($selectedChildId === 0 && $children !== []) {
            $selectedChildId = (int) $children[0]['id'];
        }

        if ($selectedChildId === 0) {
            return [
                'title' => 'Progres pe copil',
                'description' => 'Selecteaza un copil din filtru pentru a vedea istoricul evaluarilor si prezentei.',
                'columns' => [],
                'rows' => [],
                'summary' => [],
                'empty' => 'Nu exista copii disponibili pentru acest raport.',
            ];
        }

        $selectedChild = array_values(array_filter($children, static fn (array $child): bool => (int) $child['id'] === $selectedChildId))[0] ?? null;
        if ($selectedChild === null) {
            return [
                'title' => 'Progres pe copil',
                'description' => 'Copilul selectat nu este disponibil in aria curenta de acces.',
                'columns' => [],
                'rows' => [],
                'summary' => [],
                'empty' => 'Selectia curenta nu este valida.',
            ];
        }

        $evaluations = db_connect()
            ->table('evaluations e')
            ->select('e.evaluation_date, e.final_score, e.final_status, types.name as type_name')
            ->join('evaluation_types types', 'types.id = e.evaluation_type_id')
            ->where('e.child_id', $selectedChildId)
            ->orderBy('e.evaluation_date', 'DESC')
            ->orderBy('e.id', 'DESC')
            ->get()
            ->getResultArray();

        $attendanceRows = db_connect()
            ->table('attendance_records ar')
            ->select('ar.status')
            ->join('attendance_sessions sessions', 'sessions.id = ar.attendance_session_id')
            ->where('ar.child_id', $selectedChildId)
            ->where('sessions.is_cancelled', 0)
            ->where('sessions.session_date >=', $filters['date_start'])
            ->where('sessions.session_date <=', $filters['date_end'])
            ->get()
            ->getResultArray();

        $breakdown = ['present' => 0, 'recovery' => 0, 'absent_excused' => 0, 'absent_unexcused' => 0];
        foreach ($attendanceRows as $row) {
            $status = (string) $row['status'];
            if (isset($breakdown[$status])) {
                $breakdown[$status]++;
            }
        }

        $avgScore = $evaluations === [] ? null : round(array_sum(array_map(static fn (array $row): float => (float) $row['final_score'], $evaluations)) / count($evaluations), 2);

        return [
            'title' => 'Progres copil: ' . $selectedChild['full_name'],
            'description' => 'Istoric de evaluari si rata de prezenta in perioada selectata.',
            'columns' => ['Data', 'Tip', 'Scor', 'Status'],
            'rows' => array_map(static fn (array $row): array => [
                'Data' => $row['evaluation_date'],
                'Tip' => $row['type_name'],
                'Scor' => format_score($row['final_score']),
                'Status' => status_label($row['final_status']),
            ], $evaluations),
            'summary' => [
                ['label' => 'Copil selectat', 'value' => $selectedChild['full_name'], 'meta' => ($selectedChild['level_name'] ?: '-') . ' / ' . ($selectedChild['coach_name'] ?: '-')],
                ['label' => 'Scor mediu', 'value' => format_score($avgScore), 'meta' => 'Toate evaluarile disponibile'],
                ['label' => 'Prezenta', 'value' => format_percentage($this->attendanceService->calculateRateFromBreakdown($breakdown), 1), 'meta' => $filters['date_start'] . ' - ' . $filters['date_end']],
            ],
            'empty' => 'Copilul selectat nu are evaluari inregistrate.',
            'detailUrl' => url_to('children.show', $selectedChildId),
        ];
    }

    /**
     * @param list<int> $childIds
     * @return array<int, array<string, mixed>>
     */
    private function latestFullEvaluations(array $childIds): array
    {
        if ($childIds === []) {
            return [];
        }

        $rows = db_connect()
            ->table('evaluations e')
            ->select('e.child_id, e.evaluation_date, e.final_score, e.final_status')
            ->join('evaluation_types types', 'types.id = e.evaluation_type_id')
            ->where('types.slug', 'full-evaluation')
            ->whereIn('e.child_id', $childIds)
            ->orderBy('e.evaluation_date', 'DESC')
            ->orderBy('e.id', 'DESC')
            ->get()
            ->getResultArray();

        $latest = [];
        foreach ($rows as $row) {
            $childId = (int) $row['child_id'];
            if (! isset($latest[$childId])) {
                $latest[$childId] = $row;
            }
        }

        return $latest;
    }

    /**
     * @return list<array<string, mixed>>
     */
    private function coachOptions(?int $lockedTrainerId): array
    {
        $builder = db_connect()
            ->table('coaches')
            ->select('id, full_name')
            ->where('is_active', 1)
            ->orderBy('full_name', 'ASC');

        if ($lockedTrainerId !== null) {
            $builder->where('id', $lockedTrainerId);
        }

        return $builder->get()->getResultArray();
    }

    /**
     * @return list<array<string, mixed>>
     */
    private function levelOptions(): array
    {
        return db_connect()
            ->table('academy_levels')
            ->select('id, name')
            ->orderBy('sort_order', 'ASC')
            ->get()
            ->getResultArray();
    }

    /**
     * @return list<array<string, mixed>>
     */
    private function childOptions(?int $lockedTrainerId): array
    {
        $builder = db_connect()
            ->table('children')
            ->select('id, full_name')
            ->orderBy('full_name', 'ASC');

        if ($lockedTrainerId !== null) {
            $builder->where('primary_coach_id', $lockedTrainerId);
        }

        return $builder->get()->getResultArray();
    }

    /**
     * @return array<string, string>
     */
    private function settingsMap(): array
    {
        $rows = db_connect()
            ->table('settings')
            ->select('`key`, value')
            ->get()
            ->getResultArray();

        $settings = [];
        foreach ($rows as $row) {
            $settings[$row['key']] = $row['value'];
        }

        return $settings;
    }

    /**
     * @param array<string, mixed> $filters
     * @return array<string, string>
     */
    private function buildExportUrls(array $filters): array
    {
        $query = http_build_query($this->exportQueryFromFilters($filters));

        return [
            'csv' => url_to('reports.export', 'csv') . ($query !== '' ? '?' . $query : ''),
            'pdf' => url_to('reports.export', 'pdf') . ($query !== '' ? '?' . $query : ''),
        ];
    }

    /**
     * @param array<string, mixed> $filters
     * @return array<string, int|string>
     */
    private function exportQueryFromFilters(array $filters): array
    {
        return [
            'report' => (string) $filters['selected_report'],
            'period' => (string) $filters['selected_period'],
            'coach_id' => (int) $filters['selected_coach_id'],
            'level_id' => (int) $filters['selected_level_id'],
            'child_status' => (string) $filters['selected_child_status'],
            'child_id' => (int) $filters['selected_child_id'],
        ];
    }

    /**
     * @param array<string, mixed> $filters
     * @return list<array{label: string, value: string}>
     */
    private function buildAppliedFilters(array $filters): array
    {
        $items = [
            [
                'label' => 'Raport',
                'value' => (string) ($filters['report_options'][$filters['selected_report']] ?? $filters['selected_report']),
            ],
            [
                'label' => 'Perioada',
                'value' => (string) ($filters['period_options'][$filters['selected_period']] ?? $filters['selected_period']),
            ],
            [
                'label' => 'Interval',
                'value' => (string) $filters['date_start'] . ' - ' . (string) $filters['date_end'],
            ],
        ];

        $coachName = $this->findOptionLabel((array) $filters['coach_options'], (int) $filters['selected_coach_id'], 'full_name');
        if ($coachName !== null) {
            $items[] = ['label' => 'Trainer', 'value' => $coachName];
        }

        $levelName = $this->findOptionLabel((array) $filters['level_options'], (int) $filters['selected_level_id'], 'name');
        if ($levelName !== null) {
            $items[] = ['label' => 'Nivel', 'value' => $levelName];
        }

        if ((string) $filters['selected_child_status'] !== 'all') {
            $items[] = [
                'label' => 'Status copil',
                'value' => (string) ($filters['status_options'][$filters['selected_child_status']] ?? $filters['selected_child_status']),
            ];
        }

        $childName = $this->findOptionLabel((array) $filters['child_options'], (int) $filters['selected_child_id'], 'full_name');
        if ($childName !== null) {
            $items[] = ['label' => 'Copil', 'value' => $childName];
        }

        return $items;
    }

    /**
     * @param list<array<string, mixed>> $options
     */
    private function findOptionLabel(array $options, int $selectedId, string $labelKey): ?string
    {
        if ($selectedId <= 0) {
            return null;
        }

        foreach ($options as $option) {
            if ((int) ($option['id'] ?? 0) === $selectedId) {
                return (string) ($option[$labelKey] ?? '');
            }
        }

        return null;
    }

    /**
     * @param array<string, mixed> $filters
     */
    private function buildFileBasename(array $filters, DateTimeImmutable $generatedAt): string
    {
        return 'avh-kids-' . url_title((string) $filters['selected_report'], '-', true) . '-' . $generatedAt->format('Ymd-Hi');
    }

    private function stringValue(mixed $value): string
    {
        if ($value === null || $value === '') {
            return '-';
        }

        if (is_scalar($value)) {
            return (string) $value;
        }

        return json_encode($value, JSON_UNESCAPED_UNICODE) ?: '-';
    }
}
