<?php

namespace App\Database\Seeds;

use App\Models\AcademyGroupModel;
use App\Models\AcademyLevelModel;
use App\Models\AttendanceRecordModel;
use App\Models\AttendanceSessionModel;
use App\Models\ChildCoachModel;
use App\Models\ChildGuardianModel;
use App\Models\ChildModel;
use App\Models\CoachAvailabilityModel;
use App\Models\CoachModel;
use App\Models\EvaluationCriteriaModel;
use App\Models\EvaluationModel;
use App\Models\EvaluationRuleModel;
use App\Models\EvaluationScoreModel;
use App\Models\EvaluationStatusHistoryModel;
use App\Models\EvaluationTypeModel;
use App\Models\GuardianModel;
use App\Models\NotificationModel;
use App\Models\SettingModel;
use App\Models\UserRoleModel;
use CodeIgniter\Database\Seeder;
use CodeIgniter\Shield\Entities\User;
use CodeIgniter\Shield\Models\UserModel;
use RuntimeException;

class AcademiaSeeder extends Seeder
{
    private string $defaultPassword = 'Academia123!';

    private UserModel $userModel;

    /** @var array<string, int> */
    private array $roleIds = [];

    /** @var array<string, int> */
    private array $userIds = [];

    /** @var array<string, int> */
    private array $coachIds = [];

    /** @var array<string, int> */
    private array $groupIds = [];

    /** @var array<string, int> */
    private array $levelIds = [];

    /** @var array<string, int> */
    private array $guardianIds = [];

    /** @var array<string, array<string, mixed>> */
    private array $children = [];

    /** @var array<string, int> */
    private array $evaluationTypeIds = [];

    /** @var array<string, array<string, mixed>> */
    private array $criteria = [];

    /** @var array<string, list<string>> */
    private array $criteriaByType = [];

    /** @var array<string, float|int|string|bool|null> */
    private array $rule = [];

    public function run(): void
    {
        $this->userModel = model(UserModel::class);

        $this->db->transStart();

        $this->seedRoles();
        $this->seedSettings();
        $this->seedEvaluationRules();
        $this->seedLevels();
        $this->seedEvaluationCatalog();
        $this->seedUsers();
        $this->seedCoaches();
        $this->seedCoachAvailability();
        $this->seedGroups();
        $this->seedParents();
        $this->seedChildren();
        $this->seedAttendance();
        $this->seedEvaluations();
        $this->seedNotifications();

        $this->db->transComplete();

        if (! $this->db->transStatus()) {
            throw new RuntimeException('Academia seed failed: ' . json_encode($this->db->error()));
        }
    }

    private function seedRoles(): void
    {
        $now = date('Y-m-d H:i:s');

        $inserted = $this->db->table('roles')->insertBatch([
            [
                'slug' => 'admin',
                'name' => 'Admin',
                'description' => 'Acces complet in platforma.',
                'priority' => 1,
                'created_at' => $now,
                'updated_at' => $now,
            ],
            [
                'slug' => 'coach',
                'name' => 'Trainer',
                'description' => 'Acces la copii, evaluari si prezenta pentru grupele proprii de inot.',
                'priority' => 2,
                'created_at' => $now,
                'updated_at' => $now,
            ],
            [
                'slug' => 'parent',
                'name' => 'Parent',
                'description' => 'Rol limitat, pregatit pentru fazele viitoare.',
                'priority' => 3,
                'created_at' => $now,
                'updated_at' => $now,
            ],
        ]);

        if ($inserted === false) {
            throw new RuntimeException('Unable to seed roles: ' . json_encode($this->db->error()));
        }

        $query = $this->db->table('roles')->get();
        if ($query === false) {
            throw new RuntimeException('Unable to read roles after seed: ' . json_encode($this->db->error()));
        }

        foreach ($query->getResultArray() as $row) {
            $this->roleIds[$row['slug']] = (int) $row['id'];
        }
    }

    private function seedSettings(): void
    {
        $model = model(SettingModel::class);
        $now   = date('Y-m-d H:i:s');

        $model->insertBatch([
            [
                'class' => 'Academia',
                'key' => 'academy_name',
                'value' => 'Splash Academy',
                'type' => 'string',
                'context' => 'general',
                'label' => 'Academy Name',
                'group_name' => 'general',
                'description' => 'Numele academiei afisat in layout.',
                'is_public' => 1,
                'created_at' => $now,
                'updated_at' => $now,
            ],
            [
                'class' => 'Academia',
                'key' => 'default_dashboard_period',
                'value' => '30',
                'type' => 'integer',
                'context' => 'dashboard',
                'label' => 'Default Dashboard Period',
                'group_name' => 'dashboard',
                'description' => 'Perioada implicita pentru filtrele dashboardului.',
                'is_public' => 0,
                'created_at' => $now,
                'updated_at' => $now,
            ],
            [
                'class' => 'Academia',
                'key' => 'no_evaluation_days',
                'value' => '45',
                'type' => 'integer',
                'context' => 'dashboard',
                'label' => 'No Evaluation Days Threshold',
                'group_name' => 'dashboard',
                'description' => 'Numarul de zile dupa care copilul intra in alerta fara evaluare.',
                'is_public' => 0,
                'created_at' => $now,
                'updated_at' => $now,
            ],
            [
                'class' => 'Academia',
                'key' => 'absence_alert_threshold',
                'value' => '25',
                'type' => 'integer',
                'context' => 'dashboard',
                'label' => 'Absence Alert Threshold',
                'group_name' => 'dashboard',
                'description' => 'Procent de absenta peste care este generata alerta.',
                'is_public' => 0,
                'created_at' => $now,
                'updated_at' => $now,
            ],
        ]);
    }

