"""
JSON Store — simple file-based repository.
Replace this layer with SQLAlchemy to migrate to PostgreSQL / MySQL.
Only this file reads or writes to the filesystem.
"""

import json, os, uuid
from datetime import datetime, timezone
from typing import Any, Dict, List, Optional
from app.utils.logger import log


# ── File map resolved at import time ──────────────────────────
def _file(name: str) -> str:
    from app.config import cfg
    os.makedirs(cfg.DATA_DIR, exist_ok=True)
    return os.path.join(cfg.DATA_DIR, f"{name}.json")


TABLES = ["avatars", "projects", "videos", "voices", "settings"]


def init_store():
    from app.config import cfg
    for d in [cfg.DATA_DIR, cfg.UPLOAD_DIR, cfg.OUTPUT_DIR]:
        os.makedirs(d, exist_ok=True)
    for t in TABLES:
        p = _file(t)
        if not os.path.exists(p):
            with open(p, "w") as f:
                json.dump([], f)
    log.info("Store initialised — data dir: %s", cfg.DATA_DIR)


# ── Low-level I/O ──────────────────────────────────────────────
def _read(path: str) -> List[Dict]:
    try:
        with open(path) as f:
            return json.load(f)
    except Exception:
        return []


def _write(path: str, data: list):
    with open(path, "w") as f:
        json.dump(data, f, indent=2, default=str)


def _now() -> str:
    return datetime.now(timezone.utc).isoformat()


# ── Store class ────────────────────────────────────────────────
class Store:
    """One instance per collection. Swap internals for SQLAlchemy session."""

    def __init__(self, table: str):
        assert table in TABLES, f"Unknown table: {table}"
        self._table = table

    def _path(self) -> str:
        return _file(self._table)

    def create(self, data: Dict) -> Dict:
        rows = _read(self._path())
        row  = {"id": str(uuid.uuid4()), "created_at": _now(), "updated_at": _now(), **data}
        rows.append(row)
        _write(self._path(), rows)
        return row

    def get(self, item_id: str) -> Optional[Dict]:
        return next((r for r in _read(self._path())
                     if r.get("id") == item_id and not r.get("deleted")), None)

    def list(
        self,
        filters: Optional[Dict] = None,
        search: Optional[str] = None,
        search_fields: Optional[List[str]] = None,
        sort_by: str = "created_at",
        desc: bool = True,
        page: int = 1,
        per_page: int = 20,
    ) -> Dict:
        rows = [r for r in _read(self._path()) if not r.get("deleted")]
        if filters:
            rows = [r for r in rows if all(r.get(k) == v for k, v in filters.items())]
        if search and search_fields:
            q = search.lower()
            rows = [r for r in rows
                    if any(q in str(r.get(f, "")).lower() for f in search_fields)]
        rows.sort(key=lambda x: x.get(sort_by, ""), reverse=desc)
        total = len(rows)
        start = (page - 1) * per_page
        return {
            "items": rows[start: start + per_page],
            "total": total,
            "page":  page,
            "pages": max(1, -(-total // per_page)),
        }

    def update(self, item_id: str, data: Dict) -> Optional[Dict]:
        rows = _read(self._path())
        for i, r in enumerate(rows):
            if r.get("id") == item_id and not r.get("deleted"):
                rows[i] = {**r, **data, "updated_at": _now()}
                _write(self._path(), rows)
                return rows[i]
        return None

    def delete(self, item_id: str) -> bool:
        rows = _read(self._path())
        for i, r in enumerate(rows):
            if r.get("id") == item_id:
                rows[i]["deleted"]    = True
                rows[i]["updated_at"] = _now()
                _write(self._path(), rows)
                return True
        return False

    def count(self, filters: Optional[Dict] = None) -> int:
        rows = [r for r in _read(self._path()) if not r.get("deleted")]
        if filters:
            rows = [r for r in rows if all(r.get(k) == v for k, v in filters.items())]
        return len(rows)


# ── Singletons ─────────────────────────────────────────────────
avatars_store  = Store("avatars")
projects_store = Store("projects")
videos_store   = Store("videos")
voices_store   = Store("voices")
settings_store = Store("settings")
