<?php

class AdminController
{
    public function dashboard(): void
    {
        Auth::requireAdmin();
        View::render('admin/dashboard', [
            'studentsCount' => User::countStudents(),
            'appointmentsCount' => Appointment::countBooked(),
            'completedLessonsCount' => Appointment::countCompleted(),
            'upcomingSlots' => Slot::upcoming(12),
            'unreadMessages' => Communication::unreadCount('admin', Auth::id()),
            'unreadAudioMessages' => Communication::unreadAudioCount('admin', Auth::id()),
            'theoryGroupsCount' => count(TheoryGroup::all()),
            'pendingChargesCount' => count(array_filter(PaymentCenter::charges(), static fn(array $charge): bool => ($charge['status'] ?? '') === 'pending')),
        ]);
    }

    public function students(): void
    {
        Auth::requireAdmin();
        $students = User::allStudents();
        View::render('admin/students', [
            'students' => $students,
            'pendingStudents' => User::pendingStudents(),
            'lessonPackageMap' => StudentLessonPackage::mapForStudents(array_column($students, 'id')),
        ]);
    }

    public function approveStudent(): void
    {
        Auth::requireAdmin(); CSRF::check();
        $result=User::approveStudent((int)($_POST['student_id']??0));
        flash($result['ok']?'success':'danger',$result['message']);
        redirect('admin/students');
    }

    public function saveStudent(): void
    {
        Auth::requireAdmin();
        CSRF::check();
        $result = User::createStudentByAdmin($_POST);
        flash($result['ok'] ? 'success' : 'danger', $result['message']);
        redirect('admin/students');
    }

    public function updateStudent(): void
    {
        Auth::requireAdmin();
        CSRF::check();
        $result = User::updateStudentByAdmin((int)($_POST['student_id'] ?? 0), $_POST);
        flash($result['ok'] ? 'success' : 'danger', $result['message']);
        redirect('admin/students');
    }

    public function saveStudentPackage(): void
    {
        Auth::requireAdmin();
        CSRF::check();
        $result = StudentLessonPackage::saveProcessAndPackages((int)($_POST['student_id'] ?? 0), $_POST);
        flash($result['ok'] ? 'success' : 'danger', $result['message']);
        redirect('admin/students');
    }


    public function saveStudentNotes(): void
    {
        Auth::requireAdmin();
        CSRF::check();
        $result = User::updateAdminNotes((int)($_POST['student_id'] ?? 0), trim($_POST['admin_notes'] ?? ''));
        flash($result['ok'] ? 'success' : 'danger', $result['message']);
        redirect('admin/students');
    }

    public function finishStudent(): void
    {
        Auth::requireAdmin();
        CSRF::check();
        $ok = User::finishStudent((int)($_POST['student_id'] ?? 0));
        flash($ok ? 'success' : 'danger', $ok ? 'Cadastro marcado como finalizado.' : 'Não foi possivel finalizar este cadastro.');
        redirect('admin/students');
    }

    public function reactivateStudent(): void
    {
        Auth::requireAdmin();
        CSRF::check();
        $ok = User::reactivateStudent((int)($_POST['student_id'] ?? 0));
        flash($ok ? 'success' : 'danger', $ok ? 'Cadastro reativado.' : 'Não foi possivel reativar este cadastro.');
        redirect('admin/students');
    }

    public function deleteFinishedStudent(): void
    {
        Auth::requireAdmin();
        CSRF::check();
        $result = User::deleteFinishedStudent((int)($_POST['student_id'] ?? 0));
        flash($result['ok'] ? 'success' : 'danger', $result['message']);
        redirect('admin/students');
    }

    public function appointments(): void
    {
        Auth::requireAdmin();
        $filters = [
            'date' => $_GET['date'] ?? '',
            'professional_id' => $_GET['professional_id'] ?? '',
            'student' => $_GET['student'] ?? '',
            'history_student_id' => $_GET['history_student_id'] ?? '',
        ];
        $historyStudentId = (int)($filters['history_student_id'] ?? 0);
        $weekParam = trim((string)($_GET['week'] ?? date('Y-m-d')));
        $weekDt = DateTime::createFromFormat('Y-m-d', $weekParam) ?: new DateTime();
        $weekDt->modify('monday this week');
        $weekStart = $weekDt->format('Y-m-d');
        $weekAppointments = Appointment::weeklyAdminBoard($weekStart);
        $activeStudents = User::activeStudents();
        $studentBookingSummaries = [];
        $schedulableStudents = [];
        foreach ($activeStudents as $activeStudent) {
            $summary = Appointment::studentBookingSummary((int)$activeStudent['id']);
            $studentBookingSummaries[(int)$activeStudent['id']] = $summary;
            if (!empty($summary['has_packages']) && (int)($summary['available_to_schedule'] ?? 0) > 0) {
                $schedulableStudents[] = $activeStudent;
            }
        }
        View::render('admin/appointments', [
            'appointments' => Appointment::all($filters),
            'professionals' => Professional::allActive(),
            'students' => $schedulableStudents,
            'studentBookingSummaries' => $studentBookingSummaries,
            'allStudents' => User::allStudents(),
            'studentHistory' => $historyStudentId > 0 ? Appointment::byStudentHistory($historyStudentId) : [],
            'historyStudentId' => $historyStudentId,
            'filters' => $filters,
            'holidays' => Holiday::activeAll(),
            'professionalDayOffRules' => ProfessionalDayOff::allRules(),
            'weekStart' => $weekStart,
            'weekAppointments' => $weekAppointments,
        ]);
    }