    private function seedEvaluationRules(): void
    {
        $model = model(EvaluationRuleModel::class);
        $now   = date('Y-m-d H:i:s');

        $this->rule = [
            'name' => 'Global Default Rule',
            'scope_type' => 'global',
            'scope_id' => null,
            'almost_ready_threshold' => 3.5,
            'ready_threshold' => 4.0,
            'minimum_critical_threshold' => 3.0,
            'is_active' => 1,
            'notes' => 'Pragurile implicite pentru scorare si semnal de promovare.',
            'created_at' => $now,
            'updated_at' => $now,
        ];

        $model->insert($this->rule);
    }

    private function seedLevels(): void
    {
        $model = model(AcademyLevelModel::class);
        $now   = date('Y-m-d H:i:s');

        $levels = [
            ['key' => 'delfinas', 'name' => 'Delfinaș (Inițiere)', 'slug' => 'delfinas-initiere', 'sort_order' => 1, 'color_hex' => '#0ea5e9'],
            ['key' => 'rechin', 'name' => 'Rechin (Avansat)', 'slug' => 'rechin-avansat', 'sort_order' => 2, 'color_hex' => '#0284c7'],
            ['key' => 'pre_performanta', 'name' => 'Pre-Performanță', 'slug' => 'pre-performanta', 'sort_order' => 3, 'color_hex' => '#14b8a6'],
            ['key' => 'sportiv_performanta', 'name' => 'Sportiv de Performanță', 'slug' => 'sportiv-de-performanta', 'sort_order' => 4, 'color_hex' => '#f59e0b'],
        ];

        foreach ($levels as $level) {
            $model->insert([
                'name' => $level['name'],
                'slug' => $level['slug'],
                'sort_order' => $level['sort_order'],
                'color_hex' => $level['color_hex'],
                'internal_description' => 'Nivel intern pentru cursurile de inot: ' . $level['name'] . '.',
                'parent_description' => 'Nivelul ' . $level['name'] . ' marcheaza progresul copilului in programul de inot.',
                'benchmark_minimum' => 3.0,
                'benchmark_target' => 4.0,
                'promotion_rules' => 'Necesita evaluare full cu status READY si criterii critice peste prag.',
                'created_at' => $now,
                'updated_at' => $now,
            ]);

            $this->levelIds[$level['key']] = (int) $model->getInsertID();
        }
    }

    private function seedEvaluationCatalog(): void
    {
        $typeModel     = model(EvaluationTypeModel::class);
        $criteriaModel = model(EvaluationCriteriaModel::class);
        $now           = date('Y-m-d H:i:s');

        $types = [
            [
                'key' => 'quick-check',
                'name' => 'Quick Check',
                'description' => 'Monitorizare rapida pentru progresul saptamanal la inot.',
                'is_quick_check' => 1,
                'affects_promotion' => 0,
            ],
            [
                'key' => 'full-evaluation',
                'name' => 'Full Evaluation',
                'description' => 'Evaluare completa folosita pentru decizii de promovare in programul de inot.',
                'is_quick_check' => 0,
                'affects_promotion' => 1,
            ],
        ];

        foreach ($types as $type) {
            $typeModel->insert([
                'name' => $type['name'],
                'slug' => $type['key'],
                'description' => $type['description'],
                'is_quick_check' => $type['is_quick_check'],
                'affects_promotion' => $type['affects_promotion'],
                'status' => 'active',
                'created_at' => $now,
                'updated_at' => $now,
            ]);

            $this->evaluationTypeIds[$type['key']] = (int) $typeModel->getInsertID();
        }

        $criteria = [
            ['slug' => 'water-confidence', 'name' => 'Water Confidence', 'weight' => 1.2, 'critical' => 1, 'sort_order' => 1],
            ['slug' => 'breathing-control', 'name' => 'Breathing Control', 'weight' => 1.2, 'critical' => 1, 'sort_order' => 2],
            ['slug' => 'stroke-technique', 'name' => 'Stroke Technique', 'weight' => 1.4, 'critical' => 1, 'sort_order' => 3],
            ['slug' => 'start-turn-basics', 'name' => 'Start & Turn Basics', 'weight' => 0.9, 'critical' => 0, 'sort_order' => 4],
            ['slug' => 'race-awareness', 'name' => 'Race Awareness', 'weight' => 0.7, 'critical' => 0, 'sort_order' => 5],
            ['slug' => 'focus-effort', 'name' => 'Focus & Effort', 'weight' => 0.8, 'critical' => 0, 'sort_order' => 6],
        ];

        foreach ($criteria as $criterion) {
            $criteriaModel->insert([
                'name' => $criterion['name'],
                'slug' => $criterion['slug'],
                'description' => $criterion['name'] . ' in contextul evaluarii academiei.',
                'is_active' => 1,
                'default_weight' => $criterion['weight'],
                'is_critical' => $criterion['critical'],
                'sort_order' => $criterion['sort_order'],
                'min_score' => 1,
                'max_score' => 5,
                'created_at' => $now,
                'updated_at' => $now,
            ]);

            $this->criteria[$criterion['slug']] = [
                'id' => (int) $criteriaModel->getInsertID(),
                'weight' => (float) $criterion['weight'],
                'is_critical' => (bool) $criterion['critical'],
            ];
        }

        $this->criteriaByType = [
            'quick-check' => ['water-confidence', 'breathing-control', 'stroke-technique', 'focus-effort'],
            'full-evaluation' => ['water-confidence', 'breathing-control', 'stroke-technique', 'start-turn-basics', 'race-awareness', 'focus-effort'],
        ];

        $pivotRows = [];
        foreach ($this->criteriaByType as $typeSlug => $criteriaSlugs) {
            foreach ($criteriaSlugs as $index => $criterionSlug) {
                $pivotRows[] = [
                    'evaluation_type_id' => $this->evaluationTypeIds[$typeSlug],
                    'evaluation_criteria_id' => $this->criteria[$criterionSlug]['id'],
                    'weight' => $this->criteria[$criterionSlug]['weight'],
                    'is_required' => 1,
                    'sort_order' => $index + 1,
                ];
            }
        }

        $this->db->table('evaluation_type_criteria')->insertBatch($pivotRows);
    }

