<?php
class TheoryGroup
{
    public static function all(): array
    {
        Database::migrate();
        $rows = Database::pdo()->query("SELECT g.*, p.name AS instructor_name, p.profile_photo_path AS instructor_photo_path FROM theory_groups g LEFT JOIN professionals p ON p.id=g.instructor_id ORDER BY g.is_active DESC,g.id DESC")->fetchAll();
        foreach ($rows as &$row) $row['member_count'] = count(self::members((int)$row['id']));
        unset($row);
        return $rows;
    }

    public static function find(int $id): ?array
    {
        Database::migrate();
        $stmt = Database::pdo()->prepare("SELECT g.*,p.name AS instructor_name,p.profile_photo_path AS instructor_photo_path FROM theory_groups g LEFT JOIN professionals p ON p.id=g.instructor_id WHERE g.id=? LIMIT 1");
        $stmt->execute([$id]);
        return $stmt->fetch() ?: null;
    }

    public static function findByCode(string $code): ?array
    {
        Database::migrate();
        $code = only_digits($code);
        if (strlen($code) !== 9) return null;
        $stmt = Database::pdo()->prepare("SELECT g.*,p.name AS instructor_name,p.profile_photo_path AS instructor_photo_path FROM theory_groups g LEFT JOIN professionals p ON p.id=g.instructor_id WHERE g.group_code=? LIMIT 1");
        $stmt->execute([$code]);
        return $stmt->fetch() ?: null;
    }

    public static function save(array $data, array $imageFile = []): array
    {
        Database::migrate();
        $id = (int)($data['group_id'] ?? 0);
        $name = trim($data['name'] ?? '');
        $description = trim($data['description'] ?? '');
        $instructorId = (int)($data['instructor_id'] ?? 0);
        $studentIds = array_values(array_unique(array_filter(array_map('intval',$data['student_ids'] ?? []))));
        if ($name === '') return ['ok'=>false,'message'=>'Informe o nome da turma teórica.'];
        if ($instructorId <= 0) return ['ok'=>false,'message'=>'Selecione o instrutor responsável.'];
        $instructor = Professional::find($instructorId);
        if (!$instructor || empty($instructor['is_active'])) return ['ok'=>false,'message'=>'O instrutor selecionado não está ativo.'];
        if ($studentIds) {
            $validStudentIds = [];
            $studentCheck = Database::pdo()->prepare("SELECT id FROM users WHERE id=? AND role='student' AND deleted_at IS NULL LIMIT 1");
            foreach ($studentIds as $studentId) {
                $studentCheck->execute([$studentId]);
                if ($studentCheck->fetchColumn()) $validStudentIds[] = $studentId;
            }
            $studentIds = $validStudentIds;
        }
        $existing = $id > 0 ? self::find($id) : null;
        if ($id > 0 && !$existing) return ['ok'=>false,'message'=>'Turma não encontrada.'];
        $imagePath = $existing['image_path'] ?? null;
        if (!empty($imageFile['tmp_name'])) {
            $saved = PortalMedia::saveImage($imageFile,'theory_groups');
            if (!$saved['ok']) return $saved;
            PortalMedia::delete($imagePath);
            $imagePath = $saved['path'];
        }
        $pdo = Database::pdo();
        try {
            $pdo->beginTransaction();
            if ($id > 0) {
                $stmt = $pdo->prepare('UPDATE theory_groups SET name=?,description=?,instructor_id=?,image_path=? WHERE id=?');
                $stmt->execute([$name,$description,$instructorId,$imagePath,$id]);
            } else {
                $code = self::uniqueCode();
                $stmt = $pdo->prepare('INSERT INTO theory_groups (name,description,instructor_id,image_path,group_code,is_active,created_at) VALUES (?,?,?,?,?,1,?)');
                $stmt->execute([$name,$description,$instructorId,$imagePath,$code,date('Y-m-d H:i:s')]);
                $id = (int)$pdo->lastInsertId();
            }
            $pdo->prepare('DELETE FROM theory_group_members WHERE group_id=?')->execute([$id]);
            if (Database::driver()==='mysql') $insert = $pdo->prepare('INSERT IGNORE INTO theory_group_members (group_id,student_id,joined_at) VALUES (?,?,?)');
            else $insert = $pdo->prepare('INSERT OR IGNORE INTO theory_group_members (group_id,student_id,joined_at) VALUES (?,?,?)');
            foreach ($studentIds as $studentId) $insert->execute([$id,$studentId,date('Y-m-d H:i:s')]);
            $pdo->commit();
            return ['ok'=>true,'message'=>'Turma teórica salva com ' . count($studentIds) . ' aluno(s).'];
        } catch (Throwable $e) {
            if ($pdo->inTransaction()) $pdo->rollBack();
            return ['ok'=>false,'message'=>'Não foi possível salvar a turma: '.$e->getMessage()];
        }
    }

    public static function forProfessionalManagement(int $professionalId): array
    {
        Database::migrate();
        $stmt=Database::pdo()->prepare("SELECT g.*,p.name AS instructor_name,p.profile_photo_path AS instructor_photo_path FROM theory_groups g LEFT JOIN professionals p ON p.id=g.instructor_id WHERE g.instructor_id=? ORDER BY g.is_active DESC,g.id DESC");
        $stmt->execute([$professionalId]);
        $rows=$stmt->fetchAll();
        foreach($rows as &$row) $row['member_count']=count(self::members((int)$row['id']));
        unset($row);
        return $rows;
    }