    public function saveAppointmentPackageQuick(): void
    {
        Auth::requireAdmin(); CSRF::check();
        $studentId=(int)($_POST['student_id']??0); $category=normalize_driving_category($_POST['category']??'');
        $qtyA=max(0,(int)($_POST['lessons_a']??0)); $qtyB=max(0,(int)($_POST['lessons_b']??0)); $qtyOther=max(0,(int)($_POST['lessons_other']??0));
        if($category==='AB'){ $result=StudentLessonPackage::saveProcessAndPackages($studentId,['license_process'=>'first_license','lessons_a'=>max(2,$qtyA),'lessons_b'=>max(2,$qtyB)]); }
        elseif($category==='A'||$category==='B'){ $result=StudentLessonPackage::saveProcessAndPackages($studentId,['license_process'=>'first_license','lessons_a'=>$category==='A'?max(2,$qtyA):0,'lessons_b'=>$category==='B'?max(2,$qtyB):0]); }
        elseif(in_array($category,['C','D','E'],true)){ $result=StudentLessonPackage::saveProcessAndPackages($studentId,['license_process'=>'classification','classification_category'=>$category,'classification_lessons'=>max(2,$qtyOther)]); }
        else $result=['ok'=>false,'message'=>'Selecione uma categoria válida.'];
        flash($result['ok']?'success':'danger',$result['message']); redirect('admin/appointments',['date'=>trim($_POST['date']??'')]);
    }

    public function saveManualAppointment(): void
    {
        Auth::requireAdmin();
        CSRF::check();
        $result = Appointment::bookManualByAdmin(
            (int)($_POST['student_id'] ?? 0),
            (int)($_POST['professional_id'] ?? 0),
            trim($_POST['date'] ?? ''),
            trim($_POST['time'] ?? ''),
            (int)($_POST['duration'] ?? 50),
            trim($_POST['lesson_color'] ?? 'blue'),
            !empty($_POST['allow_holiday']),
            trim($_POST['lesson_category'] ?? ''),
            trim($_POST['lesson_subject'] ?? ''),
            trim($_POST['lesson_process'] ?? ''),
            !empty($_POST['allow_daily_limit_override'])
        );
        flash($result['ok'] ? 'success' : 'danger', $result['message']);
        redirect('admin/appointments', ['date' => trim($_POST['date'] ?? '')]);
    }


    public function rescheduleAppointment(): void
    {
        Auth::requireAdmin();
        CSRF::check();
        $result = Appointment::rescheduleByAdmin(
            (int)($_POST['appointment_id'] ?? 0), trim($_POST['new_date'] ?? ''), trim($_POST['new_time'] ?? ''),
            (int)($_POST['duration'] ?? 50), !empty($_POST['allow_holiday']), !empty($_POST['allow_daily_limit_override'])
        );
        flash($result['ok'] ? 'success' : 'danger', $result['message']);
        redirect('admin/appointments', ['date' => trim($_POST['return_date'] ?? $_POST['new_date'] ?? '')]);
    }

    public function saveProfessionalDayOff(): void
    {
        Auth::requireAdmin(); CSRF::check();
        $result = ProfessionalDayOff::save((int)($_POST['professional_id'] ?? 0), trim($_POST['off_date'] ?? ''), (int)($_POST['recurrence_days'] ?? 0), trim($_POST['note'] ?? ''));
        flash($result['ok'] ? 'success' : 'danger', $result['message']);
        redirect('admin/appointments');
    }

    public function deleteProfessionalDayOff(): void
    {
        Auth::requireAdmin(); CSRF::check();
        $ok = ProfessionalDayOff::delete((int)($_POST['day_off_id'] ?? 0));
        flash($ok ? 'success' : 'danger', $ok ? 'Folga removida.' : 'Folga não encontrada.');
        redirect('admin/appointments');
    }

    public function professionalOptionsJson(): void
    {
        Auth::requireAdmin();
        $date = trim($_GET['date'] ?? '');
        $units = max(1, min(8, (int)($_GET['units'] ?? 1)));
        header('Content-Type: application/json; charset=UTF-8');
        echo json_encode(['ok'=>true,'professionals'=>Appointment::professionalOptionsForDate($date,$units)], JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES);
        exit;
    }

    public function updateAppointmentLesson(): void
    {
        Auth::requireAdmin();
        CSRF::check();
        $result = Appointment::updateLessonByAdmin(
            (int)($_POST['appointment_id'] ?? 0),
            trim($_POST['lesson_category'] ?? ''),
            trim($_POST['lesson_subject'] ?? ''),
            trim($_POST['lesson_process'] ?? '')
        );
        flash($result['ok'] ? 'success' : 'danger', $result['message']);
        redirect('admin/appointments', ['date' => trim($_POST['date'] ?? '')]);
    }

    public function deleteHistoricalAppointment(): void
    { Auth::requireAdmin(); CSRF::check(); $result=Appointment::deleteHistoricalByAdmin((int)($_POST['appointment_id']??0)); flash($result['ok']?'success':'danger',$result['message']); redirect('admin/appointments',['history_student_id'=>(int)($_POST['student_id']??0)]); }

    public function deleteHistoricalStudent(): void
    { Auth::requireAdmin(); CSRF::check(); $studentId=(int)($_POST['student_id']??0); $result=Appointment::deleteHistoricalForStudentByAdmin($studentId); flash($result['ok']?'success':'danger',$result['message']); redirect('admin/appointments',['history_student_id'=>$studentId]); }

    public function reopenCompletedLesson(): void
    {
        Auth::requireAdmin();
        CSRF::check();
        $result = Appointment::reopenCompletionByAdmin((int)($_POST['appointment_id'] ?? 0));
        flash($result['ok'] ? 'success' : 'danger', $result['message']);
        redirect('admin/appointments', ['date' => trim($_POST['date'] ?? '')]);
    }


    public function ratings(): void
    {
        Auth::requireAdmin();
        $filters = [
            'professional_id' => $_GET['professional_id'] ?? '',
            'date_from' => $_GET['date_from'] ?? '',
            'date_to' => $_GET['date_to'] ?? '',
        ];
        View::render('admin/ratings', [
            'ratings' => Appointment::ratings($filters),
            'stats' => Appointment::ratingStats(),
            'professionals' => Professional::allActive(),
            'students' => User::activeStudents(),
            'filters' => $filters,
        ]);
    }



    public function theory(): void
    {
        Auth::requireAdmin();
        View::render('admin/theory', ['lessons' => TheoryLesson::all(true)]);
    }

    public function saveTheory(): void
    {
        Auth::requireAdmin();
        CSRF::check();
        $result = TheoryLesson::save($_POST);
        flash($result['ok'] ? 'success' : 'danger', $result['message']);
        redirect('admin/theory');
    }