    private function seedUsers(): void
    {
        $this->userIds['admin'] = $this->createUser('admin', 'admin@academia.local', 'admin', 'admin');
        $this->userIds['coach_andrei'] = $this->createUser('andrei.popescu', 'andrei@academia.local', 'coach', 'coach');
        $this->userIds['coach_ioana'] = $this->createUser('ioana.dumitrescu', 'ioana@academia.local', 'coach', 'coach');
        $this->userIds['coach_mihai'] = $this->createUser('mihai.ionescu', 'mihai@academia.local', 'coach', 'coach');
        $this->userIds['parent_cristina'] = $this->createUser('cristina.marin', 'cristina@academia.local', 'parent', 'parent');
    }

    private function seedCoaches(): void
    {
        $model = model(CoachModel::class);
        $now   = date('Y-m-d H:i:s');

        $coaches = [
            'coach_andrei' => [
                'full_name' => 'Andrei Popescu',
                'display_role' => 'Head Trainer',
                'phone' => '0711 111 111',
                'email' => 'andrei@academia.local',
            ],
            'coach_ioana' => [
                'full_name' => 'Ioana Dumitrescu',
                'display_role' => 'Trainer',
                'phone' => '0722 222 222',
                'email' => 'ioana@academia.local',
            ],
            'coach_mihai' => [
                'full_name' => 'Mihai Ionescu',
                'display_role' => 'Assistant Trainer',
                'phone' => '0733 333 333',
                'email' => 'mihai@academia.local',
            ],
        ];

        foreach ($coaches as $key => $coach) {
            $model->insert([
                'user_id' => $this->userIds[$key],
                'full_name' => $coach['full_name'],
                'display_role' => $coach['display_role'],
                'phone' => $coach['phone'],
                'email' => $coach['email'],
                'avatar_path' => null,
                'is_active' => 1,
                'notes' => 'Profil initial seed-uit pentru Faza 1.',
                'created_at' => $now,
                'updated_at' => $now,
            ]);

            $this->coachIds[$key] = (int) $model->getInsertID();
        }
    }

    private function seedCoachAvailability(): void
    {
        $model = model(CoachAvailabilityModel::class);
        $now   = date('Y-m-d H:i:s');

        $slots = [
            'coach_andrei' => [[1, '16:00:00', '19:00:00'], [3, '16:00:00', '19:00:00'], [5, '16:00:00', '18:30:00']],
            'coach_ioana' => [[2, '16:00:00', '19:00:00'], [4, '16:00:00', '19:00:00'], [6, '10:00:00', '13:00:00']],
            'coach_mihai' => [[1, '17:00:00', '20:00:00'], [4, '17:00:00', '20:00:00'], [6, '09:00:00', '12:00:00']],
        ];

        foreach ($slots as $coachKey => $entries) {
            foreach ($entries as [$dayOfWeek, $start, $end]) {
                $model->insert([
                    'coach_id' => $this->coachIds[$coachKey],
                    'day_of_week' => $dayOfWeek,
                    'start_time' => $start,
                    'end_time' => $end,
                    'is_available' => 1,
                    'created_at' => $now,
                ]);
            }
        }
    }

    private function seedGroups(): void
    {
        $model = model(AcademyGroupModel::class);
        $now   = date('Y-m-d H:i:s');

        $groups = [
            'red_sparks' => [
                'name' => 'Delfinas Initiere',
                'code' => 'DFN',
                'academy_level_id' => $this->levelIds['delfinas'],
                'primary_coach_id' => $this->coachIds['coach_andrei'],
                'schedule_summary' => 'Mon & Wed, 17:00',
            ],
            'orange_aces' => [
                'name' => 'Rechin Avansat',
                'code' => 'RCH',
                'academy_level_id' => $this->levelIds['rechin'],
                'primary_coach_id' => $this->coachIds['coach_ioana'],
                'schedule_summary' => 'Tue & Thu, 17:00',
            ],
            'green_smash' => [
                'name' => 'Performanta Bazin',
                'code' => 'PRF',
                'academy_level_id' => $this->levelIds['sportiv_performanta'],
                'primary_coach_id' => $this->coachIds['coach_mihai'],
                'schedule_summary' => 'Mon & Thu, 18:00',
            ],
        ];

        foreach ($groups as $key => $group) {
            $model->insert([
                'name' => $group['name'],
                'code' => $group['code'],
                'academy_level_id' => $group['academy_level_id'],
                'primary_coach_id' => $group['primary_coach_id'],
                'schedule_summary' => $group['schedule_summary'],
                'status' => 'active',
                'capacity' => 12,
                'created_at' => $now,
                'updated_at' => $now,
            ]);

            $this->groupIds[$key] = (int) $model->getInsertID();
        }
    }

