from __future__ import annotations

import json
import re
import unicodedata
from datetime import datetime, timezone
from pathlib import Path
from typing import Any, Iterable, Mapping

_SLUG_PATTERN = re.compile(r"[^a-z0-9._-]+")
_WHITESPACE_PATTERN = re.compile(r"\s+")


def utc_now() -> str:
    return datetime.now(timezone.utc).replace(microsecond=0).isoformat().replace("+00:00", "Z")


def normalize_tag(tag: str) -> str:
    candidate = _WHITESPACE_PATTERN.sub(" ", tag.strip())
    if not candidate:
        raise ValueError("tag must not be empty.")
    return candidate


def slugify(value: str) -> str:
    candidate = unicodedata.normalize("NFKD", value).encode("ascii", "ignore").decode("ascii")
    candidate = candidate.strip().lower()
    candidate = _SLUG_PATTERN.sub("-", candidate)
    candidate = candidate.strip("-")
    if not candidate:
        raise ValueError("value does not contain any slug-safe characters.")
    return candidate


def write_json(path: str | Path, payload: Mapping[str, Any]) -> Path:
    target = Path(path)
    target.parent.mkdir(parents=True, exist_ok=True)
    target.write_text(json.dumps(dict(payload), indent=2, sort_keys=True), encoding="utf-8")
    return target


def append_jsonl(path: str | Path, records: Iterable[Mapping[str, Any]]) -> Path:
    target = Path(path)
    target.parent.mkdir(parents=True, exist_ok=True)
    with target.open("a", encoding="utf-8") as handle:
        for record in records:
            handle.write(json.dumps(dict(record), sort_keys=True))
            handle.write("\n")
    return target