    public function deleteTheory(): void
    {
        Auth::requireAdmin();
        CSRF::check();
        $ok = TheoryLesson::delete((int)($_POST['lesson_id'] ?? 0));
        flash($ok ? 'success' : 'danger', $ok ? 'Aula teórica apagada.' : 'Não foi possivel apagar a aula teórica.');
        redirect('admin/theory');
    }

    public function availability(): void
    {
        Auth::requireAdmin();
        $month = $_GET['month'] ?? date('Y-m');
        if (!preg_match('/^\d{4}-\d{2}$/', $month)) {
            $month = date('Y-m');
        }
        View::render('admin/availability', [
            'professionals' => Professional::allActive(),
            'slots' => Slot::byMonthForStudent($month, 0),
            'month' => $month,
        ]);
    }

    public function saveAvailability(): void
    {
        Auth::requireAdmin();
        CSRF::check();
        $professionalId = (int)($_POST['professional_id'] ?? 0);
        $start = $_POST['start_date'] ?? date('Y-m-d');
        $end = $_POST['end_date'] ?? date('Y-m-d');
        $weekdays = array_map('intval', $_POST['weekdays'] ?? []);
        $hoursRaw = trim($_POST['hours'] ?? '');
        $hours = array_filter(array_map('trim', preg_split('/[\n,;]+/', $hoursRaw)));
        $duration = max(30, min(240, (int)($_POST['duration'] ?? 50)));

        if (!$professionalId || !$weekdays || !$hours) {
            flash('danger', 'Selecione profissional, dias da semana e horários.');
            redirect('admin/availability');
        }

        $created = Slot::createRecurring($professionalId, $start, $end, $weekdays, $hours, $duration);
        flash('success', $created . ' horário(s) criado(s). Duplicados foram ignorados.');
        redirect('admin/availability', ['month' => substr($start, 0, 7)]);
    }

    public function deleteSlot(): void
    {
        Auth::requireAdmin();
        CSRF::check();
        $ok = Slot::deactivate((int)($_POST['slot_id'] ?? 0));
        flash($ok ? 'success' : 'danger', $ok ? 'Horário removido.' : 'Não e possivel remover um horário já agendado.');
        redirect('admin/availability', ['month' => $_POST['month'] ?? date('Y-m')]);
    }

    public function professionals(): void
    {
        Auth::requireAdmin();
        $historyProfessionalId = (int)($_GET['history_professional_id'] ?? 0);
        $historyMonth = $_GET['history_month'] ?? date('Y-m');
        if (!preg_match('/^\d{4}-\d{2}$/', $historyMonth)) {
            $historyMonth = date('Y-m');
        }
        View::render('admin/professionals', [
            'professionals' => Professional::all(),
            'historyProfessionalId' => $historyProfessionalId,
            'historyMonth' => $historyMonth,
            'professionalMonthAppointments' => $historyProfessionalId > 0 ? Appointment::byProfessionalMonth($historyProfessionalId, $historyMonth) : [],
        ]);
    }

    public function saveProfessional(): void
    {
        Auth::requireAdmin();
        CSRF::check();
        $id = (int)($_POST['professional_id'] ?? 0);
        $name = trim($_POST['name'] ?? '');
        $type = trim($_POST['type'] ?? 'Instrutor');
        $whatsapp = trim($_POST['whatsapp'] ?? '');
        $username = trim($_POST['username'] ?? '');
        $password = (string)($_POST['password'] ?? '');
        $adminNotes = trim($_POST['admin_notes'] ?? '');
        $accessEnabled = isset($_POST['access_enabled']) ? 1 : 0;
        $canManageTheoryGroups = isset($_POST['can_manage_theory_groups']) ? 1 : 0;
        $canManageTheoryVideos = isset($_POST['can_manage_theory_videos']) ? 1 : 0;
        $dailyLessonLimit = max(0, min(99, (int)($_POST['daily_lesson_limit'] ?? 0)));
        if ($name === '') {
            flash('danger', 'Informe o nome do profissional.');
            redirect('admin/professionals');
        }
        if ($id > 0) {
            $result = Professional::update($id, $name, $type, $whatsapp, $username, $password, $accessEnabled, $adminNotes, $canManageTheoryGroups, $canManageTheoryVideos, $dailyLessonLimit);
        } else {
            if ($password !== '' && strlen($password) < 6) {
                flash('danger', 'A senha do instrutor precisa ter no mínimo 6 caracteres.');
                redirect('admin/professionals');
            }
            $result = Professional::create($name, $type, $whatsapp, $username, $password, $adminNotes, $canManageTheoryGroups, $canManageTheoryVideos, $dailyLessonLimit);
        }
        flash($result['ok'] ? 'success' : 'danger', $result['message']);
        redirect('admin/professionals');
    }


    public function saveProfessionalNotes(): void
    {
        Auth::requireAdmin();
        CSRF::check();
        $result = Professional::updateAdminNotes((int)($_POST['professional_id'] ?? 0), trim($_POST['admin_notes'] ?? ''));
        flash($result['ok'] ? 'success' : 'danger', $result['message']);
        redirect('admin/professionals');
    }

    public function deleteProfessional(): void
    {
        Auth::requireAdmin();
        CSRF::check();
        $result = Professional::delete((int)($_POST['professional_id'] ?? 0));
        flash($result['ok'] ? 'success' : 'danger', $result['message']);
        redirect('admin/professionals');
    }

    public function toggleProfessional(): void
    {
        Auth::requireAdmin();
        CSRF::check();
        Professional::toggle((int)($_POST['professional_id'] ?? 0));
        flash('success', 'Status atualizado.');
        redirect('admin/professionals');
    }

    public function refreshProfessionalToken(): void
    {
        Auth::requireAdmin();
        CSRF::check();
        Professional::refreshToken((int)($_POST['professional_id'] ?? 0));
        flash('success', 'Link do painel do profissional renovado.');
        redirect('admin/professionals');
    }




    public function ebooks(): void
    {
        Auth::requireAdmin();
        View::render('admin/ebooks', [
            'ebooks' => Ebook::all(),
            'students' => User::activeStudents(),
            'accessList' => Ebook::accessMap(),
            'groups' => TheoryGroup::all(),
        ]);
    }