    private function seedParents(): void
    {
        $model = model(GuardianModel::class);
        $now   = date('Y-m-d H:i:s');

        foreach ($this->childDefinitions() as $childKey => $child) {
            $guardian = $child['guardian'];
            $model->insert([
                'user_id' => $guardian['user_key'] ? $this->userIds[$guardian['user_key']] : null,
                'full_name' => $guardian['full_name'],
                'phone' => $guardian['phone'],
                'email' => $guardian['email'],
                'relationship_type' => 'parent',
                'status' => 'active',
                'notes' => 'Contact seed-uit pentru profilul copilului.',
                'created_at' => $now,
                'updated_at' => $now,
            ]);

            $this->guardianIds[$childKey] = (int) $model->getInsertID();
        }
    }

    private function seedChildren(): void
    {
        $childModel          = model(ChildModel::class);
        $childGuardianModel  = model(ChildGuardianModel::class);
        $childCoachModel     = model(ChildCoachModel::class);
        $journeyService      = service('journey');
        $now                 = date('Y-m-d H:i:s');

        foreach ($this->childDefinitions() as $childKey => $definition) {
            $fullName = $definition['first_name'] . ' ' . $definition['last_name'];
            $childModel->insert([
                'first_name' => $definition['first_name'],
                'last_name' => $definition['last_name'],
                'full_name' => $fullName,
                'birth_date' => $definition['birth_date'],
                'gender' => $definition['gender'],
                'academy_level_id' => $this->levelIds[$definition['level_key']],
                'academy_group_id' => $this->groupIds[$definition['group_key']],
                'primary_coach_id' => $this->coachIds[$definition['coach_key']],
                'primary_guardian_id' => $this->guardianIds[$childKey],
                'first_class_at' => $definition['first_class_at'],
                'status' => $definition['status'],
                'has_siblings' => $definition['has_siblings'],
                'notes' => $definition['notes'],
                'created_at' => $now,
                'updated_at' => $now,
            ]);

            $childId = (int) $childModel->getInsertID();

            $childGuardianModel->insert([
                'child_id' => $childId,
                'parent_id' => $this->guardianIds[$childKey],
                'relationship_type' => 'parent',
                'is_primary' => 1,
                'created_at' => $now,
            ]);

            $childCoachModel->insert([
                'child_id' => $childId,
                'coach_id' => $this->coachIds[$definition['coach_key']],
                'is_primary' => 1,
                'assigned_at' => $definition['first_class_at'] . ' 09:00:00',
                'unassigned_at' => null,
            ]);

            $this->children[$childKey] = [
                'id' => $childId,
                'full_name' => $fullName,
                'status' => $definition['status'],
                'group_key' => $definition['group_key'],
                'coach_key' => $definition['coach_key'],
                'level_key' => $definition['level_key'],
            ];

            $journeyService->recordEvent([
                'child_id' => $childId,
                'event_type' => 'child_created',
                'title' => 'Copil adaugat in academie',
                'description' => 'Profilul copilului a fost creat si asignat la grupa si trainerul principal.',
                'metadata' => json_encode([
                    'group' => $definition['group_key'],
                    'coach' => $definition['coach_key'],
                    'level' => $definition['level_key'],
                ], JSON_UNESCAPED_UNICODE),
                'created_by' => $this->userIds['admin'],
                'created_at' => $now,
            ]);
        }
    }

    private function seedAttendance(): void
    {
        $sessionModel = model(AttendanceSessionModel::class);
        $recordModel  = model(AttendanceRecordModel::class);
        $journey      = service('journey');
        $today        = new \DateTimeImmutable('today');
        $offsets      = [-27, -24, -20, -17, -13, -10, -6, -3];
        $patterns     = $this->attendancePatterns();

        foreach ($this->groupIds as $groupKey => $groupId) {
            $cancelledSessionId = null;

            foreach ($offsets as $index => $offset) {
                $sessionDate = $today->modify($offset . ' days')->format('Y-m-d');
                $status      = 'completed';
                $isCancelled = 0;
                $recoveryFor = null;

                if ($groupKey === 'orange_aces' && $index === 2) {
                    $status      = 'cancelled';
                    $isCancelled = 1;
                }

                if ($groupKey === 'orange_aces' && $index === 3) {
                    $status      = 'recovery';
                    $recoveryFor = $cancelledSessionId;
                }

                $sessionModel->insert([
                    'academy_group_id' => $groupId,
                    'coach_id' => $this->coachIds[$this->groupCoachKey($groupKey)],
                    'session_date' => $sessionDate,
                    'start_time' => $groupKey === 'green_smash' ? '18:00:00' : '17:00:00',
                    'end_time' => $groupKey === 'green_smash' ? '19:30:00' : '18:30:00',
                    'status' => $status,
                    'is_cancelled' => $isCancelled,
                    'cancelled_reason' => $isCancelled ? 'Trainer indisponibil - sesiune mutata pe recovery.' : null,
                    'recovery_for_session_id' => $recoveryFor,
                    'notes' => $status === 'recovery' ? 'Sesiune de recuperare programata automat.' : null,
                    'created_at' => $sessionDate . ' 08:00:00',
                    'updated_at' => $sessionDate . ' 08:00:00',
                ]);

                $sessionId = (int) $sessionModel->getInsertID();

                if ($isCancelled) {
                    $cancelledSessionId = $sessionId;
                    continue;
                }

                foreach ($this->children as $childKey => $child) {
                    if ($child['group_key'] !== $groupKey || ! $this->childAttendsSession($child['status'], $offset)) {
                        continue;
                    }

                    $pattern = $patterns[$childKey] ?? array_fill(0, count($offsets), 'present');
                    $status  = $pattern[$index] ?? 'present';

                    if ($status === 'recovery' && $groupKey !== 'orange_aces') {
                        $status = 'present';
                    }

                    if ($groupKey === 'orange_aces' && $index === 3 && $status === 'present') {
                        $status = 'recovery';
                    }

                    $recordModel->insert([
                        'attendance_session_id' => $sessionId,
                        'child_id' => $child['id'],
                        'status' => $status,
                        'checked_in_at' => in_array($status, ['present', 'recovery'], true) ? $sessionDate . ' 16:55:00' : null,
                        'notes' => $status === 'absent_unexcused' ? 'Absenta nemotivata.' : null,
                        'created_at' => $sessionDate . ' 20:00:00',
                        'updated_at' => $sessionDate . ' 20:00:00',
                    ]);
                }
            }
        }

        foreach (['maria_enache', 'teodor_stan'] as $childKey) {
            $journey->recordEvent([
                'child_id' => $this->children[$childKey]['id'],
                'event_type' => 'attendance_issue',
                'title' => 'Avertizare de prezenta',
                'description' => 'Copilul a depasit pragul de absente pentru perioada recenta.',
                'metadata' => json_encode(['source' => 'seed'], JSON_UNESCAPED_UNICODE),
                'created_by' => $this->userIds['admin'],
            ]);
        }
    }

