"""Deterministic filename generation for ISTAT XML exports."""

from __future__ import annotations

import re
from datetime import date

from istat.xml_export.exceptions import XmlPayloadValidationError


_SAFE_PART_RE = re.compile(r"[^a-z0-9_]+")


def _validate_date(value: date | None, field_name: str) -> date:
    if value is None:
        raise XmlPayloadValidationError(f"{field_name} is required")
    if not isinstance(value, date):
        raise XmlPayloadValidationError(f"{field_name} must be a date instance")
    return value


def _safe_filename_part(value: object) -> str:
    normalized = str(value).strip().lower().replace("-", "_")
    normalized = _SAFE_PART_RE.sub("_", normalized)
    normalized = re.sub(r"_+", "_", normalized).strip("_")
    return normalized


def _build_xml_filename(
    export_type: str,
    structure_id: int,
    export_date: date,
) -> str:
    safe_export_type = _safe_filename_part(export_type)
    safe_structure_id = _safe_filename_part(structure_id)
    if not safe_export_type:
        raise XmlPayloadValidationError("export_type is required")
    if not safe_structure_id:
        raise XmlPayloadValidationError("structure_id is required")

    valid_date = _validate_date(export_date, "export_date")
    return (
        f"istat_{safe_export_type}_{safe_structure_id}_"
        f"{valid_date:%Y_%m_%d}.xml"
    )


def build_guest_xml_filename(
    *,
    structure_id: int,
    start_date: date,
    end_date: date,
) -> str:
    """Build a deterministic guest movement XML filename."""

    valid_start = _validate_date(start_date, "start_date")
    valid_end = _validate_date(end_date, "end_date")
    if valid_end < valid_start:
        raise XmlPayloadValidationError(
            "end_date must be greater than or equal to start_date"
        )

    if valid_start == valid_end:
        return _build_xml_filename("movimenti", structure_id, valid_start)

    safe_structure_id = _safe_filename_part(structure_id)
    if not safe_structure_id:
        raise XmlPayloadValidationError("structure_id is required")

    return (
        f"istat_movimenti_{safe_structure_id}_{valid_start:%Y_%m_%d}"
        f"_to_{valid_end:%Y_%m_%d}.xml"
    )


def build_c59_xml_filename(*, structure_id: int, export_date: date) -> str:
    """Build a deterministic C59 XML filename."""

    return _build_xml_filename("c59", structure_id, export_date)


def build_c59_daily_xml_filename(*, report_date: date) -> str:
    """Build the per-day C59 XML filename used inside a ZIP archive.

    Format: ``C59_YYYYMMDD.xml`` — matches the Ross1000 / Liguria convention.
    """
    valid_date = _validate_date(report_date, "report_date")
    return f"C59_{valid_date:%Y%m%d}.xml"


def build_c59_zip_filename(*, start_date: date, end_date: date) -> str:
    """Build the ZIP archive filename for a multi-day C59 export.

    Format: ``C59_YYYYMMDD_YYYYMMDD.zip``
    """
    valid_start = _validate_date(start_date, "start_date")
    valid_end = _validate_date(end_date, "end_date")
    if valid_end < valid_start:
        raise XmlPayloadValidationError(
            "end_date must be greater than or equal to start_date"
        )
    return f"C59_{valid_start:%Y%m%d}_{valid_end:%Y%m%d}.zip"
