import json
from pathlib import Path
from typing import Optional

import anyio

from .models import AppConfig


class ConfigStore:
  def __init__(self, file_path: Path):
    self._file_path = file_path
    self._lock = anyio.Lock()

  def _write_unlocked(self, cfg: AppConfig) -> None:
    self._file_path.parent.mkdir(parents=True, exist_ok=True)
    self._file_path.write_text(
      json.dumps(cfg.model_dump(mode="json"), indent=2, ensure_ascii=False),
      encoding="utf-8",
    )

  async def load(self) -> AppConfig:
    async with self._lock:
      if not self._file_path.exists():
        cfg = AppConfig(cameras=[])
        self._write_unlocked(cfg)
        return cfg

      raw = self._file_path.read_text(encoding="utf-8")
      data = json.loads(raw) if raw.strip() else {}
      cfg = AppConfig.model_validate(data)
      # Auto-fill newly introduced config keys.
      normalized = cfg.model_dump(mode="json")
      if normalized != data:
        self._write_unlocked(cfg)
      return cfg

  async def save(self, cfg: AppConfig) -> None:
    async with self._lock:
      self._write_unlocked(cfg)


def default_store(project_root: Optional[Path] = None) -> ConfigStore:
  root = project_root or Path(__file__).resolve().parents[2]
  return ConfigStore(root / "api" / "data" / "config.json")