    private function seedEvaluations(): void
    {
        $plans = $this->evaluationPlan();

        foreach ($plans as $childKey => $entries) {
            foreach ($entries as $entry) {
                $this->createEvaluation(
                    $childKey,
                    $entry['type'],
                    $entry['days_ago'],
                    $entry['template'],
                    $entry['note'],
                );
            }
        }
    }

    private function seedNotifications(): void
    {
        $model = model(NotificationModel::class);
        $now   = date('Y-m-d H:i:s');

        $model->insertBatch([
            [
                'user_id' => $this->userIds['admin'],
                'child_id' => $this->children['luca_marin']['id'],
                'type' => 'promotion_ready',
                'title' => 'Copil pregatit pentru avansare',
                'message' => 'Luca Marin are ultima evaluare Full cu status READY.',
                'status' => 'unread',
                'action_url' => '/dashboard',
                'created_at' => $now,
                'read_at' => null,
            ],
            [
                'user_id' => $this->userIds['coach_andrei'],
                'child_id' => $this->children['luca_marin']['id'],
                'type' => 'promotion_ready',
                'title' => 'Ready in grupa ta',
                'message' => 'Luca Marin poate intra in discutia de promovare.',
                'status' => 'unread',
                'action_url' => '/dashboard',
                'created_at' => $now,
                'read_at' => null,
            ],
            [
                'user_id' => $this->userIds['admin'],
                'child_id' => $this->children['maria_enache']['id'],
                'type' => 'attendance_alert',
                'title' => 'Prezenta scazuta',
                'message' => 'Maria Enache are absente ridicate in ultimele sedinte.',
                'status' => 'unread',
                'action_url' => '/dashboard',
                'created_at' => $now,
                'read_at' => null,
            ],
            [
                'user_id' => $this->userIds['admin'],
                'child_id' => $this->children['daria_neagu']['id'],
                'type' => 'evaluation_overdue',
                'title' => 'Fara evaluare recenta',
                'message' => 'Daria Neagu nu are evaluare in ultimele 45 de zile.',
                'status' => 'unread',
                'action_url' => '/dashboard',
                'created_at' => $now,
                'read_at' => null,
            ],
        ]);
    }

    private function createUser(string $username, string $email, string $shieldGroup, string $appRole): int
    {
        $user = new User([
            'username' => $username,
            'email' => $email,
            'password' => $this->defaultPassword,
            'active' => 1,
        ]);

        $this->userModel->save($user);

        $created = $this->userModel->findByCredentials(['email' => $email]);
        if (! $created) {
            throw new RuntimeException('Unable to create user ' . $email);
        }

        $created->addGroup($shieldGroup);

        model(UserRoleModel::class)->insert([
            'user_id' => (int) $created->id,
            'role_id' => $this->roleIds[$appRole],
            'created_at' => date('Y-m-d H:i:s'),
        ]);

        return (int) $created->id;
    }

