<?php
class ProfessionalController
{
    public function login(): void
    {
        View::render('professional/login');
    }

    public function doLogin(): void
    {
        CSRF::check();
        $ok = Professional::login(trim($_POST['username'] ?? ''), (string)($_POST['password'] ?? ''));
        if (!$ok) {
            flash('danger', 'Usuário ou senha do instrutor incorretos.');
            redirect('professional/login');
        }
        flash('success', 'Bem-vindo ao painel do instrutor.');
        redirect('professional/panel');
    }

    public function logout(): void
    {
        Professional::logout();
        flash('success', 'Você saiu do painel do instrutor.');
        redirect('professional/login');
    }

    public function panel(): void
    {
        [$professional, $token] = $this->resolveProfessional();
        if (!$professional) {
            redirect('professional/login');
        }

        $week = $_GET['week'] ?? date('Y-m-d');
        $weekStart = $this->weekStart($week);
        $appointments = Professional::weeklyAppointments((int)$professional['id'], $weekStart);
        View::render('professional/panel', [
            'professional' => $professional,
            'appointments' => $appointments,
            'counters' => Appointment::professionalCounters((int)$professional['id']),
            'lessonPackageMap' => StudentLessonPackage::mapForStudents(array_column($appointments, 'student_id')),
            'weekStart' => $weekStart,
            'token' => $token,
            'materials' => ProfessionalMaterial::forProfessional((int)$professional['id']),
            'contactCounts' => array_map('count', QuickContact::groupedForOwner('professional', (int)$professional['id'])),
            'unreadMessages' => ProfessionalMessage::unreadCount((int)$professional['id']),
            'portalUnreadMessages' => Communication::unreadCount('professional', (int)$professional['id']),
            'portalUnreadAudioMessages' => Communication::unreadAudioCount('professional', (int)$professional['id']),
            'overdueConfirmationCount' => Appointment::overdueConfirmationCount((int)$professional['id']),
            'professionalGroupCount' => ProfessionalChatGroup::countForProfessional((int)$professional['id']),
            'videoCount' => count(VideoLesson::forActor('professional', (int)$professional['id'])),
            'groupCount' => count(TheoryGroup::forActor('professional', (int)$professional['id'])),
            'learningLevelMap' => StudentLearningLevel::groupedForStudents(array_column($appointments, 'student_id')),
            'daysOff' => ProfessionalDayOff::upcomingForProfessional((int)$professional['id'], 90),
        ]);
    }


    public function updateProfilePhoto(): void
    {
        CSRF::check();
        [$professional, $token] = $this->resolveProfessionalFromPost();
        if (!$professional) {
            flash('danger', 'Painel do instrutor invalido.');
            redirect('professional/login');
        }
        $result = Professional::updateProfilePhoto((int)$professional['id'], $_FILES['profile_photo'] ?? []);
        flash($result['ok'] ? 'success' : 'danger', $result['message']);
        $params = [];
        if ($token !== '') {
            $params['token'] = $token;
        }
        redirect('professional/panel', $params);
    }

    public function appointments(): void
    {
        [$professional, $token] = $this->resolveProfessional();
        if (!$professional) {
            redirect('professional/login');
        }
        $month = trim($_GET['month'] ?? date('Y-m'));
        if (!preg_match('/^\d{4}-\d{2}$/', $month)) {
            $month = date('Y-m');
        }
        $appointments = Appointment::byProfessionalMonth((int)$professional['id'], $month);
        View::render('professional/appointments', [
            'professional' => $professional,
            'token' => $token,
            'month' => $month,
            'appointments' => $appointments,
            'counters' => Appointment::professionalCounters((int)$professional['id'], $month),
            'lessonPackageMap' => StudentLessonPackage::mapForStudents(array_column($appointments, 'student_id')),
            'learningLevelMap' => StudentLearningLevel::groupedForStudents(array_column($appointments, 'student_id')),
        ]);
    }


