from __future__ import annotations

import re


def duration_phrase(seconds: int) -> str:
    seconds = max(0, int(seconds))
    hours, rem = divmod(seconds, 3600)
    minutes, secs = divmod(rem, 60)
    if hours and minutes:
        return f"{hours} h {minutes} min"
    if hours:
        return f"{hours} h"
    if minutes and secs:
        return f"{minutes} min {secs} s"
    if minutes:
        return f"{minutes} min"
    return f"{secs} s"


def format_upload_date(value: str | None) -> str | None:
    if not value or len(value) != 8 or not value.isdigit():
        return None
    return f"{value[0:4]}-{value[4:6]}-{value[6:8]}"


def safe_download_name(title: str, ext: str) -> str:
    cleaned = re.sub(r'[<>:"/\\|?*\x00-\x1f]', "", title or "")
    cleaned = re.sub(r"\s+", " ", cleaned).strip().rstrip(". ")
    cleaned = cleaned[:80].rstrip(". ")
    if not cleaned:
        cleaned = "vaani"
    suffix = ext if ext.startswith(".") else f".{ext}"
    return f"{cleaned}{suffix}"


def content_disposition(filename: str, inline: bool = False) -> str:
    from urllib.parse import quote

    kind = "inline" if inline else "attachment"
    ascii_name = filename.encode("ascii", "ignore").decode().replace('"', "").strip()
    if not ascii_name or ascii_name in {".mp3", ".txt", ".jpg", ".png", ".webp"}:
        ascii_name = "vaani" + (filename[filename.rfind(".") :] if "." in filename else "")
    return f"{kind}; filename=\"{ascii_name}\"; filename*=UTF-8''{quote(filename)}"


def normalize_for_cer(text: str) -> str:
    return "".join(ch for ch in text if not ch.isspace())


def levenshtein(left: str, right: str) -> int:
    if left == right:
        return 0
    if not left:
        return len(right)
    if not right:
        return len(left)
    previous = list(range(len(right) + 1))
    for i, ca in enumerate(left, 1):
        current = [i]
        for j, cb in enumerate(right, 1):
            insert = current[j - 1] + 1
            delete = previous[j] + 1
            replace = previous[j - 1] + (ca != cb)
            current.append(min(insert, delete, replace))
        previous = current
    return previous[-1]


def cer(reference: str, hypothesis: str) -> float:
    ref = normalize_for_cer(reference)
    hyp = normalize_for_cer(hypothesis)
    if not ref:
        return 0.0 if not hyp else 1.0
    return levenshtein(ref, hyp) / len(ref)