    private function createEvaluation(string $childKey, string $typeKey, int $daysAgo, string $templateKey, string $note): void
    {
        $child        = $this->children[$childKey];
        $typeId       = $this->evaluationTypeIds[$typeKey];
        $date         = (new \DateTimeImmutable('today'))->modify('-' . $daysAgo . ' days')->format('Y-m-d');
        $coachKey     = $child['coach_key'];
        $template     = $this->scoreTemplates()[$templateKey];
        $criteriaRows = [];

        foreach ($this->criteriaByType[$typeKey] as $criterionSlug) {
            $criteriaRows[] = [
                'evaluation_criteria_id' => $this->criteria[$criterionSlug]['id'],
                'weight' => $this->criteria[$criterionSlug]['weight'],
                'score' => $template[$criterionSlug],
                'is_critical' => $this->criteria[$criterionSlug]['is_critical'],
                'notes' => null,
            ];
        }

        $result = service('evaluationEngine')->evaluate($criteriaRows, $this->rule);
        $promotionSignal = $typeKey === 'full-evaluation' ? (int) $result['promotion_signal'] : 0;

        $evaluationModel = model(EvaluationModel::class);
        $evaluationModel->insert([
            'child_id' => $child['id'],
            'evaluation_type_id' => $typeId,
            'evaluation_date' => $date,
            'evaluator_user_id' => $this->userIds[$coachKey],
            'evaluator_coach_id' => $this->coachIds[$coachKey],
            'level_at_time_id' => $this->levelIds[$child['level_key']],
            'final_score' => $result['final_score'],
            'final_status' => $result['final_status'],
            'promotion_signal' => $promotionSignal,
            'notes' => $note,
            'created_at' => $date . ' 12:00:00',
            'updated_at' => $date . ' 12:00:00',
        ]);

        $evaluationId = (int) $evaluationModel->getInsertID();

        foreach ($criteriaRows as $criteriaRow) {
            model(EvaluationScoreModel::class)->insert(array_merge($criteriaRow, [
                'evaluation_id' => $evaluationId,
            ]));
        }

        model(EvaluationStatusHistoryModel::class)->insert([
            'evaluation_id' => $evaluationId,
            'previous_status' => null,
            'new_status' => $result['final_status'],
            'reason' => 'Seeded initial evaluation status.',
            'changed_by' => $this->userIds[$coachKey],
            'created_at' => $date . ' 12:05:00',
        ]);

        service('journey')->recordEvent([
            'child_id' => $child['id'],
            'event_type' => $typeKey === 'quick-check' ? 'quick_check_added' : 'evaluation_added',
            'title' => $typeKey === 'quick-check' ? 'Quick Check adaugat' : 'Full Evaluation adaugata',
            'description' => $note,
            'metadata' => json_encode([
                'type' => $typeKey,
                'score' => $result['final_score'],
                'status' => $result['final_status'],
            ], JSON_UNESCAPED_UNICODE),
            'created_by' => $this->userIds[$coachKey],
            'created_at' => $date . ' 12:10:00',
        ]);
    }

    /**
     * @return array<string, array<string, mixed>>
     */
    private function childDefinitions(): array
    {
        return [
            'luca_marin' => $this->childDefinition('Luca', 'Marin', '2016-04-12', 'male', 'rechin', 'red_sparks', 'coach_andrei', 'active', '2025-09-02', 1, 'Adaptare buna in apa si ritm foarte bun.', 'Cristina Marin', '0740 100 100', 'cristina@academia.local', 'parent_cristina'),
            'sofia_radu' => $this->childDefinition('Sofia', 'Radu', '2017-01-20', 'female', 'delfinas', 'red_sparks', 'coach_andrei', 'active', '2025-10-10', 0, 'Foarte receptiva la feedback.', 'Elena Radu', '0740 100 101', 'elena.radu@academia.local'),
            'matei_dinu' => $this->childDefinition('Matei', 'Dinu', '2016-08-05', 'male', 'rechin', 'red_sparks', 'coach_andrei', 'active', '2025-09-18', 0, 'Constanta in crestere, are nevoie de mai multa incredere.', 'Roxana Dinu', '0740 100 102', 'roxana.dinu@academia.local'),
            'emma_pavel' => $this->childDefinition('Emma', 'Pavel', '2015-07-11', 'female', 'pre_performanta', 'orange_aces', 'coach_ioana', 'active', '2025-08-15', 0, 'Se misca bine in bazin, coordonare in progres.', 'Adrian Pavel', '0740 100 103', 'adrian.pavel@academia.local'),
            'david_ilie' => $this->childDefinition('David', 'Ilie', '2015-11-09', 'male', 'pre_performanta', 'orange_aces', 'coach_ioana', 'active', '2025-08-22', 1, 'Competitiv, raspunde bine la obiective clare.', 'Corina Ilie', '0740 100 104', 'corina.ilie@academia.local'),
            'ana_toma' => $this->childDefinition('Ana', 'Toma', '2014-09-03', 'female', 'sportiv_performanta', 'orange_aces', 'coach_ioana', 'active', '2025-07-30', 0, 'Stabila in sesiuni, aproape de pragul urmator.', 'Andreea Toma', '0740 100 105', 'andreea.toma@academia.local'),
            'teodor_stan' => $this->childDefinition('Teodor', 'Stan', '2014-12-14', 'male', 'sportiv_performanta', 'orange_aces', 'coach_ioana', 'active', '2025-07-18', 0, 'Prezenta inconstanta in ultima luna.', 'Mihnea Stan', '0740 100 106', 'mihnea.stan@academia.local'),
            'ilinca_pop' => $this->childDefinition('Ilinca', 'Pop', '2013-06-01', 'female', 'sportiv_performanta', 'green_smash', 'coach_mihai', 'active', '2025-06-20', 0, 'Control bun pe serii lungi.', 'Camelia Pop', '0740 100 107', 'camelia.pop@academia.local'),
            'victor_oprea' => $this->childDefinition('Victor', 'Oprea', '2013-10-27', 'male', 'sportiv_performanta', 'green_smash', 'coach_mihai', 'active', '2025-06-28', 0, 'Nivel bun, inca lucreaza la strategie de cursa.', 'Laura Oprea', '0740 100 108', 'laura.oprea@academia.local'),
            'maria_enache' => $this->childDefinition('Maria', 'Enache', '2012-03-16', 'female', 'sportiv_performanta', 'green_smash', 'coach_mihai', 'active', '2025-05-12', 0, 'Potential bun, dar absentele incetinesc progresul.', 'George Enache', '0740 100 109', 'george.enache@academia.local'),
            'alex_tudor' => $this->childDefinition('Alex', 'Tudor', '2017-09-21', 'male', 'delfinas', 'red_sparks', 'coach_andrei', 'active', '2025-10-18', 0, 'Energetic, are nevoie de mai multa consistenta.', 'Bianca Tudor', '0740 100 110', 'bianca.tudor@academia.local'),
            'eva_nistor' => $this->childDefinition('Eva', 'Nistor', '2015-02-07', 'female', 'pre_performanta', 'orange_aces', 'coach_ioana', 'pause', '2025-08-05', 0, 'Pauza temporara, revenire planificata luna viitoare.', 'Sorin Nistor', '0740 100 111', 'sorin.nistor@academia.local'),
            'rares_mocanu' => $this->childDefinition('Rares', 'Mocanu', '2013-01-30', 'male', 'sportiv_performanta', 'green_smash', 'coach_mihai', 'active', '2025-05-28', 0, 'Stagnare usoara pe partea de cursa.', 'Daniela Mocanu', '0740 100 112', 'daniela.mocanu@academia.local'),
            'daria_neagu' => $this->childDefinition('Daria', 'Neagu', '2012-11-11', 'female', 'sportiv_performanta', 'green_smash', 'coach_mihai', 'active', '2025-05-02', 0, 'Necesita reevaluare completa dupa revenirea in ritm.', 'Silviu Neagu', '0740 100 113', 'silviu.neagu@academia.local'),
            'tudor_barbu' => $this->childDefinition('Tudor', 'Barbu', '2016-06-18', 'male', 'rechin', 'red_sparks', 'coach_andrei', 'left', '2025-09-10', 0, 'A parasit temporar programul.', 'Anca Barbu', '0740 100 114', 'anca.barbu@academia.local'),
        ];
    }

