"""
Snapshot Store — captures project memory state over time.

Storage: .kodara/snapshots/YYYY-MM-DD_HHMMSS.json

Snapshots answer: "how did the architecture look 3 months ago?"
They also enable: drift detection, growth tracking, onboarding history.

Auto-snapshot: created by `kodara init` once per day (if not exists for today).
Manual:        `kodara snapshot`
List:          `kodara snapshot list`
Compare:       `kodara snapshot diff <date>`
"""

from __future__ import annotations

import json
import shutil
from dataclasses import dataclass
from datetime import datetime
from pathlib import Path

from ..memory.store import MemoryStore, KodaraIndex

SNAPSHOTS_DIR = "snapshots"


@dataclass
class SnapshotMeta:
    filename: str
    date: str           # YYYY-MM-DD
    timestamp: str      # YYYY-MM-DD HH:MM
    file_count: int
    module_count: int
    languages: dict[str, int]


class SnapshotStore:
    def __init__(self, kodara_dir: Path):
        self.snapshots_dir = kodara_dir / SNAPSHOTS_DIR

    def create(self, idx: KodaraIndex) -> str:
        """
        Save current index as a snapshot.
        Returns the snapshot filename.
        """
        self.snapshots_dir.mkdir(parents=True, exist_ok=True)
        now = datetime.now()
        filename = now.strftime("%Y-%m-%d_%H%M%S") + ".json"
        dst = self.snapshots_dir / filename

        store = MemoryStore.__new__(MemoryStore)
        # Reuse save logic — serialize the index
        data = _index_to_dict(idx)
        data["_snapshot_at"] = now.isoformat()

        tmp = dst.with_suffix(".tmp")
        tmp.write_text(json.dumps(data, indent=2, ensure_ascii=False), encoding="utf-8")
        tmp.replace(dst)
        return filename

    def auto_snapshot(self, idx: KodaraIndex) -> str | None:
        """
        Create a snapshot only if none exists for today.
        Called automatically by `kodara init`.
        Returns filename if created, None if skipped.
        """
        today = datetime.now().strftime("%Y-%m-%d")
        if self.snapshots_dir.exists():
            existing = list(self.snapshots_dir.glob(f"{today}_*.json"))
            if existing:
                return None  # already have one for today
        return self.create(idx)

    def list(self) -> list[SnapshotMeta]:
        """Return all snapshots, newest first."""
        if not self.snapshots_dir.exists():
            return []

        metas: list[SnapshotMeta] = []
        for f in sorted(self.snapshots_dir.glob("*.json"), reverse=True):
            try:
                data = json.loads(f.read_text(encoding="utf-8"))
                metas.append(SnapshotMeta(
                    filename=f.name,
                    date=f.stem[:10],
                    timestamp=f.stem[:10] + " " + f.stem[11:13] + ":" + f.stem[13:15],
                    file_count=data.get("file_count", 0),
                    module_count=len(data.get("modules", {})),
                    languages=data.get("language_counts", {}),
                ))
            except Exception:
                continue
        return metas

    def load(self, filename: str) -> dict | None:
        """Load a specific snapshot by filename or date prefix."""
        if not self.snapshots_dir.exists():
            return None

        # Exact match
        exact = self.snapshots_dir / filename
        if exact.exists():
            try:
                return json.loads(exact.read_text(encoding="utf-8"))
            except Exception:
                return None

        # Date prefix match — return newest for that date
        matches = sorted(self.snapshots_dir.glob(f"{filename}*.json"), reverse=True)
        if matches:
            try:
                return json.loads(matches[0].read_text(encoding="utf-8"))
            except Exception:
                return None

        return None

    def compare(self, idx: KodaraIndex, filename: str) -> dict:
        """
        Compare current index to a snapshot.
        Returns: added, removed, changed module counts + file delta.
        """
        snap = self.load(filename)
        if not snap:
            raise ValueError(f"Snapshot not found: {filename}")

        current_paths = set(idx.modules.keys())
        snap_paths = set(snap.get("modules", {}).keys())

        added = current_paths - snap_paths
        removed = snap_paths - current_paths
        common = current_paths & snap_paths

        changed = set()
        for path in common:
            cur_hash = idx.modules[path].get("file_hash", "")
            snap_hash = snap["modules"][path].get("file_hash", "")
            if cur_hash != snap_hash:
                changed.add(path)

        return {
            "snapshot": filename,
            "snapshot_date": filename[:10],
            "current_files": idx.file_count,
            "snapshot_files": snap.get("file_count", 0),
            "added_modules": sorted(added),
            "removed_modules": sorted(removed),
            "changed_modules": sorted(changed),
            "summary": (
                f"+{len(added)} added, -{len(removed)} removed, "
                f"~{len(changed)} modified since {filename[:10]}"
            ),
        }


def _index_to_dict(idx: KodaraIndex) -> dict:
    from dataclasses import asdict
    return asdict(idx)