    public function saveEbook(): void
    {
        Auth::requireAdmin();
        CSRF::check();
        $result = Ebook::createFromUpload($_POST, $_FILES['ebook_file'] ?? [], $_FILES['cover_image'] ?? []);
        flash($result['ok'] ? 'success' : 'danger', $result['message']);
        redirect('admin/ebooks');
    }

    public function updateEbookCover(): void
    {
        Auth::requireAdmin();
        CSRF::check();
        $result = Ebook::updateCover((int)($_POST['ebook_id'] ?? 0), $_FILES['cover_image'] ?? []);
        flash($result['ok'] ? 'success' : 'danger', $result['message']);
        redirect('admin/ebooks');
    }

    public function toggleEbook(): void
    {
        Auth::requireAdmin();
        CSRF::check();
        $ok = Ebook::toggle((int)($_POST['ebook_id'] ?? 0));
        flash($ok ? 'success' : 'danger', $ok ? 'Status do e-book atualizado.' : 'E-book não encontrado.');
        redirect('admin/ebooks');
    }

    public function deleteEbook(): void
    {
        Auth::requireAdmin();
        CSRF::check();
        $result = Ebook::delete((int)($_POST['ebook_id'] ?? 0));
        flash($result['ok'] ? 'success' : 'danger', $result['message']);
        redirect('admin/ebooks');
    }

    public function grantEbook(): void
    {
        Auth::requireAdmin();
        CSRF::check();
        $recipientType = trim((string)($_POST['recipient_type'] ?? 'student'));
        $recipientId = (int)($_POST['recipient_id'] ?? ($_POST['student_id'] ?? 0));
        $result = $recipientType === 'group'
            ? Ebook::grantToGroup((int)($_POST['ebook_id'] ?? 0), $recipientId)
            : Ebook::grant((int)($_POST['ebook_id'] ?? 0), $recipientId);
        flash($result['ok'] ? 'success' : 'danger', $result['message']);
        redirect('admin/ebooks');
    }

    public function revokeEbook(): void
    {
        Auth::requireAdmin();
        CSRF::check();
        $recipientType = trim((string)($_POST['recipient_type'] ?? 'student'));
        $recipientId = (int)($_POST['recipient_id'] ?? ($_POST['student_id'] ?? 0));
        $ok = $recipientType === 'group'
            ? Ebook::revokeFromGroup((int)($_POST['ebook_id'] ?? 0), $recipientId)
            : Ebook::revoke((int)($_POST['ebook_id'] ?? 0), $recipientId);
        flash($ok ? 'success' : 'danger', $ok ? 'Liberação removida.' : 'Liberação não encontrada.');
        redirect('admin/ebooks');
    }

    public function account(): void
    {
        Auth::requireAdmin();
        View::render('admin/account', ['admin' => Auth::user()]);
    }

    public function saveAccount(): void
    {
        Auth::requireAdmin();
        CSRF::check();
        $newPassword = (string)($_POST['new_password'] ?? '');
        $confirm = (string)($_POST['new_password_confirmation'] ?? '');
        if ($newPassword !== '' && $newPassword !== $confirm) {
            flash('danger', 'A conformação da nova senha não confere.');
            redirect('admin/account');
        }
        $result = User::updateAdminCredentials(
            (int)Auth::id(),
            trim($_POST['name'] ?? ''),
            trim($_POST['email'] ?? ''),
            (string)($_POST['current_password'] ?? ''),
            $newPassword
        );
        flash($result['ok'] ? 'success' : 'danger', $result['message']);
        redirect('admin/account');
    }



    public function updateAppointmentColor(): void
    {
        Auth::requireAdmin();
        CSRF::check();
        $result = Appointment::updateColorByAdmin(
            (int)($_POST['appointment_id'] ?? 0),
            trim($_POST['lesson_color'] ?? 'blue')
        );
        flash($result['ok'] ? 'success' : 'danger', $result['message']);
        redirect('admin/appointments', ['date' => $_POST['date'] ?? '']);
    }

    public function unlockAppointment(): void
    {
        Auth::requireAdmin();
        CSRF::check();
        $result = Appointment::unlockByAdmin((int)($_POST['appointment_id'] ?? 0));
        flash($result['ok'] ? 'success' : 'danger', $result['message']);
        redirect('admin/appointments', ['date' => $_POST['date'] ?? '']);
    }

    public function unlockSlot(): void
    {
        Auth::requireAdmin();
        CSRF::check();
        $result = Slot::unlock((int)($_POST['slot_id'] ?? 0));
        flash($result['ok'] ? 'success' : 'danger', $result['message']);
        redirect('admin/availability', ['month' => $_POST['month'] ?? date('Y-m')]);
    }

    public function professionalMaterials(): void
    {
        Auth::requireAdmin();
        View::render('admin/professional_materials', [
            'materials' => ProfessionalMaterial::all(),
            'professionals' => Professional::allActive(),
        ]);
    }

    public function saveProfessionalMaterial(): void
    {
        Auth::requireAdmin();
        CSRF::check();
        $result = ProfessionalMaterial::createFromUpload($_POST, $_FILES['material_file'] ?? [], $_FILES['cover_image'] ?? []);
        flash($result['ok'] ? 'success' : 'danger', $result['message']);
        redirect('admin/professional-materials');
    }

    public function updateProfessionalMaterialCover(): void
    {
        Auth::requireAdmin();
        CSRF::check();
        $result = ProfessionalMaterial::updateCover((int)($_POST['material_id'] ?? 0), $_FILES['cover_image'] ?? []);
        flash($result['ok'] ? 'success' : 'danger', $result['message']);
        redirect('admin/professional-materials');
    }

    public function toggleProfessionalMaterial(): void
    {
        Auth::requireAdmin();
        CSRF::check();
        $ok = ProfessionalMaterial::toggle((int)($_POST['material_id'] ?? 0));
        flash($ok ? 'success' : 'danger', $ok ? 'Status do material atualizado.' : 'Material nao encontrado.');
        redirect('admin/professional-materials');
    }