    public function messages(): void
    {
        [$professional, $token] = $this->resolveProfessional();
        if (!$professional) {
            redirect('professional/login');
        }
        $tab = ($_GET['tab'] ?? 'inbox') === 'sent' ? 'sent' : 'inbox';
        View::render('professional/messages', [
            'professional' => $professional,
            'token' => $token,
            'tab' => $tab,
            'messageRecipients' => array_values(array_filter(Professional::allActive(), static fn(array $p): bool => (int)$p['id'] !== (int)$professional['id'])),
            'inboxMessages' => ProfessionalMessage::inbox((int)$professional['id']),
            'sentMessages' => ProfessionalMessage::sent((int)$professional['id']),
            'unreadMessages' => ProfessionalMessage::unreadCount((int)$professional['id']),
        ]);
    }

    public function contacts(): void
    {
        [$professional, $token] = $this->resolveProfessional();
        if (!$professional) {
            redirect('professional/login');
        }
        $folder = normalize_contact_folder($_GET['folder'] ?? 'alunos');
        View::render('professional/contacts', [
            'professional' => $professional,
            'token' => $token,
            'folder' => $folder,
            'contactsByFolder' => QuickContact::groupedForOwner('professional', (int)$professional['id']),
        ]);
    }


    public function confirmLesson(): void
    {
        CSRF::check();
        [$professional, $token] = $this->resolveProfessionalFromPost();
        if (!$professional) {
            flash('danger', 'Painel do profissional inválido.');
            redirect('professional/login');
        }
        $result = Appointment::confirmLessonByProfessional((int)$professional['id'], (int)($_POST['appointment_id'] ?? 0), (int)($_POST['confirmed_units'] ?? 0));
        flash($result['ok'] ? 'success' : 'danger', $result['message']);
        $this->redirectPanel($token, $_POST['week'] ?? date('Y-m-d'));
    }


    public function rateStudent(): void
    {
        CSRF::check();
        [$professional, $token] = $this->resolveProfessionalFromPost();
        if (!$professional) {
            flash('danger', 'Painel do profissional invalido.');
            redirect('professional/login');
        }
        $result = Appointment::rateStudentByProfessional(
            (int)$professional['id'],
            (int)($_POST['appointment_id'] ?? 0),
            (int)($_POST['rating'] ?? 0),
            trim($_POST['comment'] ?? '')
        );
        flash($result['ok'] ? 'success' : 'danger', $result['message']);
        $this->redirectPanel($token, $_POST['week'] ?? date('Y-m-d'));
    }


    public function saveStudentLevel(): void
    {
        CSRF::check();
        [$professional, $token] = $this->resolveProfessionalFromPost();
        if (!$professional) {
            flash('danger', 'Painel do profissional invalido.');
            redirect('professional/login');
        }
        $result = StudentLearningLevel::save(
            (int)$professional['id'],
            (int)($_POST['student_id'] ?? 0),
            trim($_POST['learning_category'] ?? ''),
            trim($_POST['student_level'] ?? ''),
            trim($_POST['student_level_note'] ?? '')
        );
        flash($result['ok'] ? 'success' : 'danger', $result['message']);
        $this->redirectPanel($token, $_POST['week'] ?? date('Y-m-d'));
    }

    public function markStudentAbsence(): void
    {
        CSRF::check();
        [$professional, $token] = $this->resolveProfessionalFromPost();
        if (!$professional) {
            flash('danger', 'Painel do profissional invalido.');
            redirect('professional/login');
        }
        $result = Appointment::markStudentNoShowByProfessional(
            (int)$professional['id'],
            (int)($_POST['appointment_id'] ?? 0),
            trim($_POST['reason'] ?? '')
        );
        flash($result['ok'] ? 'success' : 'danger', $result['message']);
        $this->redirectPanel($token, $_POST['week'] ?? date('Y-m-d'));
    }

    public function notifyProfessionalAbsence(): void
    {
        CSRF::check();
        [$professional, $token] = $this->resolveProfessionalFromPost();
        if (!$professional) {
            flash('danger', 'Painel do profissional invalido.');
            redirect('professional/login');
        }
        $result = Appointment::notifyProfessionalAbsence(
            (int)$professional['id'],
            (int)($_POST['appointment_id'] ?? 0),
            trim($_POST['reason'] ?? '')
        );
        flash($result['ok'] ? 'success' : 'danger', $result['message']);
        $this->redirectPanel($token, $_POST['week'] ?? date('Y-m-d'));
    }

