<?php
class Ebook
{
    public static function all(): array
    {
        Database::migrate();
        $stmt = Database::pdo()->query("SELECT e.*,
            (SELECT COUNT(*) FROM ebook_student_access a WHERE a.ebook_id=e.id) AS student_releases,
            (SELECT COUNT(*) FROM ebook_group_access g WHERE g.ebook_id=e.id) AS group_releases
            FROM ebooks e ORDER BY e.created_at DESC");
        $rows = $stmt->fetchAll();
        foreach ($rows as &$row) $row['total_released'] = (int)$row['student_releases'] + (int)$row['group_releases'];
        unset($row);
        return $rows;
    }

    public static function find(int $id): ?array
    {
        Database::migrate();
        $stmt = Database::pdo()->prepare('SELECT * FROM ebooks WHERE id=? LIMIT 1');
        $stmt->execute([$id]);
        return $stmt->fetch() ?: null;
    }

    public static function forStudent(int $studentId): array
    {
        Database::migrate();
        $stmt = Database::pdo()->prepare("SELECT DISTINCT e.*,
            COALESCE((SELECT MAX(a.granted_at) FROM ebook_student_access a WHERE a.ebook_id=e.id AND a.student_id=?),
                     (SELECT MAX(g.granted_at) FROM ebook_group_access g INNER JOIN theory_group_members m ON m.group_id=g.group_id WHERE g.ebook_id=e.id AND m.student_id=?)) AS granted_at
            FROM ebooks e WHERE e.is_active=1 AND (
                EXISTS(SELECT 1 FROM ebook_student_access a WHERE a.ebook_id=e.id AND a.student_id=?) OR
                EXISTS(SELECT 1 FROM ebook_group_access g INNER JOIN theory_group_members m ON m.group_id=g.group_id WHERE g.ebook_id=e.id AND m.student_id=?))
            ORDER BY granted_at DESC,e.title ASC");
        $stmt->execute([$studentId,$studentId,$studentId,$studentId]);
        return $stmt->fetchAll();
    }

    public static function findForStudent(int $ebookId, int $studentId): ?array
    {
        foreach (self::forStudent($studentId) as $ebook) if ((int)$ebook['id']===$ebookId) return $ebook;
        return null;
    }

    public static function createFromUpload(array $post, array $file, array $coverFile = []): array
    {
        Database::migrate();
        $title = trim((string)($post['title'] ?? ''));
        $description = trim((string)($post['description'] ?? ''));
        if ($title === '') return ['ok'=>false,'message'=>'Informe o título do e-book.'];
        $error = (int)($file['error'] ?? UPLOAD_ERR_NO_FILE);
        if ($error !== UPLOAD_ERR_OK || empty($file['tmp_name'])) return ['ok'=>false,'message'=>'Envie o arquivo do e-book. Código de envio: '.$error];
        $maxBytes = 50 * 1024 * 1024;
        if ((int)($file['size'] ?? 0) > $maxBytes) return ['ok'=>false,'message'=>'O e-book deve ter no máximo 50 MB.'];
        $finfo = new finfo(FILEINFO_MIME_TYPE);
        $mime = $finfo->file($file['tmp_name']) ?: 'application/octet-stream';
        $allowed = ['application/pdf'=>'pdf','application/epub+zip'=>'epub','application/vnd.openxmlformats-officedocument.wordprocessingml.document'=>'docx','application/msword'=>'doc','image/jpeg'=>'jpg','image/png'=>'png','image/webp'=>'webp'];
        if (!isset($allowed[$mime])) return ['ok'=>false,'message'=>'Formato não permitido. Use PDF, EPUB, DOC, DOCX ou imagem.'];
        $cover = save_cover_image_upload($coverFile,'ebooks');
        if (!$cover['ok']) return ['ok'=>false,'message'=>$cover['message']];
        $dir = STORAGE_PATH.'/ebooks';
        if (!is_dir($dir) && !mkdir($dir,0775,true) && !is_dir($dir)) return ['ok'=>false,'message'=>'Não foi possível criar a pasta de e-books.'];
        $filename='ebook_'.date('Ymd_His').'_'.bin2hex(random_bytes(6)).'.'.$allowed[$mime];
        $relative='ebooks/'.$filename; $dest=$dir.'/'.$filename;
        if (!move_uploaded_file($file['tmp_name'],$dest)) { delete_storage_file($cover['path']); return ['ok'=>false,'message'=>'Não foi possível salvar o arquivo do e-book.']; }
        try {
            $stmt=Database::pdo()->prepare('INSERT INTO ebooks (title,description,file_path,original_name,mime_type,file_size,cover_path,cover_mime_type,is_active,created_at) VALUES (?,?,?,?,?,?,?,?,1,?)');
            $stmt->execute([$title,$description,$relative,basename((string)($file['name']??$filename)),$mime,(int)($file['size']??0),$cover['path'],$cover['mime'],date('Y-m-d H:i:s')]);
        } catch(Throwable $e) { delete_storage_file($relative); delete_storage_file($cover['path']); return ['ok'=>false,'message'=>'Não foi possível cadastrar o e-book.']; }
        return ['ok'=>true,'message'=>'E-book cadastrado com sucesso.'];
    }

    public static function updateCover(int $id,array $coverFile): array
    {
        $record=self::find($id); if(!$record)return ['ok'=>false,'message'=>'Registro não encontrado.'];
        $cover=save_cover_image_upload($coverFile,'ebooks'); if(!$cover['ok'])return ['ok'=>false,'message'=>$cover['message']];
        if(empty($cover['path']))return ['ok'=>false,'message'=>'Selecione uma imagem JPG, PNG ou WEBP.'];
        try { Database::pdo()->prepare('UPDATE ebooks SET cover_path=?,cover_mime_type=? WHERE id=?')->execute([$cover['path'],$cover['mime'],$id]); }
        catch(Throwable $e){delete_storage_file($cover['path']);return ['ok'=>false,'message'=>'Não foi possível atualizar a imagem.'];}
        delete_storage_file($record['cover_path']??null); return ['ok'=>true,'message'=>'Imagem atualizada com sucesso.'];
    }

    public static function toggle(int $id): bool { Database::migrate();$s=Database::pdo()->prepare('UPDATE ebooks SET is_active=CASE WHEN is_active=1 THEN 0 ELSE 1 END WHERE id=?');$s->execute([$id]);return $s->rowCount()>0; }
    public static function delete(int $id): array { $e=self::find($id);if(!$e)return ['ok'=>false,'message'=>'E-book não encontrado.'];Database::pdo()->prepare('DELETE FROM ebooks WHERE id=?')->execute([$id]);delete_storage_file($e['file_path']??null);delete_storage_file($e['cover_path']??null);return ['ok'=>true,'message'=>'E-book removido com sucesso.']; }

    public static function grant(int $ebookId,int $studentId): array
    {
        Database::migrate(); if(!self::find($ebookId)||!User::find($studentId))return ['ok'=>false,'message'=>'E-book ou aluno não encontrado.'];
        try { $s=Database::pdo()->prepare('INSERT INTO ebook_student_access (ebook_id,student_id,granted_at) VALUES (?,?,?)');$s->execute([$ebookId,$studentId,date('Y-m-d H:i:s')]);return ['ok'=>true,'message'=>'E-book liberado para o aluno.']; }
        catch(PDOException $e){if($e->getCode()==='23000'||str_contains(strtolower($e->getMessage()),'unique'))return ['ok'=>false,'message'=>'Este e-book já está liberado para esse aluno.'];throw $e;}
    }

    public static function grantToGroup(int $ebookId,int $groupId): array
    {
        Database::migrate(); if(!self::find($ebookId)||!TheoryGroup::find($groupId))return ['ok'=>false,'message'=>'E-book ou grupo não encontrado.'];
        try { $sql=Database::driver()==='mysql'?'INSERT IGNORE INTO ebook_group_access (ebook_id,group_id,granted_at) VALUES (?,?,?)':'INSERT OR IGNORE INTO ebook_group_access (ebook_id,group_id,granted_at) VALUES (?,?,?)';Database::pdo()->prepare($sql)->execute([$ebookId,$groupId,date('Y-m-d H:i:s')]);return ['ok'=>true,'message'=>'E-book liberado para o grupo teórico.']; }
        catch(Throwable $e){return ['ok'=>false,'message'=>'Não foi possível liberar o e-book para o grupo.'];}
    }

    public static function revoke(int $ebookId,int $studentId): bool { $s=Database::pdo()->prepare('DELETE FROM ebook_student_access WHERE ebook_id=? AND student_id=?');$s->execute([$ebookId,$studentId]);return $s->rowCount()>0; }
    public static function revokeFromGroup(int $ebookId,int $groupId): bool { $s=Database::pdo()->prepare('DELETE FROM ebook_group_access WHERE ebook_id=? AND group_id=?');$s->execute([$ebookId,$groupId]);return $s->rowCount()>0; }

    public static function accessMap(): array
    {
        Database::migrate(); $rows=[];
        $direct=Database::pdo()->query("SELECT a.ebook_id,a.student_id AS recipient_id,'student' AS recipient_type,a.granted_at,u.name AS recipient_name,u.email AS recipient_detail,e.title AS ebook_title FROM ebook_student_access a INNER JOIN users u ON u.id=a.student_id INNER JOIN ebooks e ON e.id=a.ebook_id")->fetchAll();
        $groups=Database::pdo()->query("SELECT a.ebook_id,a.group_id AS recipient_id,'group' AS recipient_type,a.granted_at,g.name AS recipient_name,g.group_code AS recipient_detail,e.title AS ebook_title FROM ebook_group_access a INNER JOIN theory_groups g ON g.id=a.group_id INNER JOIN ebooks e ON e.id=a.ebook_id")->fetchAll();
        $rows=array_merge($direct,$groups); usort($rows,static fn($a,$b)=>strcmp($b['granted_at'],$a['granted_at'])); return $rows;
    }

    public static function streamFile(array $ebook): never
    {
        $path=STORAGE_PATH.'/'.ltrim((string)($ebook['file_path']??''),'/'); if(!is_file($path)){http_response_code(404);exit('Arquivo não encontrado.');}
        $mime=$ebook['mime_type']?:'application/octet-stream';$name=$ebook['original_name']?:'ebook.pdf';header('Content-Type: '.$mime);header('Content-Length: '.filesize($path));header('Content-Disposition: inline; filename="'.str_replace('"','',$name).'"');header('X-Content-Type-Options: nosniff');readfile($path);exit;
    }
    public static function streamCover(array $ebook): never { stream_storage_image($ebook['cover_path']??null,$ebook['cover_mime_type']??null); }
}