    /**
     * @return array<string, mixed>
     */
    private function childDefinition(
        string $firstName,
        string $lastName,
        string $birthDate,
        string $gender,
        string $levelKey,
        string $groupKey,
        string $coachKey,
        string $status,
        string $firstClassAt,
        int $hasSiblings,
        string $notes,
        string $guardianName,
        string $guardianPhone,
        string $guardianEmail,
        ?string $guardianUserKey = null,
    ): array {
        return [
            'first_name' => $firstName,
            'last_name' => $lastName,
            'birth_date' => $birthDate,
            'gender' => $gender,
            'level_key' => $levelKey,
            'group_key' => $groupKey,
            'coach_key' => $coachKey,
            'status' => $status,
            'first_class_at' => $firstClassAt,
            'has_siblings' => $hasSiblings,
            'notes' => $notes,
            'guardian' => [
                'full_name' => $guardianName,
                'phone' => $guardianPhone,
                'email' => $guardianEmail,
                'user_key' => $guardianUserKey,
            ],
        ];
    }

    /**
     * @return array<string, list<string>>
     */
    private function attendancePatterns(): array
    {
        return [
            'luca_marin' => ['present', 'present', 'present', 'present', 'recovery', 'present', 'present', 'present'],
            'sofia_radu' => ['present', 'present', 'absent_excused', 'present', 'present', 'present', 'present', 'present'],
            'matei_dinu' => ['present', 'absent_unexcused', 'present', 'present', 'absent_excused', 'present', 'present', 'present'],
            'emma_pavel' => ['present', 'present', 'present', 'present', 'present', 'present', 'present', 'present'],
            'david_ilie' => ['present', 'present', 'present', 'present', 'recovery', 'present', 'present', 'present'],
            'ana_toma' => ['present', 'present', 'absent_excused', 'recovery', 'present', 'present', 'present', 'present'],
            'teodor_stan' => ['present', 'absent_unexcused', 'absent_unexcused', 'present', 'present', 'absent_excused', 'present', 'present'],
            'ilinca_pop' => ['present', 'present', 'present', 'present', 'present', 'present', 'present', 'present'],
            'victor_oprea' => ['present', 'present', 'present', 'present', 'present', 'absent_excused', 'present', 'present'],
            'maria_enache' => ['present', 'absent_unexcused', 'absent_unexcused', 'present', 'absent_excused', 'absent_unexcused', 'recovery', 'absent_unexcused'],
            'alex_tudor' => ['present', 'present', 'present', 'present', 'present', 'present', 'absent_excused', 'present'],
            'eva_nistor' => ['present', 'present', 'absent_excused', 'present', 'present', 'present', 'absent_excused', 'absent_excused'],
            'rares_mocanu' => ['present', 'present', 'present', 'present', 'absent_unexcused', 'present', 'present', 'present'],
            'daria_neagu' => ['present', 'present', 'present', 'present', 'present', 'present', 'present', 'present'],
            'tudor_barbu' => ['present', 'present', 'absent_unexcused', 'present', 'present', 'present', 'present', 'present'],
        ];
    }