    public function downloadMaterial(): void
    {
        [$professional, $token] = $this->resolveProfessional();
        if (!$professional) {
            redirect('professional/login');
        }
        $material = ProfessionalMaterial::findAllowed((int)($_GET['id'] ?? 0), (int)$professional['id']);
        if (!$material) {
            http_response_code(404);
            exit('Material não encontrado ou não liberado para este instrutor.');
        }
        ProfessionalMaterial::streamFile($material);
    }

    public function saveContact(): void
    {
        CSRF::check();
        [$professional, $token] = $this->resolveProfessionalFromPost();
        if (!$professional) {
            redirect('professional/login');
        }
        $result = QuickContact::save('professional', (int)$professional['id'], $_POST);
        flash($result['ok'] ? 'success' : 'danger', $result['message']);
        $this->redirectContacts($token, $_POST['folder'] ?? 'alunos');
    }

    public function deleteContact(): void
    {
        CSRF::check();
        [$professional, $token] = $this->resolveProfessionalFromPost();
        if (!$professional) {
            redirect('professional/login');
        }
        $ok = QuickContact::delete('professional', (int)$professional['id'], (int)($_POST['contact_id'] ?? 0));
        flash($ok ? 'success' : 'danger', $ok ? 'Contato apagado.' : 'Contato não encontrado.');
        $this->redirectContacts($token, $_POST['folder'] ?? 'alunos');
    }

    public function sendMessage(): void
    {
        CSRF::check();
        [$professional, $token] = $this->resolveProfessionalFromPost();
        if (!$professional) {
            redirect('professional/login');
        }
        $result = ProfessionalMessage::send((int)$professional['id'], $_POST);
        flash($result['ok'] ? 'success' : 'danger', $result['message']);
        $this->redirectMessages($token, 'sent');
    }

    public function unlockMessage(): void
    {
        CSRF::check();
        [$professional, $token] = $this->resolveProfessionalFromPost();
        if (!$professional) {
            redirect('professional/login');
        }
        $result = ProfessionalMessage::unlock(
            (int)$professional['id'],
            (int)($_POST['message_id'] ?? 0),
            (string)($_POST['message_password'] ?? '')
        );
        flash($result['ok'] ? 'success' : 'danger', $result['message']);
        $this->redirectMessages($token, 'inbox');
    }

    public function deleteMessage(): void
    {
        CSRF::check();
        [$professional, $token] = $this->resolveProfessionalFromPost();
        if (!$professional) {
            redirect('professional/login');
        }
        $result = ProfessionalMessage::deleteForProfessional((int)$professional['id'], (int)($_POST['message_id'] ?? 0));
        flash($result['ok'] ? 'success' : 'danger', $result['message']);
        $this->redirectMessages($token, ($_POST['tab'] ?? 'inbox') === 'sent' ? 'sent' : 'inbox');
    }

    public function theoryGroups(): void
    {
        [$professional,$token]=$this->resolveProfessional();
        if(!$professional) redirect('professional/login');
        if(!Professional::canManageTheoryGroups($professional)){
            flash('danger','Seu cadastro não possui permissão para gerenciar turmas teóricas.');
            redirect('professional/panel',$token!==''?['token'=>$token]:[]);
        }
        $editId=(int)($_GET['edit']??0);
        $editGroup=$editId>0?TheoryGroup::find($editId):null;
        if($editGroup && (int)$editGroup['instructor_id']!==(int)$professional['id']) $editGroup=null;
        View::render('professional/theory_groups',[
            'professional'=>$professional,'token'=>$token,
            'groups'=>TheoryGroup::forProfessionalManagement((int)$professional['id']),
            'students'=>User::activeStudents(),'editGroup'=>$editGroup,
            'editMemberIds'=>$editGroup?array_map('intval',array_column(TheoryGroup::members((int)$editGroup['id']),'id')):[],
        ]);
    }

