# -*- coding: utf-8 -*-
"""JSON 存储引擎：一个文件 = 一张表。

当前阶段用本地 JSON 文件代替数据库。每个文件是一个 JSON 数组，
元素为一行记录；存储层只做最朴素的"读全量/写全量 + 原子替换"，
业务逻辑全部收敛在 ``repositories.py``。

未来数据库映射（下一阶段据此设计）：
    JsonTable(path)      ->  一张数据库表（表名 = 文件名）
    数组元素             ->  一行记录（主键 = 记录里的 ``id`` 字段）
    记录字段             ->  一列
"""
from __future__ import annotations

import json
import threading
from pathlib import Path
from typing import Callable


class JsonTable:
    """对单个 JSON 数组文件的最小 CRUD 封装。

    - 写入使用「写临时文件 + rename 替换」，避免崩溃/并发读到半截数据。
    - 内部用 RLock 保证同一进程内的读写互斥（演示级并发足够）。
    """

    def __init__(self, path: Path):
        self.path = path
        self._lock = threading.RLock()

    def all(self) -> list[dict]:
        """读全部记录。文件不存在/损坏时返回空表（下次写入时重建）。"""
        with self._lock:
            if not self.path.exists():
                return []
            try:
                with open(self.path, "r", encoding="utf-8") as fh:
                    data = json.load(fh)
            except (json.JSONDecodeError, OSError):
                return []
            return data if isinstance(data, list) else []

    def save(self, records: list[dict]) -> None:
        """整体写回。原子：先写 ``<name>.tmp`` 再 rename。"""
        with self._lock:
            self.path.parent.mkdir(parents=True, exist_ok=True)
            tmp = self.path.with_name(self.path.name + ".tmp")
            with open(tmp, "w", encoding="utf-8") as fh:
                json.dump(records, fh, ensure_ascii=False, indent=2)
            tmp.replace(self.path)

    # ------------------------------------------------------------------
    # 便捷操作
    # ------------------------------------------------------------------
    def find(self, predicate: Callable[[dict], bool]) -> dict | None:
        """返回第一条满足条件的记录，没有则 None。"""
        for record in self.all():
            if predicate(record):
                return record
        return None

    def insert(self, record: dict) -> dict:
        """追加一条记录并返回它。"""
        records = self.all()
        records.append(record)
        self.save(records)
        return record

    def update(self, record_id: str, fields: dict) -> dict | None:
        """按 ``id`` 合并更新字段，返回更新后的记录（不存在则 None）。"""
        records = self.all()
        for record in records:
            if record.get("id") == record_id:
                record.update(fields)
                self.save(records)
                return record
        return None

    def delete_matching(self, predicate: Callable[[dict], bool]) -> int:
        """删除所有满足条件的记录，返回删除条数。"""
        records = self.all()
        kept = [r for r in records if not predicate(r)]
        removed = len(records) - len(kept)
        if removed:
            self.save(kept)
        return removed