    public function deleteProfessionalMaterial(): void
    {
        Auth::requireAdmin();
        CSRF::check();
        $result = ProfessionalMaterial::delete((int)($_POST['material_id'] ?? 0));
        flash($result['ok'] ? 'success' : 'danger', $result['message']);
        redirect('admin/professional-materials');
    }

    public function links(): void
    {
        Auth::requireAdmin();
        View::render('admin/links', ['links' => QuickLink::all()]);
    }

    public function saveLink(): void
    {
        Auth::requireAdmin();
        CSRF::check();
        $result = QuickLink::save($_POST);
        flash($result['ok'] ? 'success' : 'danger', $result['message']);
        redirect('admin/links');
    }

    public function toggleLink(): void
    {
        Auth::requireAdmin();
        CSRF::check();
        $ok = QuickLink::toggle((int)($_POST['link_id'] ?? 0));
        flash($ok ? 'success' : 'danger', $ok ? 'Status do link atualizado.' : 'Link não encontrado.');
        redirect('admin/links');
    }

    public function deleteLink(): void
    {
        Auth::requireAdmin();
        CSRF::check();
        $ok = QuickLink::delete((int)($_POST['link_id'] ?? 0));
        flash($ok ? 'success' : 'danger', $ok ? 'Link apagado.' : 'Link não encontrado.');
        redirect('admin/links');
    }

    public function contacts(): void
    {
        Auth::requireAdmin();
        View::render('admin/contacts', ['contacts' => QuickContact::forOwner('admin')]);
    }

    public function saveContact(): void
    {
        Auth::requireAdmin();
        CSRF::check();
        $result = QuickContact::save('admin', null, $_POST);
        flash($result['ok'] ? 'success' : 'danger', $result['message']);
        redirect('admin/contacts');
    }

    public function deleteContact(): void
    {
        Auth::requireAdmin();
        CSRF::check();
        $ok = QuickContact::delete('admin', null, (int)($_POST['contact_id'] ?? 0));
        flash($ok ? 'success' : 'danger', $ok ? 'Contato apagado.' : 'Contato não encontrado.');
        redirect('admin/contacts');
    }


    public function backups(): void
    {
        Auth::requireAdmin();
        View::render('admin/backups', [
            'backups' => BackupManager::list(),
            'zipEnabled' => class_exists('ZipArchive'),
            'archiveEnabled' => BackupManager::archiveAvailable(),
            'archiveMode' => BackupManager::archiveMode(),
            'sqliteDownloadAvailable' => BackupManager::sqliteDatabasePath() !== null,
        ]);
    }

    public function createBackup(): void
    {
        Auth::requireAdmin();
        CSRF::check();
        $result = BackupManager::create();
        flash($result['ok'] ? 'success' : 'danger', $result['message']);
        redirect('admin/backups');
    }

    public function downloadDatabaseBackup(): void
    {
        Auth::requireAdmin();
        CSRF::check();
        $path = BackupManager::sqliteDatabasePath();
        if (!$path) {
            flash('danger', 'O backup rápido do banco só está disponível quando o sistema usa SQLite.');
            redirect('admin/backups');
        }
        while (ob_get_level() > 0) {
            ob_end_clean();
        }
        $filename = 'backup-cfc-banco-' . date('Ymd-His') . '.sqlite';
        header('Content-Type: application/vnd.sqlite3');
        header('Content-Disposition: attachment; filename="' . $filename . '"');
        header('Content-Length: ' . filesize($path));
        header('X-Content-Type-Options: nosniff');
        header('Cache-Control: no-store, private');
        readfile($path);
        exit;
    }

    public function downloadBackup(): void
    {
        Auth::requireAdmin();
        $name = basename((string)($_GET['file'] ?? ''));
        $path = BackupManager::pathFor($name);
        if (!$path || !is_file($path)) {
            http_response_code(404);
            exit('Backup nao encontrado.');
        }
        while (ob_get_level() > 0) {
            ob_end_clean();
        }
        $lower=strtolower($path);
        $contentType=str_ends_with($lower,'.zip')?'application/zip':(str_ends_with($lower,'.gz')?'application/gzip':'application/octet-stream');
        header('Content-Type: '.$contentType);
        header('Content-Disposition: attachment; filename="' . basename($path) . '"');
        header('Content-Length: ' . filesize($path));
        header('X-Content-Type-Options: nosniff');
        readfile($path);
        exit;
    }

    public function restoreBackup(): void
    {
        Auth::requireAdmin();
        if (($_SERVER['REQUEST_METHOD'] ?? '') === 'POST' && empty($_POST) && empty($_FILES)) {
            flash('danger', 'O backup ultrapassou o limite post_max_size da hospedagem. Aumente post_max_size/upload_max_filesize ou envie o arquivo para storage/backups e restaure pela lista.');
            redirect('admin/backups');
        }
        CSRF::check();
        $confirm = trim($_POST['confirm_restore'] ?? '');
        if ($confirm !== 'RESTAURAR') {
            flash('danger', 'Para restaurar, digite RESTAURAR no campo de confirmação.');
            redirect('admin/backups');
        }
        $result = BackupManager::restoreFromUpload($_FILES['backup_file'] ?? []);
        flash($result['ok'] ? 'success' : 'danger', $result['message']);
        redirect('admin/backups');
    }

    public function restoreSavedBackup(): void
    {
        Auth::requireAdmin();
        CSRF::check();
        $confirm = trim($_POST['confirm_restore_saved'] ?? '');
        if ($confirm !== 'RESTAURAR') {
            flash('danger', 'Para restaurar o backup salvo, digite RESTAURAR no campo de confirmação.');
            redirect('admin/backups');
        }
        $result = BackupManager::restoreFromSaved((string)($_POST['file'] ?? ''));
        flash($result['ok'] ? 'success' : 'danger', $result['message']);
        redirect('admin/backups');
    }

    public function deleteBackup(): void
    {
        Auth::requireAdmin();
        CSRF::check();
        $result = BackupManager::delete((string)($_POST['file'] ?? ''));
        flash($result['ok'] ? 'success' : 'danger', $result['message']);
        redirect('admin/backups');
    }


    public function holidays(): void
    {
        Auth::requireAdmin();
        View::render('admin/holidays', ['holidays' => Holiday::all()]);
    }