    public function saveTheoryGroup(): void
    {
        if(($_SERVER['REQUEST_METHOD']??'')==='POST' && empty($_POST) && empty($_FILES)){
            flash('danger','A imagem ultrapassou o limite de envio da hospedagem.');
            redirect('professional/login');
        }
        CSRF::check();
        [$professional,$token]=$this->resolveProfessionalFromPost();
        if(!$professional) redirect('professional/login');
        $result=TheoryGroup::saveForProfessional((int)$professional['id'],$_POST,$_FILES['group_image']??[]);
        flash($result['ok']?'success':'danger',$result['message']);
        redirect('professional/theory-groups',$token!==''?['token'=>$token]:[]);
    }

    public function theoryVideos(): void
    {
        [$professional,$token]=$this->resolveProfessional();
        if(!$professional) redirect('professional/login');
        if(!Professional::canManageTheoryVideos($professional)){
            flash('danger','Seu cadastro não possui permissão para adicionar vídeos às turmas.');
            redirect('professional/panel',$token!==''?['token'=>$token]:[]);
        }
        View::render('professional/theory_videos',[
            'professional'=>$professional,'token'=>$token,
            'groups'=>TheoryGroup::forProfessionalManagement((int)$professional['id']),
            'videos'=>VideoLesson::forProfessionalManager((int)$professional['id']),
        ]);
    }

    public function saveTheoryVideo(): void
    {
        if(($_SERVER['REQUEST_METHOD']??'')==='POST' && empty($_POST) && empty($_FILES)){
            flash('danger','O envio ultrapassou o limite da hospedagem. Para vídeos grandes, use o envio em partes da própria página.');
            redirect('professional/login');
        }
        CSRF::check();
        [$professional,$token]=$this->resolveProfessionalFromPost();
        if(!$professional) redirect('professional/login');
        if(!Professional::canManageTheoryVideos($professional)){
            flash('danger','Permissão de videoaulas não liberada.');
            redirect('professional/panel',$token!==''?['token'=>$token]:[]);
        }
        $groupId=(int)($_POST['group_id']??0);
        $group=TheoryGroup::find($groupId);
        if(!$group || (int)$group['instructor_id']!==(int)$professional['id']){
            flash('danger','Selecione uma turma sob sua responsabilidade.');
            redirect('professional/theory-videos',$token!==''?['token'=>$token]:[]);
        }
        $data=$_POST;
        $data['audience']='student';
        $data['access_mode']='individual';
        $data['created_by_professional_id']=(int)$professional['id'];
        $result=VideoLesson::save($data,$_FILES['video_file']??[],$_FILES['cover_image']??[]);
        if(!empty($result['ok'])){
            $lessonId=(int)($result['video_lesson_id']??0);
            if($lessonId>0 && VideoLesson::grant($lessonId,'group',$groupId)){
                $result['message']='Vídeo adicionado e liberado para a turma '.$group['name'].'.';
            }
        }
        flash($result['ok']?'success':'danger',$result['message']);
        redirect('professional/theory-videos',$token!==''?['token'=>$token]:[]);
    }

