"""Persist Hudl downloads under media/{id}/ and track them in the DB."""

from __future__ import annotations

import hashlib
import shutil
import uuid
from pathlib import Path

from sqlalchemy.orm import Session

from app.models.media_model import MediaVideo

# backend/sergio-backend/
BACKEND_ROOT = Path(__file__).resolve().parents[2]
MEDIA_ROOT = BACKEND_ROOT / "media"


def source_key_from_watch_url(watch_url: str) -> str:
    return hashlib.sha256((watch_url or "").strip().encode("utf-8")).hexdigest()[:32]


def source_key_from_hudl_v(v: str) -> str:
    """Stable media key for a Hudl `v` id (trailing = ignored)."""
    canon = (v or "").strip().rstrip("=")
    return hashlib.sha256(f"hudl_v:{canon}".encode("utf-8")).hexdigest()[:32]


def find_media_by_hudl_v(db: Session, v: str) -> MediaVideo | None:
    """
    Find a saved media row for this Hudl v.
    Matches new hudl_v source keys and older watch_url-based rows.
    """
    from urllib.parse import unquote

    canon = (v or "").strip().rstrip("=")
    if not canon:
        return None

    key = source_key_from_hudl_v(canon)
    row = db.query(MediaVideo).filter(MediaVideo.source_key == key).first()
    if row and media_file_exists(row):
        return row

    # Legacy rows keyed by full watch_url hash — match on watch_url containing v
    candidates = (
        db.query(MediaVideo)
        .filter(MediaVideo.watch_url.isnot(None))
        .order_by(MediaVideo.created_at.desc())
        .all()
    )
    needles = (
        canon,
        f"{canon}=",
        f"v={canon}",
        f"v={canon}=",
        f"v={canon}%3D",
        f"v={canon}%3d",
    )
    for row in candidates:
        if not media_file_exists(row):
            continue
        url = unquote((row.watch_url or "").strip())
        if any(n in url or n in (row.watch_url or "") for n in needles):
            # Upgrade source_key so future lookups are instant
            try:
                if row.source_key != key:
                    clash = db.query(MediaVideo).filter(MediaVideo.source_key == key).first()
                    if clash is None:
                        row.source_key = key
                        db.commit()
                        db.refresh(row)
            except Exception:
                db.rollback()
            return row
    return None


def absolute_media_path(relative_path: str) -> Path:
    return BACKEND_ROOT / relative_path


def media_file_exists(row: MediaVideo) -> bool:
    try:
        return absolute_media_path(row.file_path).is_file()
    except Exception:
        return False


def store_downloaded_video(
    db: Session,
    *,
    temp_path: str,
    title: str,
    watch_url: str,
    original_filename: str,
    video_index: int | None = None,
    source_key: str | None = None,
    media_id: str | None = None,
) -> MediaVideo:
    MEDIA_ROOT.mkdir(parents=True, exist_ok=True)

    key = (source_key or "").strip() or source_key_from_watch_url(watch_url)
    existing = db.query(MediaVideo).filter(MediaVideo.source_key == key).first()

    src = Path(temp_path)
    # If Playwright already saved into media/<id>/video.ext, reuse that folder
    reused_media_id = (media_id or "").strip() or None
    if not reused_media_id:
        try:
            parts = src.resolve().relative_to(MEDIA_ROOT.resolve()).parts
            if len(parts) >= 2:
                reused_media_id = parts[0]
        except Exception:
            reused_media_id = None

    media_id = existing.id if existing else (reused_media_id or str(uuid.uuid4()))
    dest_dir = MEDIA_ROOT / media_id
    dest_dir.mkdir(parents=True, exist_ok=True)

    ext = Path(original_filename or "").suffix or src.suffix or ".mp4"
    if len(ext) > 10:
        ext = ".mp4"
    dest = dest_dir / f"video{ext}"

    if src.resolve() != dest.resolve():
        if dest.exists():
            dest.unlink(missing_ok=True)
        if src.exists():
            shutil.move(str(src), str(dest))
    # else: already at final media path

    rel = f"media/{media_id}/video{ext}"
    size = dest.stat().st_size if dest.exists() else None
    safe_title = (title or original_filename or "Video").strip()[:512]

    if existing:
        # Remove previous file if path changed
        old_abs = absolute_media_path(existing.file_path)
        if old_abs.exists() and old_abs.resolve() != dest.resolve():
            try:
                old_abs.unlink(missing_ok=True)
            except Exception:
                pass
        existing.title = safe_title
        existing.watch_url = (watch_url or "").strip()[:1024] or None
        existing.file_path = rel
        existing.original_filename = (original_filename or "")[:512] or None
        existing.file_size = size
        existing.video_index = video_index
        if existing.source_key != key:
            # Keep unique constraint safe
            clash = db.query(MediaVideo).filter(
                MediaVideo.source_key == key, MediaVideo.id != existing.id
            ).first()
            if clash is None:
                existing.source_key = key
        db.commit()
        db.refresh(existing)
        return existing

    row = MediaVideo(
        id=media_id,
        source_key=key,
        title=safe_title,
        watch_url=(watch_url or "").strip()[:1024] or None,
        file_path=rel,
        original_filename=(original_filename or "")[:512] or None,
        file_size=size,
        video_index=video_index,
    )
    db.add(row)
    db.commit()
    db.refresh(row)
    return row


def serialize_media(row: MediaVideo) -> dict:
    return {
        "id": row.id,
        "source_key": row.source_key,
        "title": row.title,
        "watch_url": row.watch_url,
        "file_path": row.file_path,
        "original_filename": row.original_filename,
        "file_size": row.file_size,
        "video_index": row.video_index,
        "created_at": row.created_at.isoformat() if row.created_at else None,
        "access_url": f"/api/v1/hudl/media/{row.id}",
        "file_exists": media_file_exists(row),
    }