    public function saveHoliday(): void
    {
        Auth::requireAdmin();
        CSRF::check();
        $result = Holiday::save($_POST);
        flash($result['ok'] ? 'success' : 'danger', $result['message']);
        redirect('admin/holidays');
    }

    public function deleteHoliday(): void
    {
        Auth::requireAdmin();
        CSRF::check();
        $ok = Holiday::delete((int)($_POST['holiday_id'] ?? 0));
        flash($ok ? 'success' : 'danger', $ok ? 'Feriado apagado.' : 'Feriado não encontrado.');
        redirect('admin/holidays');
    }

    public function studentPayments(): void
    {
        Auth::requireAdmin();
        View::render('admin/student_payments', [
            'payments' => StudentPayment::all(),
            'students' => User::activeStudents(),
        ]);
    }

    public function saveStudentPayment(): void
    {
        Auth::requireAdmin();
        CSRF::check();
        $result = StudentPayment::save($_POST);
        flash($result['ok'] ? 'success' : 'danger', $result['message']);
        redirect('admin/student-payments');
    }

    public function deleteStudentPayment(): void
    {
        Auth::requireAdmin();
        CSRF::check();
        $ok = StudentPayment::delete((int)($_POST['payment_id'] ?? 0));
        flash($ok ? 'success' : 'danger', $ok ? 'Pagamento apagado.' : 'Pagamento não encontrado.');
        redirect('admin/student-payments');
    }


    public function beginnerTraining(): void
    {
        Auth::requireAdmin();
        View::render('admin/beginner_training', [
            'beginners' => BeginnerInstructor::all(),
            'contents' => TrainingContent::all(),
            'orders' => TrainingOrder::all(),
        ]);
    }

    public function saveTrainingContent(): void
    {
        Auth::requireAdmin();
        CSRF::check();
        $result = TrainingContent::save($_POST, $_FILES['content_file'] ?? [], $_FILES['cover_image'] ?? []);
        flash($result['ok'] ? 'success' : 'danger', $result['message']);
        redirect('admin/beginner-training');
    }

    public function updateTrainingContentCover(): void
    {
        Auth::requireAdmin();
        CSRF::check();
        $result = TrainingContent::updateCover((int)($_POST['content_id'] ?? 0), $_FILES['cover_image'] ?? []);
        flash($result['ok'] ? 'success' : 'danger', $result['message']);
        redirect('admin/beginner-training');
    }

    public function toggleTrainingContent(): void
    {
        Auth::requireAdmin();
        CSRF::check();
        $ok = TrainingContent::toggle((int)($_POST['content_id'] ?? 0));
        flash($ok ? 'success' : 'danger', $ok ? 'Conteúdo atualizado.' : 'Conteúdo não encontrado.');
        redirect('admin/beginner-training');
    }

    public function deleteTrainingContent(): void
    {
        Auth::requireAdmin();
        CSRF::check();
        $result = TrainingContent::delete((int)($_POST['content_id'] ?? 0));
        flash($result['ok'] ? 'success' : 'danger', $result['message']);
        redirect('admin/beginner-training');
    }

    public function saveTrainingCharge(): void
    {
        Auth::requireAdmin();
        CSRF::check();
        $result = TrainingOrder::saveCharge($_POST);
        flash($result['ok'] ? 'success' : 'danger', $result['message']);
        redirect('admin/beginner-training');
    }

    public function updateTrainingOrder(): void
    {
        Auth::requireAdmin();
        CSRF::check();
        $result = TrainingOrder::updateStatus((int)($_POST['order_id'] ?? 0), trim($_POST['status'] ?? ''), trim($_POST['admin_message'] ?? ''));
        flash($result['ok'] ? 'success' : 'danger', $result['message']);
        redirect('admin/beginner-training');
    }

    public function updateBeginnerStatus(): void
    {
        Auth::requireAdmin();
        CSRF::check();
        $result = BeginnerInstructor::updateStatus((int)($_POST['beginner_id'] ?? 0), trim($_POST['status'] ?? ''), trim($_POST['admin_notes'] ?? ''));
        flash($result['ok'] ? 'success' : 'danger', $result['message']);
        redirect('admin/beginner-training');
    }

    public function deleteBeginnerInstructor(): void
    {
        Auth::requireAdmin(); CSRF::check();
        $result = BeginnerInstructor::delete((int)($_POST['beginner_id'] ?? 0));
        flash($result['ok'] ? 'success' : 'danger', $result['message']);
        redirect('admin/beginner-training');
    }

    public function viewTrainingProof(): void
    {
        Auth::requireAdmin();
        $order = TrainingOrder::proofForAdmin((int)($_GET['id'] ?? 0));
        if (!$order) {
            http_response_code(404);
            exit('Comprovante não encontrado.');
        }
        TrainingOrder::streamProof($order);
    }


    public function settings(): void
    {
        Auth::requireAdmin();
        View::render('admin/settings', ['settings' => Settings::safeAll()]);
    }

    public function saveSettings(): void
    {
        Auth::requireAdmin();
        CSRF::check();
        $textKeys = [
            'site_name', 'top_phone', 'address', 'google_maps_url', 'waze_url', 'instagram_url', 'facebook_url',
            'contact_button_text', 'hero_title', 'hero_subtitle', 'hero_button_text',
            'hero_button_url', 'hero_years', 'info_text', 'about_title', 'about_text',
            'services_title', 'services_text', 'service_1_title', 'service_1_items', 'service_1_icon',
            'service_2_title', 'service_2_items', 'service_2_icon', 'service_3_title', 'service_3_items', 'service_3_icon',
            'cta_title', 'cta_text', 'cta_button_text', 'links_title', 'links_text',
            'useful_link_1_title', 'useful_link_1_url', 'useful_link_2_title', 'useful_link_2_url',
            'more_info_title', 'more_info_text', 'more_info_1_title', 'more_info_1_items',
            'more_info_2_title', 'more_info_2_items', 'more_info_3_title', 'more_info_3_items',
            'more_info_4_title', 'more_info_4_items', 'category_acc_text', 'category_a_text', 'category_b_text',
            'category_ab_text', 'category_c_text', 'category_d_text', 'category_e_text', 'pix_key',
            'detran_simulado_url', 'detran_simulado_button_text',
            'receipt_company_name', 'receipt_company_document'
        ];
        $data = [];
        foreach ($textKeys as $key) {
            $data[$key] = trim($_POST[$key] ?? '');
        }
        $data['whatsapp_support'] = trim($_POST['whatsapp_support'] ?? '');

        foreach (['logo_path' => 'logo', 'banner_path' => 'banner', 'hero_vehicle_path' => 'hero_vehicle', 'cta_background_path' => 'cta_background', 'pix_qr_path' => 'pix_qr'] as $settingKey => $inputName) {
            $path = $this->handleUpload($inputName);
            if ($path) {
                $data[$settingKey] = $path;
            }
        }
        Settings::saveMany($data);
        flash('success', 'Configurações atualizadas.');
        redirect('admin/settings');
    }