    public static function saveForProfessional(int $professionalId, array $data, array $imageFile=[]): array
    {
        $professional=Professional::find($professionalId);
        if(!$professional || !Professional::canManageTheoryGroups($professional)) {
            return ['ok'=>false,'message'=>'Seu cadastro não possui permissão para criar ou editar turmas.'];
        }
        $groupId=(int)($data['group_id']??0);
        if($groupId>0){
            $existing=self::find($groupId);
            if(!$existing || (int)$existing['instructor_id']!==$professionalId){
                return ['ok'=>false,'message'=>'Você só pode editar turmas sob sua responsabilidade.'];
            }
        }
        $data['instructor_id']=$professionalId;
        return self::save($data,$imageFile);
    }

    public static function toggle(int $id): bool
    {
        Database::migrate();
        $stmt=Database::pdo()->prepare('UPDATE theory_groups SET is_active=CASE WHEN is_active=1 THEN 0 ELSE 1 END WHERE id=?');
        $stmt->execute([$id]);
        return $stmt->rowCount()>0;
    }

    public static function delete(int $id): bool
    {
        Database::migrate();
        $row = self::find($id);
        if (!$row) return false;
        $pdo = Database::pdo();
        try {
            $pdo->beginTransaction();
            $messageIds = $pdo->prepare("SELECT id,attachment_path FROM internal_messages WHERE conversation_type='group' AND group_id=?");
            $messageIds->execute([$id]);
            $messageRows = $messageIds->fetchAll();
            $ids = array_map('intval', array_column($messageRows, 'id'));
            if ($ids) {
                $placeholders = implode(',', array_fill(0, count($ids), '?'));
                $pdo->prepare("DELETE FROM internal_message_deletions WHERE message_id IN ($placeholders)")->execute($ids);
                $pdo->prepare("DELETE FROM internal_message_reads WHERE message_id IN ($placeholders)")->execute($ids);
                $pdo->prepare("DELETE FROM internal_messages WHERE id IN ($placeholders)")->execute($ids);
            }
            $stmt = $pdo->prepare('DELETE FROM theory_groups WHERE id=?');
            $stmt->execute([$id]);
            if ($stmt->rowCount() <= 0) {
                $pdo->rollBack();
                return false;
            }
            $pdo->commit();
            PortalMedia::delete($row['image_path'] ?? '');
            foreach ($messageRows ?? [] as $messageRow) {
                if (!empty($messageRow['attachment_path'])) {
                    PortalMedia::delete((string)$messageRow['attachment_path']);
                }
            }
            return true;
        } catch (Throwable $e) {
            if ($pdo->inTransaction()) $pdo->rollBack();
            return false;
        }
    }

    public static function members(int $groupId): array
    {
        Database::migrate();
        $stmt=Database::pdo()->prepare("SELECT u.id,u.name,u.email,u.whatsapp,u.internal_code,u.profile_photo_path FROM theory_group_members gm INNER JOIN users u ON u.id=gm.student_id WHERE gm.group_id=? AND u.deleted_at IS NULL ORDER BY u.name");
        $stmt->execute([$groupId]);
        return $stmt->fetchAll();
    }

    public static function forActor(string $actorType,int $actorId): array
    {
        Database::migrate();
        $actorType=normalize_internal_actor_type($actorType);
        if($actorType==='admin') return self::all();
        if($actorType==='professional'){
            $stmt=Database::pdo()->prepare("SELECT g.*,p.name AS instructor_name,p.profile_photo_path AS instructor_photo_path FROM theory_groups g LEFT JOIN professionals p ON p.id=g.instructor_id WHERE g.is_active=1 AND g.instructor_id=? ORDER BY g.id DESC");
            $stmt->execute([$actorId]);return $stmt->fetchAll();
        }
        if($actorType==='student'){
            $stmt=Database::pdo()->prepare("SELECT g.*,p.name AS instructor_name,p.profile_photo_path AS instructor_photo_path FROM theory_groups g INNER JOIN theory_group_members gm ON gm.group_id=g.id LEFT JOIN professionals p ON p.id=g.instructor_id WHERE g.is_active=1 AND gm.student_id=? ORDER BY g.id DESC");
            $stmt->execute([$actorId]);return $stmt->fetchAll();
        }
        return [];
    }

    public static function canAccess(int $groupId,string $actorType,int $actorId): bool
    {
        $actorType=normalize_internal_actor_type($actorType);
        if($actorType==='admin') return self::find($groupId)!==null;
        if($actorType==='professional'){
            $stmt=Database::pdo()->prepare('SELECT COUNT(*) FROM theory_groups WHERE id=? AND instructor_id=? AND is_active=1');
            $stmt->execute([$groupId,$actorId]);return (int)$stmt->fetchColumn()>0;
        }
        if($actorType==='student'){
            $stmt=Database::pdo()->prepare('SELECT COUNT(*) FROM theory_group_members gm INNER JOIN theory_groups g ON g.id=gm.group_id WHERE gm.group_id=? AND gm.student_id=? AND g.is_active=1');
            $stmt->execute([$groupId,$actorId]);return (int)$stmt->fetchColumn()>0;
        }
        return false;
    }

    private static function uniqueCode(): string
    {
        $pdo = Database::pdo();
        do {
            $code = (string)random_int(100000000, 999999999);
            $exists = false;
            foreach ([['theory_groups','group_code'], ['users','internal_code'], ['professionals','internal_code'], ['beginner_instructors','internal_code']] as [$table,$column]) {
                if (!Database::tableExists($table) || !Database::columnExists($table, $column)) continue;
                $safeTable = preg_replace('/[^a-zA-Z0-9_]/', '', $table);
                $safeColumn = preg_replace('/[^a-zA-Z0-9_]/', '', $column);
                $stmt = $pdo->prepare("SELECT COUNT(*) FROM {$safeTable} WHERE {$safeColumn}=?");
                $stmt->execute([$code]);
                if ((int)$stmt->fetchColumn() > 0) { $exists = true; break; }
            }
        } while ($exists);
        return $code;
    }
}
