from __future__ import annotations

import mimetypes
import os
import secrets
from pathlib import Path

from werkzeug.datastructures import FileStorage
from werkzeug.utils import secure_filename

from app.config import UPLOAD_DIR
from app.db import execute, query_one, utcnow

ALLOWED = {
    '.jpg': ('image/jpeg', 'image'),
    '.jpeg': ('image/jpeg', 'image'),
    '.png': ('image/png', 'image'),
    '.webp': ('image/webp', 'image'),
    '.mp4': ('video/mp4', 'video'),
}
MAX_SIZE = 25 * 1024 * 1024


class MediaService:
    def save(self, file: FileStorage) -> int:
        if not file or not file.filename:
            raise ValueError('No file selected')
        original = secure_filename(file.filename)
        ext = Path(original).suffix.lower()
        if ext not in ALLOWED:
            raise ValueError('Unsupported file extension')
        expected_mime, file_type = ALLOWED[ext]
        mime = (file.mimetype or mimetypes.guess_type(original)[0] or '').lower()
        if mime != expected_mime:
            raise ValueError('MIME type does not match extension')
        file.stream.seek(0, os.SEEK_END)
        size = file.stream.tell()
        file.stream.seek(0)
        if size <= 0 or size > MAX_SIZE:
            raise ValueError('File is empty or exceeds 25 MB')
        stored = secrets.token_hex(16) + ext
        UPLOAD_DIR.mkdir(parents=True, exist_ok=True)
        target = (UPLOAD_DIR / stored).resolve()
        if UPLOAD_DIR.resolve() not in target.parents:
            raise ValueError('Invalid upload path')
        file.save(target)
        try:
            os.chmod(target, 0o600)
        except OSError:
            pass
        return execute(
            'INSERT INTO media_files(original_name, stored_name, mime_type, file_type, size_bytes, created_at) VALUES (?, ?, ?, ?, ?, ?)',
            (original, stored, mime, file_type, size, utcnow()),
        )

    def path_for(self, media_file_id: int) -> Path:
        row = query_one('SELECT * FROM media_files WHERE id=?', (media_file_id,))
        if not row:
            raise FileNotFoundError('Media record not found')
        path = (UPLOAD_DIR / row['stored_name']).resolve()
        if UPLOAD_DIR.resolve() not in path.parents or not path.exists():
            raise FileNotFoundError('Media file not found')
        return path
