"""Checkpoint storage: path resolution, ClickHouse load/save, provenance."""

from __future__ import annotations

import json
import logging
import os
import socket
from datetime import UTC, datetime
from pathlib import Path

from .models import _CHECKPOINT_DIR, PopulationCheckpoint

logger = logging.getLogger(__name__)


def _get_checkpoint_path(
    symbol: str,
    threshold_decimal_bps: int,
    start_date: str,
    end_date: str,
    checkpoint_dir: Path | None = None,
    ouroboros_mode: str = "aion",
) -> Path:
    """Get the checkpoint file path for a population job.

    Parameters
    ----------
    symbol : str
        Trading symbol.
    threshold_decimal_bps : int
        Threshold in decimal basis points. Included in filename to prevent
        collisions when multiple thresholds run concurrently (Issue #84).
    start_date : str
        Start date (YYYY-MM-DD).
    end_date : str
        End date (YYYY-MM-DD).
    checkpoint_dir : Path | None
        Custom checkpoint directory. Uses default if None.
    ouroboros_mode : str
        Ouroboros mode included in filename to prevent cross-mode
        checkpoint pollution (Issue #126).

    Returns
    -------
    Path
        Path to the checkpoint file.
    """
    if checkpoint_dir is None:
        checkpoint_dir = _CHECKPOINT_DIR

    # Issue #126: Mode in filename prevents cross-mode resume contamination
    filename = (
        f"{symbol}_{threshold_decimal_bps}_{start_date}_{end_date}"
        f"_{ouroboros_mode}.json"
    )
    return checkpoint_dir / filename


def _load_checkpoint_from_clickhouse(
    symbol: str,
    threshold_decimal_bps: int,
    start_date: str,
    end_date: str,
    ouroboros_mode: str = "aion",
) -> PopulationCheckpoint | None:
    """Load checkpoint from ClickHouse for cross-machine resume.

    Issue #69: Hybrid checkpoint storage enables resume on different machines.

    Parameters
    ----------
    symbol : str
        Trading symbol.
    threshold_decimal_bps : int
        Threshold in decimal basis points.
    start_date : str
        Start date (YYYY-MM-DD).
    end_date : str
        End date (YYYY-MM-DD).
    ouroboros_mode : str
        Ouroboros reset mode filter (default: "aion").
        Prevents cross-mode checkpoint pollution.

    Returns
    -------
    PopulationCheckpoint | None
        Loaded checkpoint, or None if not found.
    """
    try:
        from opendeviationbar.clickhouse import OpenDeviationBarCache

        with OpenDeviationBarCache() as cache:
            data = cache.load_checkpoint(
                symbol,
                threshold_decimal_bps,
                start_date,
                end_date,
                ouroboros_mode=ouroboros_mode,
            )
            if data is None:
                return None

            # Convert ClickHouse data to PopulationCheckpoint
            return PopulationCheckpoint(
                symbol=symbol,
                threshold_bps=threshold_decimal_bps,
                start_date=start_date,
                end_date=end_date,
                last_completed_date=data["last_completed_date"],
                bars_written=data["bars_written"],
                processor_checkpoint=json.loads(data["processor_checkpoint"])
                if data.get("processor_checkpoint")
                else None,
                last_trade_timestamp_us=data.get("last_trade_timestamp_us"),
                include_microstructure=data.get("include_microstructure", False),
                ouroboros_mode=data.get("ouroboros_mode", "aion"),
                # Issue #72: Full Audit Trail
                first_agg_trade_id_in_bar=data.get("first_agg_trade_id_in_bar"),
                last_agg_trade_id_in_bar=data.get("last_agg_trade_id_in_bar"),
                # Issue #111 (Ariadne): High-water mark
                last_processed_agg_trade_id=data.get("last_processed_agg_trade_id"),
            )
    except (ImportError, ConnectionError, OSError, RuntimeError) as e:
        logger.debug("ClickHouse checkpoint load failed: %s", e)
        return None


def _save_checkpoint_to_clickhouse(checkpoint: PopulationCheckpoint) -> None:
    """Save checkpoint to ClickHouse for cross-machine resume.

    Issue #69: Hybrid checkpoint storage enables resume on different machines.

    Parameters
    ----------
    checkpoint : PopulationCheckpoint
        Checkpoint to save.
    """
    try:
        from opendeviationbar.clickhouse import OpenDeviationBarCache

        with OpenDeviationBarCache() as cache:
            cache.save_checkpoint(
                symbol=checkpoint.symbol,
                threshold_decimal_bps=checkpoint.threshold_bps,
                start_date=checkpoint.start_date,
                end_date=checkpoint.end_date,
                last_completed_date=checkpoint.last_completed_date,
                last_trade_timestamp_us=checkpoint.last_trade_timestamp_us,
                processor_checkpoint=json.dumps(checkpoint.processor_checkpoint)
                if checkpoint.processor_checkpoint
                else "",
                bars_written=checkpoint.bars_written,
                include_microstructure=checkpoint.include_microstructure,
                ouroboros_mode=checkpoint.ouroboros_mode,
                # Issue #72: Full Audit Trail
                first_agg_trade_id_in_bar=checkpoint.first_agg_trade_id_in_bar,
                last_agg_trade_id_in_bar=checkpoint.last_agg_trade_id_in_bar,
                # Issue #111 (Ariadne): High-water mark
                last_processed_agg_trade_id=checkpoint.last_processed_agg_trade_id,
            )
    except (ImportError, ConnectionError, OSError, RuntimeError) as e:
        logger.debug("ClickHouse checkpoint save failed (non-fatal): %s", e)


def _checkpoint_provenance(trace_id: str | None = None) -> dict:
    """Build provenance metadata for checkpoint files (Issue #97)."""
    import opendeviationbar

    return {
        "service": "opendeviationbar-py",
        "version": getattr(opendeviationbar, "__version__", "unknown"),
        "git_sha": os.environ.get("OPENDEVIATIONBAR_GIT_SHA", "unknown"),
        "host": socket.gethostname(),
        "pid": os.getpid(),
        "created_utc": datetime.now(UTC).isoformat(),
        "trace_id": trace_id,
    }