    public function uploadTheoryVideoChunk(): void
    {
        header('Content-Type: application/json; charset=UTF-8');
        try{
            CSRF::check();
            [$professional]=$this->resolveProfessionalFromPost();
            if(!$professional || !Professional::canManageTheoryVideos($professional)){
                http_response_code(403);
                echo json_encode(['ok'=>false,'message'=>'Acesso não autorizado.'],JSON_UNESCAPED_UNICODE);exit;
            }
            $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 deleteTheoryVideo(): void
    {
        CSRF::check();
        [$professional,$token]=$this->resolveProfessionalFromPost();
        if(!$professional) redirect('professional/login');
        $ok=Professional::canManageTheoryVideos($professional) && VideoLesson::deleteByProfessional((int)($_POST['video_lesson_id']??0),(int)$professional['id']);
        flash($ok?'success':'danger',$ok?'Vídeo apagado.':'Vídeo não encontrado ou sem permissão.');
        redirect('professional/theory-videos',$token!==''?['token'=>$token]:[]);
    }


    public function chatGroups(): void
    {
        [$professional,$token]=$this->resolveProfessional();
        if(!$professional) redirect('professional/login');
        $groupId=(int)($_GET['id']??0);
        $group=$groupId>0?ProfessionalChatGroup::findForProfessional($groupId,(int)$professional['id']):null;
        View::render('professional/chat_groups',[
            'professional'=>$professional,'token'=>$token,
            'groups'=>ProfessionalChatGroup::forProfessional((int)$professional['id']),
            'professionals'=>array_values(array_filter(Professional::allActive(),static fn(array $p):bool=>(int)$p['id']!==(int)$professional['id'])),
            'group'=>$group,
            'members'=>$group?ProfessionalChatGroup::members((int)$group['id']):[],
            'messages'=>$group?Communication::professionalGroupMessages((int)$group['id'],(int)$professional['id']):[],
        ]);
    }

    public function saveChatGroup(): void
    {
        CSRF::check();
        [$professional,$token]=$this->resolveProfessionalFromPost();
        if(!$professional) redirect('professional/login');
        $result=ProfessionalChatGroup::create((int)$professional['id'],(string)($_POST['group_name']??''),$_POST['member_ids']??[]);
        flash($result['ok']?'success':'danger',$result['message']);
        $params=[];if($token!=='')$params['token']=$token;if(!empty($result['group_id']))$params['id']=(int)$result['group_id'];
        redirect('professional/chat-groups',$params);
    }

    public function sendChatGroupMessage(): void
    {
        CSRF::check();
        [$professional,$token]=$this->resolveProfessionalFromPost();
        if(!$professional) redirect('professional/login');
        $groupId=(int)($_POST['group_id']??0);
        $prepared=[];$audioToken=trim((string)($_POST['message_audio_token']??''));
        if($audioToken!==''){
            $prepared=PortalMedia::claimMessageAudio($audioToken,'professional',(int)$professional['id']);
            if(empty($prepared['ok'])){
                flash('danger',(string)($prepared['message']??'Áudio não encontrado.'));
                redirect('professional/chat-groups',array_filter(['token'=>$token,'id'=>$groupId]));
            }
        }
        $result=Communication::sendProfessionalGroup((int)$professional['id'],$groupId,(string)($_POST['message_body']??''),$_FILES['message_audio']??[],$prepared);
        flash($result['ok']?'success':'danger',$result['message']);
        redirect('professional/chat-groups',array_filter(['token'=>$token,'id'=>$groupId]));
    }

    private function resolveProfessional(): array
    {
        $token = trim($_GET['token'] ?? '');
        if ($token !== '') {
            return [Professional::findByToken($token), $token];
        }
        $professional = Professional::current();
        return [$professional, ''];
    }

    private function resolveProfessionalFromPost(): array
    {
        $token = trim($_POST['token'] ?? '');
        if ($token !== '') {
            return [Professional::findByToken($token), $token];
        }
        $professional = Professional::current();
        return [$professional, ''];
    }

    private function redirectPanel(string $token, string $week): never
    {
        $month = preg_match('/^\d{4}-\d{2}/', $week, $match) ? $match[0] : date('Y-m');
        $params = ['month' => $month];
        if ($token !== '') {
            $params['token'] = $token;
        }
        redirect('professional/appointments', $params);
    }


    private function redirectMessages(string $token, string $tab = 'inbox'): never
    {
        $params = ['tab' => $tab === 'sent' ? 'sent' : 'inbox'];
        if ($token !== '') {
            $params['token'] = $token;
        }
        redirect('professional/messages', $params);
    }

    private function redirectContacts(string $token, string $folder = 'alunos'): never
    {
        $params = ['folder' => normalize_contact_folder($folder)];
        if ($token !== '') {
            $params['token'] = $token;
        }
        redirect('professional/contacts', $params);
    }

    private function weekStart(string $date): string
    {
        $dt = DateTime::createFromFormat('Y-m-d', $date) ?: new DateTime();
        $dt->modify('monday this week');
        return $dt->format('Y-m-d');
    }
}