    private function handleUpload(string $input): ?string
    {
        if (empty($_FILES[$input]['tmp_name']) || ($_FILES[$input]['error'] ?? UPLOAD_ERR_NO_FILE) !== UPLOAD_ERR_OK) {
            return null;
        }
        $maxBytes = (int)config_value('uploads.max_size_mb', 3) * 1024 * 1024;
        if (($_FILES[$input]['size'] ?? 0) > $maxBytes) {
            flash('warning', 'Arquivo ' . $input . ' excede o limite permitido.');
            return null;
        }
        $finfo = new finfo(FILEINFO_MIME_TYPE);
        $mime = $finfo->file($_FILES[$input]['tmp_name']);
        if (!in_array($mime, config_value('uploads.allowed_mimes', []), true)) {
            flash('warning', 'Arquivo ' . $input . ' não e uma imagem valida.');
            return null;
        }
        $ext = match ($mime) {
            'image/jpeg' => 'jpg',
            'image/png' => 'png',
            'image/webp' => 'webp',
            'image/gif' => 'gif',
            default => 'bin',
        };
        $filename = $input . '_' . bin2hex(random_bytes(8)) . '.' . $ext;
        $dest = UPLOAD_PATH . '/' . $filename;
        if (!move_uploaded_file($_FILES[$input]['tmp_name'], $dest)) {
            flash('warning', 'Não foi possivel salvar o arquivo ' . $input . '.');
            return null;
        }
        return 'uploads/' . $filename;
    }

    public function videoLessons(): void
    {
        Auth::requireAdmin();
        View::render('admin/video_lessons', [
            'videos' => VideoLesson::all(),
            'students' => User::activeStudents(),
            'professionals' => Professional::allActive(),
            'beginners' => BeginnerInstructor::all(),
            'accessMap' => VideoLesson::accessMap(),
            'groups' => TheoryGroup::all(),
        ]);
    }

    public function saveVideoLesson(): void
    {
        Auth::requireAdmin();
        if (($_SERVER['REQUEST_METHOD'] ?? '') === 'POST' && empty($_POST) && empty($_FILES)) {
            flash('danger', 'O envio ultrapassou o limite post_max_size da hospedagem. Aumente post_max_size e upload_max_filesize.');
            redirect('admin/video-lessons');
        }
        CSRF::check();
        $result = VideoLesson::save($_POST, $_FILES['video_file'] ?? [], $_FILES['cover_image'] ?? []);
        flash($result['ok'] ? 'success' : 'danger', $result['message']);
        redirect('admin/video-lessons');
    }

