from __future__ import annotations

import time
from typing import Any

from ..models.db import Database, get_db


class Ledger:
    def __init__(self, db: Database | None = None) -> None:
        self.db = db or get_db()

    def snapshot(self) -> dict[str, Any]:
        row = self.db.fetchone("SELECT * FROM ledger_meta WHERE id=1")
        assert row is not None
        return {
            "equity": float(row["equity"]),
            "available": float(row["available"]),
            "reserved": float(row["reserved"]),
            "updated_at_ms": int(row["updated_at_ms"]),
        }

    def apply_cash(
        self,
        amount: float,
        *,
        kind: str,
        group_id: str | None = None,
        note: str = "",
        allow_negative: bool = False,
    ) -> float:
        """amount>0 入账；amount<0 出账。返回余额。

        LIVE 实盘成交后本地账本仅作镜像，须 allow_negative=True，避免「交易所已成交、本地拒记」导致卡仓。
        """
        now = int(time.time() * 1000)
        with self.db._lock:
            row = self.db._conn.execute("SELECT * FROM ledger_meta WHERE id=1").fetchone()
            assert row is not None
            equity = float(row["equity"]) + float(amount)
            available = float(row["available"]) + float(amount)
            if not allow_negative and available < -1e-9:
                raise RuntimeError("可用资金不足")
            self.db._conn.execute(
                "UPDATE ledger_meta SET equity=?, available=?, updated_at_ms=? WHERE id=1",
                (equity, available, now),
            )
            self.db._conn.execute(
                "INSERT INTO ledger_entries(group_id, kind, amount, balance_after, note, ts_ms) VALUES (?,?,?,?,?,?)",
                (group_id, kind, float(amount), equity, note, now),
            )
            self.db._conn.commit()
        try:
            from ..config import get_settings
            from .funds_wallets import SimFundsWallets

            if get_settings().is_sim:
                SimFundsWallets(self.db).mirror_cash(float(amount), kind=kind)
        except Exception:
            pass
        return equity

    def reset_equity(self, amount: float, *, note: str = "重置模拟资金") -> float:
        """将权益与可用资金重置为 amount（reserved 清零）。须在无持仓时调用。"""
        now = int(time.time() * 1000)
        amt = float(amount)
        if amt < 0:
            raise ValueError("模拟资金不能为负")
        with self.db._lock:
            self.db._conn.execute(
                "UPDATE ledger_meta SET equity=?, available=?, reserved=0, updated_at_ms=? WHERE id=1",
                (amt, amt, now),
            )
            self.db._conn.execute(
                "INSERT INTO ledger_entries(group_id, kind, amount, balance_after, note, ts_ms) VALUES (?,?,?,?,?,?)",
                (None, "reset", amt, amt, note, now),
            )
            self.db._conn.commit()
        try:
            from ..config import get_settings
            from .funds_wallets import SimFundsWallets

            if get_settings().is_sim:
                SimFundsWallets(self.db).reset_from_equity(amt)
        except Exception:
            pass
        return amt

    def get_setting_float(self, key: str, default: float) -> float:
        v = self.db.get_setting(key)
        if v is None or v == "":
            return default
        try:
            return float(v)
        except ValueError:
            return default

    def get_setting_int(self, key: str, default: int) -> int:
        return int(self.get_setting_float(key, float(default)))

    def get_setting_str(self, key: str, default: str) -> str:
        v = self.db.get_setting(key)
        if v is None or v == "":
            return default
        return str(v)

    def get_setting_bool(self, key: str, default: bool) -> bool:
        v = self.db.get_setting(key)
        if v is None or v == "":
            return default
        return str(v).strip().lower() in ("1", "true", "yes", "on")