    /**
     * @return array<string, list<array<string, int|string>>>
     */
    private function evaluationPlan(): array
    {
        return [
            'luca_marin' => $this->standardPlan('ready', 6),
            'sofia_radu' => $this->standardPlan('ready', 9),
            'matei_dinu' => $this->standardPlan('almost', 5),
            'emma_pavel' => $this->standardPlan('almost', 4),
            'david_ilie' => $this->standardPlan('ready', 8),
            'ana_toma' => $this->standardPlan('almost', 11),
            'teodor_stan' => $this->standardPlan('hold', 7),
            'ilinca_pop' => $this->standardPlan('ready', 10),
            'victor_oprea' => $this->standardPlan('almost', 12),
            'maria_enache' => $this->standardPlan('hold', 3),
            'alex_tudor' => $this->standardPlan('hold', 13),
            'eva_nistor' => $this->standardPlan('almost', 20),
            'rares_mocanu' => $this->standardPlan('hold', 14),
            'daria_neagu' => [
                ['type' => 'full-evaluation', 'days_ago' => 58, 'template' => 'full_hold_old', 'note' => 'Ultima evaluare completa este depasita si necesita refresh.'],
            ],
            'tudor_barbu' => [
                ['type' => 'full-evaluation', 'days_ago' => 75, 'template' => 'full_hold_old', 'note' => 'Evaluare istorica pastrata pentru traseul copilului.'],
            ],
        ];
    }

    /**
     * @return list<array<string, int|string>>
     */
    private function standardPlan(string $status, int $latestFullDaysAgo): array
    {
        return match ($status) {
            'ready' => [
                ['type' => 'full-evaluation', 'days_ago' => 52, 'template' => 'full_ready_old', 'note' => 'Evaluare completa de referinta, aproape de READY.'],
                ['type' => 'quick-check', 'days_ago' => 18, 'template' => 'quick_ready', 'note' => 'Quick Check pozitiv, progres confirmat intre evaluari.'],
                ['type' => 'full-evaluation', 'days_ago' => $latestFullDaysAgo, 'template' => 'full_ready', 'note' => 'Evaluare completa recenta, copil pregatit pentru discutie de promovare.'],
            ],
            'almost' => [
                ['type' => 'full-evaluation', 'days_ago' => 49, 'template' => 'full_almost_old', 'note' => 'Evaluare anterioara cu progres constant, dar sub pragul final.'],
                ['type' => 'quick-check', 'days_ago' => 16, 'template' => 'quick_almost', 'note' => 'Quick Check de monitorizare, copil aproape de READY.'],
                ['type' => 'full-evaluation', 'days_ago' => $latestFullDaysAgo, 'template' => 'full_almost', 'note' => 'Evaluare completa recenta, copil aproape gata pentru nivelul urmator.'],
            ],
            default => [
                ['type' => 'full-evaluation', 'days_ago' => 47, 'template' => 'full_hold_old', 'note' => 'Evaluare anterioara cu blocaj pe criteriile critice.'],
                ['type' => 'quick-check', 'days_ago' => 15, 'template' => 'quick_hold', 'note' => 'Quick Check folosit pentru monitorizare interna si alerta.'],
                ['type' => 'full-evaluation', 'days_ago' => $latestFullDaysAgo, 'template' => 'full_hold', 'note' => 'Evaluare completa recenta, copilul ramane in HOLD.'],
            ],
        };
    }

    /**
     * @return array<string, array<string, float>>
     */
    private function scoreTemplates(): array
    {
        return [
            'full_ready_old' => [
                'water-confidence' => 3.8,
                'breathing-control' => 3.9,
                'stroke-technique' => 4.0,
                'start-turn-basics' => 3.6,
                'race-awareness' => 3.7,
                'focus-effort' => 3.9,
            ],
            'full_ready' => [
                'water-confidence' => 4.4,
                'breathing-control' => 4.2,
                'stroke-technique' => 4.5,
                'start-turn-basics' => 4.0,
                'race-awareness' => 4.1,
                'focus-effort' => 4.4,
            ],
            'full_almost_old' => [
                'water-confidence' => 3.2,
                'breathing-control' => 3.3,
                'stroke-technique' => 3.4,
                'start-turn-basics' => 3.0,
                'race-awareness' => 3.1,
                'focus-effort' => 3.3,
            ],
            'full_almost' => [
                'water-confidence' => 3.6,
                'breathing-control' => 3.7,
                'stroke-technique' => 3.8,
                'start-turn-basics' => 3.4,
                'race-awareness' => 3.5,
                'focus-effort' => 3.7,
            ],
            'full_hold_old' => [
                'water-confidence' => 2.9,
                'breathing-control' => 3.0,
                'stroke-technique' => 2.8,
                'start-turn-basics' => 3.1,
                'race-awareness' => 3.0,
                'focus-effort' => 3.2,
            ],
            'full_hold' => [
                'water-confidence' => 3.0,
                'breathing-control' => 3.1,
                'stroke-technique' => 2.9,
                'start-turn-basics' => 3.2,
                'race-awareness' => 3.0,
                'focus-effort' => 3.3,
            ],
            'quick_ready' => [
                'water-confidence' => 4.3,
                'breathing-control' => 4.1,
                'stroke-technique' => 4.3,
                'focus-effort' => 4.4,
            ],
            'quick_almost' => [
                'water-confidence' => 3.7,
                'breathing-control' => 3.6,
                'stroke-technique' => 3.7,
                'focus-effort' => 3.8,
            ],
            'quick_hold' => [
                'water-confidence' => 3.0,
                'breathing-control' => 3.0,
                'stroke-technique' => 2.8,
                'focus-effort' => 3.2,
            ],
        ];
    }

    private function groupCoachKey(string $groupKey): string
    {
        return match ($groupKey) {
            'red_sparks' => 'coach_andrei',
            'orange_aces' => 'coach_ioana',
            default => 'coach_mihai',
        };
    }

    private function childAttendsSession(string $status, int $offset): bool
    {
        if ($status === 'left' && $offset > -18) {
            return false;
        }

        if ($status === 'pause' && $offset > -8) {
            return false;
        }

        return true;
    }
}
