"""JSON-file-backed peer store."""

from __future__ import annotations

import json
import logging
import os
import tempfile
import time
from pathlib import Path

from pydantic import BaseModel, Field

logger = logging.getLogger(__name__)


class PeerRecord(BaseModel):
    peer_id: str
    alias: str = ""
    public_key_pem: str = ""
    addresses: list[str] = Field(default_factory=list)
    trust_level: int = 0  # 0=unknown, 1=verified, 2=trusted, 3=allied
    scope_instructions: str = ""
    description: str = ""
    capabilities: list[str] = Field(default_factory=list)
    last_seen: float = 0.0
    added_at: float = Field(default_factory=time.time)
    metadata: dict = Field(default_factory=dict)


class PeerStore:
    """JSON-file-backed store. Loads on init, atomic flush on every write."""

    def __init__(self, path: Path | str = "~/.p2p/peers.json") -> None:
        self._path = Path(path).expanduser()
        self._peers: dict[str, PeerRecord] = {}
        self._load()

    def _load(self) -> None:
        if not self._path.exists():
            return
        try:
            data = json.loads(self._path.read_text("utf-8"))
            self._peers = {k: PeerRecord.model_validate(v) for k, v in data.items()}
        except Exception:
            logger.warning("Failed to load %s", self._path, exc_info=True)

    def _flush(self) -> None:
        self._path.parent.mkdir(parents=True, exist_ok=True)
        try:
            os.chmod(str(self._path.parent), 0o700)
        except OSError:
            pass
        data = {k: v.model_dump(mode="json") for k, v in self._peers.items()}
        fd, tmp = tempfile.mkstemp(dir=str(self._path.parent), suffix=".tmp")
        try:
            os.fchmod(fd, 0o600)
            with os.fdopen(fd, "w", encoding="utf-8") as f:
                json.dump(data, f, indent=2, ensure_ascii=False)
            os.replace(tmp, str(self._path))
            os.chmod(str(self._path), 0o600)
        except Exception:
            try:
                os.unlink(tmp)
            except OSError:
                pass
            raise

    def get(self, peer_id: str) -> PeerRecord | None:
        return self._peers.get(peer_id)

    def save(self, record: PeerRecord) -> None:
        self._peers[record.peer_id] = record
        self._flush()

    def remove(self, peer_id: str) -> bool:
        if peer_id in self._peers:
            del self._peers[peer_id]
            self._flush()
            return True
        return False

    def list_all(self) -> list[PeerRecord]:
        return list(self._peers.values())

    def update_last_seen(self, peer_id: str) -> None:
        r = self._peers.get(peer_id)
        if r:
            r.last_seen = time.time()
            self._flush()

    def update_description(self, peer_id: str, desc: str) -> None:
        r = self._peers.get(peer_id)
        if r:
            r.description = desc
            self._flush()

    def update_trust(self, peer_id: str, level: int) -> None:
        r = self._peers.get(peer_id)
        if r:
            r.trust_level = level
            self._flush()

    def __len__(self) -> int:
        return len(self._peers)
