"""
EXIF write-back helpers.

The rest of the app reads EXIF at scan time and stashes the result in Postgres
(see `services/metadata.py`). This module handles the reverse direction: when
the user corrects a date in the UI we also rewrite the relevant EXIF tags on
disk so a later rescan won't clobber the fix and external tools see the same
truth the DB does.
"""
import asyncio
import logging
import subprocess
from datetime import datetime
from pathlib import Path

logger = logging.getLogger(__name__)

EXIFTOOL_TIMEOUT_SECONDS = 30


class ExifWriteError(RuntimeError):
    """Raised when exiftool fails to write tags to a file."""


def _format_exif_dt(dt: datetime) -> str:
    return dt.strftime("%Y:%m:%d %H:%M:%S")


async def write_taken_at(filepath: str, dt: datetime) -> None:
    """Rewrite DateTimeOriginal / CreateDate / ModifyDate on the file.

    - ``-overwrite_original`` so we don't litter the library with
      ``<name>_original`` sidecars.
    - ``-P`` preserves the file's mtime so the scanner's mtime-based
      change detection stays quiet.
    - We set all three common date tags together because different viewers
      read different ones; keeping them in lockstep avoids confusing
      downstream tools and our own re-extraction pass.
    """
    if not Path(filepath).exists():
        raise ExifWriteError(f"File not found: {filepath}")

    stamp = _format_exif_dt(dt)
    cmd = [
        "exiftool",
        "-overwrite_original",
        "-P",
        f"-DateTimeOriginal={stamp}",
        f"-CreateDate={stamp}",
        f"-ModifyDate={stamp}",
        filepath,
    ]

    def _run() -> subprocess.CompletedProcess:
        return subprocess.run(
            cmd,
            capture_output=True,
            text=True,
            timeout=EXIFTOOL_TIMEOUT_SECONDS,
        )

    try:
        result = await asyncio.to_thread(_run)
    except subprocess.TimeoutExpired as exc:
        raise ExifWriteError(f"exiftool timed out writing {filepath}") from exc
    except FileNotFoundError as exc:
        raise ExifWriteError("exiftool binary not available") from exc

    if result.returncode != 0:
        msg = (result.stderr or result.stdout or "unknown error").strip()
        logger.warning("exiftool write failed for %s: %s", filepath, msg)
        raise ExifWriteError(msg)
