from __future__ import annotations
import os
import tempfile
from datetime import datetime
from pathlib import Path, PurePosixPath

from govcrawler.settings import get_settings
from govcrawler.storage.filenames import safe_filename
from govcrawler.storage.paths import build_reldir, to_os_path


def _atomic_write_bytes(path: Path, data: bytes) -> None:
    path.parent.mkdir(parents=True, exist_ok=True)
    fd, tmp = tempfile.mkstemp(prefix=".tmp_", dir=str(path.parent))
    try:
        with os.fdopen(fd, "wb") as f:
            f.write(data)
        os.replace(tmp, path)
    except Exception:
        try:
            os.unlink(tmp)
        except FileNotFoundError:
            pass
        raise


def _unique_relpath(reldir: PurePosixPath, abs_dir: Path, filename: str, fallback_key: str) -> PurePosixPath:
    safe = safe_filename(filename)
    if not (abs_dir / safe).exists():
        return reldir / safe
    stem, dot, ext = safe.rpartition(".")
    suffix = safe_filename(fallback_key, max_len=32)
    if dot:
        safe = f"{stem}_{suffix}.{ext}"
    else:
        safe = f"{safe}_{suffix}"
    if not (abs_dir / safe).exists():
        return reldir / safe
    base = safe
    stem, dot, ext = base.rpartition(".")
    for i in range(2, 1000):
        safe = f"{stem}_{i}.{ext}" if dot else f"{base}_{i}"
        if not (abs_dir / safe).exists():
            return reldir / safe
    return reldir / safe


def write_raw_html(
    site: str, column: str, when: datetime, article_key: str, html: str
) -> PurePosixPath:
    """Write raw html; return POSIX relative path (stored in DB)."""
    reldir = build_reldir(site, column, when, "raw_html")
    relpath = reldir / f"{article_key}.html"
    abs_path = to_os_path(get_settings().data_dir, relpath)
    _atomic_write_bytes(abs_path, html.encode("utf-8"))
    return relpath


def write_article_text(
    site: str,
    column: str,
    when: datetime,
    article_key: str,
    text: str,
    title: str | None = None,
) -> PurePosixPath:
    reldir = build_reldir(site, column, when, "articles_text")
    abs_dir = to_os_path(get_settings().data_dir, reldir)
    filename = f"{title or article_key}.txt"
    relpath = _unique_relpath(reldir, abs_dir, filename, article_key)
    abs_path = to_os_path(get_settings().data_dir, relpath)
    _atomic_write_bytes(abs_path, text.encode("utf-8"))
    return relpath