    public function uploadVideoChunk(): void
    {
        Auth::requireAdmin();
        header('Content-Type: application/json; charset=UTF-8');

        // Quando post_max_size é menor que o bloco recebido, o PHP entrega
        // POST e FILES vazios. Respondemos em JSON para o navegador exibir a
        // causa correta em vez de uma página branca/erro de sessão.
        if (($_SERVER['REQUEST_METHOD'] ?? '') === 'POST' && empty($_POST) && empty($_FILES)) {
            http_response_code(413);
            echo json_encode([
                'ok' => false,
                'message' => 'A hospedagem recusou esta parte do vídeo por limite de upload. O sistema usa blocos de 512 KB; verifique post_max_size e upload_max_filesize.',
            ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
            exit;
        }

        try {
            CSRF::check();
            $result = PortalMedia::storeVideoChunk($_FILES['file_chunk'] ?? [], $_POST);
            if (empty($result['ok'])) {
                http_response_code(422);
            }
            echo json_encode($result, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
        } catch (Throwable $e) {
            http_response_code(500);
            echo json_encode(['ok' => false, 'message' => 'Falha ao receber parte do vídeo: ' . $e->getMessage()], JSON_UNESCAPED_UNICODE);
        }
        exit;
    }

    public function toggleVideoLesson(): void
    {
        Auth::requireAdmin(); CSRF::check();
        $ok = VideoLesson::toggle((int)($_POST['video_lesson_id'] ?? 0));
        flash($ok ? 'success' : 'danger', $ok ? 'Status da videoaula atualizado.' : 'Videoaula não encontrada.');
        redirect('admin/video-lessons');
    }

    public function deleteVideoLesson(): void
    {
        Auth::requireAdmin(); CSRF::check();
        $ok = VideoLesson::delete((int)($_POST['video_lesson_id'] ?? 0));
        flash($ok ? 'success' : 'danger', $ok ? 'Videoaula apagada.' : 'Videoaula não encontrada.');
        redirect('admin/video-lessons');
    }

    public function grantVideoLesson(): void
    {
        Auth::requireAdmin(); CSRF::check();
        $ok = VideoLesson::grant((int)($_POST['video_lesson_id'] ?? 0), (string)($_POST['recipient_type'] ?? ''), (int)($_POST['recipient_id'] ?? 0));
        flash($ok ? 'success' : 'danger', $ok ? 'Videoaula liberada individualmente.' : 'Não foi possível liberar.');
        redirect('admin/video-lessons');
    }

    public function revokeVideoLesson(): void
    {
        Auth::requireAdmin(); CSRF::check();
        VideoLesson::revoke((int)($_POST['video_lesson_id'] ?? 0), (string)($_POST['recipient_type'] ?? ''), (int)($_POST['recipient_id'] ?? 0));
        flash('success', 'Liberação individual removida.');
        redirect('admin/video-lessons');
    }

    public function paymentCenter(): void
    {
        Auth::requireAdmin();
        View::render('admin/payment_center', [
            'banks' => PaymentCenter::banks(),
            'charges' => PaymentCenter::charges(),
            'students' => User::activeStudents(),
            'receiptStudents' => User::allStudents(),
            'beginners' => BeginnerInstructor::all(),
            'manualReceipts' => PaymentReceipt::manualAll(),
        ]);
    }

    public function createManualPaymentReceipt(): void
    {
        Auth::requireAdmin(); CSRF::check();
        $result = PaymentReceipt::createManualForStudent($_POST);
        flash($result['ok'] ? 'success' : 'danger', $result['message']);
        redirect('admin/payment-center');
    }

    public function savePaymentBank(): void
    {
        Auth::requireAdmin(); CSRF::check();
        $result = PaymentCenter::saveBank($_POST, $_FILES['bank_image'] ?? []);
        flash($result['ok'] ? 'success' : 'danger', $result['message']);
        redirect('admin/payment-center');
    }

    public function togglePaymentBank(): void
    {
        Auth::requireAdmin(); CSRF::check();
        $ok = PaymentCenter::toggleBank((int)($_POST['bank_id'] ?? 0));
        flash($ok ? 'success' : 'danger', $ok ? 'Status do banco atualizado.' : 'Banco não encontrado.');
        redirect('admin/payment-center');
    }

    public function deletePaymentBank(): void
    {
        Auth::requireAdmin(); CSRF::check();
        $result = PaymentCenter::deleteBank((int)($_POST['bank_id'] ?? 0));
        flash($result['ok'] ? 'success' : 'danger', $result['message']);
        redirect('admin/payment-center');
    }

    public function savePaymentCharge(): void
    {
        Auth::requireAdmin(); CSRF::check();
        $result = PaymentCenter::saveCharge($_POST);
        flash($result['ok'] ? 'success' : 'danger', $result['message']);
        redirect('admin/payment-center');
    }


    public function updatePaymentChargeStatus(): void
    {
        Auth::requireAdmin(); CSRF::check();
        $result = PaymentCenter::updateChargeStatus((int)($_POST['charge_id'] ?? 0), trim((string)($_POST['status'] ?? 'pending')));
        flash($result['ok'] ? 'success' : 'danger', $result['message']);
        redirect('admin/payment-center');
    }

    public function deletePaymentCharge(): void
    {
        Auth::requireAdmin(); CSRF::check();
        $ok = PaymentCenter::deleteCharge((int)($_POST['charge_id'] ?? 0));
        flash($ok ? 'success' : 'danger', $ok ? 'Cobrança apagada.' : 'Cobrança não encontrada.');
        redirect('admin/payment-center');
    }

    public function deletePaymentProof(): void
    {
        Auth::requireAdmin(); CSRF::check();
        $result = PaymentCenter::deleteProof((int)($_POST['charge_id'] ?? 0));
        flash($result['ok'] ? 'success' : 'danger', $result['message']);
        redirect('admin/payment-center');
    }

    public function theoryGroups(): void
    {
        Auth::requireAdmin();
        $editGroupId = (int)($_GET['edit'] ?? 0);
        $editGroup = $editGroupId > 0 ? TheoryGroup::find($editGroupId) : null;
        View::render('admin/theory_groups', [
            'groups' => TheoryGroup::all(),
            'students' => User::activeStudents(),
            'professionals' => Professional::allActive(),
            'editGroup' => $editGroup,
            'editMemberIds' => $editGroup ? array_map('intval', array_column(TheoryGroup::members($editGroupId), 'id')) : [],
        ]);
    }

    public function saveTheoryGroup(): void
    {
        Auth::requireAdmin(); CSRF::check();
        $result = TheoryGroup::save($_POST, $_FILES['group_image'] ?? []);
        flash($result['ok'] ? 'success' : 'danger', $result['message']);
        redirect('admin/theory-groups');
    }

    public function toggleTheoryGroup(): void
    {
        Auth::requireAdmin(); CSRF::check();
        $ok = TheoryGroup::toggle((int)($_POST['group_id'] ?? 0));
        flash($ok ? 'success' : 'danger', $ok ? 'Status da turma atualizado.' : 'Turma não encontrada.');
        redirect('admin/theory-groups');
    }

    public function deleteTheoryGroup(): void
    {
        Auth::requireAdmin(); CSRF::check();
        $ok = TheoryGroup::delete((int)($_POST['group_id'] ?? 0));
        flash($ok ? 'success' : 'danger', $ok ? 'Turma apagada.' : 'Turma não encontrada.');
        redirect('admin/theory-groups');
    }

    public function announcements(): void
    {
        Auth::requireAdmin();
        $editId = (int)($_GET['edit'] ?? 0);
        View::render('admin/announcements', [
            'announcements' => Announcement::all(),
            'editAnnouncement' => $editId > 0 ? Announcement::find($editId) : null,
        ]);
    }

    public function saveAnnouncement(): void
    {
        Auth::requireAdmin();
        CSRF::check();
        $result = Announcement::save($_POST);
        flash($result['ok'] ? 'success' : 'danger', $result['message']);
        redirect('admin/announcements');
    }

    public function toggleAnnouncement(): void
    {
        Auth::requireAdmin();
        CSRF::check();
        $ok = Announcement::toggle((int)($_POST['announcement_id'] ?? 0));
        flash($ok ? 'success' : 'danger', $ok ? 'Status do aviso atualizado.' : 'Aviso não encontrado.');
        redirect('admin/announcements');
    }

    public function deleteAnnouncement(): void
    {
        Auth::requireAdmin();
        CSRF::check();
        $ok = Announcement::delete((int)($_POST['announcement_id'] ?? 0));
        flash($ok ? 'success' : 'danger', $ok ? 'Aviso apagado.' : 'Aviso não encontrado.');
        redirect('admin/announcements');
    }

    public function messages(): void
    {
        Auth::requireAdmin();
        redirect('portal/messages');
    }

}
