"""Price history tracking and diff support.

Each run can optionally append a snapshot to a JSONL history file.
The diff function compares the current run against the last snapshot.
"""

from __future__ import annotations

import json
import time
from pathlib import Path
from typing import Any


def append_snapshot(
    history_file: Path,
    rows: list[dict[str, Any]],
    *,
    profile: str | None = None,
    currency: str | None = None,
) -> None:
    """Append a timestamped snapshot of scored server IDs and prices."""
    history_file.parent.mkdir(parents=True, exist_ok=True)
    snapshot = {
        "timestamp": int(time.time()),
        "iso": time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()),
        "profile": profile,
        "currency": currency,
        "count": len(rows),
        "servers": [
            {
                "id": r["id"],
                "cpu": r["cpu"],
                "price_amount": r["price_amount"],
                "currency": r.get("currency"),
                "ram_gb": r["ram_gb"],
                "storage_gb": r["storage_gb"],
                "score_overall_rank": round(r.get("score_overall_rank", 0), 6),
            }
            for r in rows
        ],
    }
    with history_file.open("a") as f:
        f.write(json.dumps(snapshot, separators=(",", ":")) + "\n")


def load_last_snapshot(history_file: Path) -> dict[str, Any] | None:
    """Load the most recent snapshot from the history file, or None."""
    if not history_file.is_file():
        return None
    last_line = ""
    with history_file.open() as f:
        for line in f:
            stripped = line.strip()
            if stripped:
                last_line = stripped
    if not last_line:
        return None
    try:
        return json.loads(last_line)
    except json.JSONDecodeError:
        return None


def diff_snapshots(
    previous: dict[str, Any],
    current_rows: list[dict[str, Any]],
) -> dict[str, Any]:
    """Compare current rows against a previous snapshot.

    Returns a dict with ``new``, ``removed``, ``price_changes``, and ``unchanged`` counts.
    """
    prev_by_id: dict[Any, dict[str, Any]] = {
        s["id"]: s for s in previous.get("servers", [])
    }
    curr_by_id: dict[Any, dict[str, Any]] = {}
    for r in current_rows:
        curr_by_id[r["id"]] = {
            "id": r["id"],
            "cpu": r["cpu"],
            "price_amount": r["price_amount"],
            "currency": r.get("currency"),
            "ram_gb": r["ram_gb"],
            "storage_gb": r["storage_gb"],
            "score_overall_rank": round(r.get("score_overall_rank", 0), 6),
        }

    new_ids = set(curr_by_id) - set(prev_by_id)
    removed_ids = set(prev_by_id) - set(curr_by_id)
    common_ids = set(curr_by_id) & set(prev_by_id)

    price_changes: list[dict[str, Any]] = []
    for sid in sorted(common_ids):
        old_price = prev_by_id[sid]["price_amount"]
        new_price = curr_by_id[sid]["price_amount"]
        if abs(old_price - new_price) > 0.01:
            price_changes.append({
                "id": sid,
                "old_price": old_price,
                "new_price": new_price,
                "delta": round(new_price - old_price, 2),
            })

    return {
        "previous_timestamp": previous.get("iso", previous.get("timestamp")),
        "new": sorted(new_ids),
        "removed": sorted(removed_ids),
        "price_changes": price_changes,
        "new_count": len(new_ids),
        "removed_count": len(removed_ids),
        "price_change_count": len(price_changes),
        "unchanged_count": len(common_ids) - len(price_changes),
    }
