from __future__ import annotations

import json
import time
from pathlib import Path
from typing import Any

from kraken_bot.models import Side


class TradeLedger:
    def __init__(self, path: Path) -> None:
        self.path = path
        self.positions: dict[str, dict[str, Any]] = {}
        self.events: list[dict[str, Any]] = []
        self.load()

    def load(self) -> None:
        if not self.path.exists():
            return
        try:
            raw = json.loads(self.path.read_text(encoding="utf-8"))
        except json.JSONDecodeError:
            return
        self.positions = dict(raw.get("positions", {}))
        self.events = list(raw.get("events", []))

    def save(self) -> None:
        self.path.parent.mkdir(parents=True, exist_ok=True)
        payload = {
            "positions": self.positions,
            "events": self.events[-500:],
        }
        self.path.write_text(json.dumps(payload, indent=2, sort_keys=True), encoding="utf-8")
        try:
            self.path.chmod(0o600)
        except OSError:
            pass

    def record_signal(
        self,
        symbol: str,
        side: Side,
        price: float,
        strategy: str,
        reason: str,
        dry_run: bool,
    ) -> dict[str, Any] | None:
        if side is Side.HOLD or price <= 0:
            return None

        now = int(time.time())
        symbol = symbol.upper()
        mode = "paper" if dry_run else "live"

        if side is Side.BUY:
            if symbol in self.positions:
                return None
            event = self._event(symbol, "entry", price, strategy, reason, mode, now)
            self.positions[symbol] = {
                "entry_time": now,
                "entry_price": price,
                "strategy": strategy,
                "mode": mode,
            }
            self.events.append(event)
            self.save()
            return event

        if side is Side.SELL:
            position = self.positions.pop(symbol, None)
            event_type = "exit" if position else "sell_signal"
            event = self._event(symbol, event_type, price, strategy, reason, mode, now)
            if position:
                event["entry_price"] = position.get("entry_price")
                event["pnl_pct"] = round(((price - float(position.get("entry_price", price))) / float(position.get("entry_price", price))) * 100, 4)
            self.events.append(event)
            self.save()
            return event

        return None

    def for_symbol(self, symbol: str) -> list[dict[str, Any]]:
        symbol = symbol.upper()
        return [event for event in self.events if event.get("symbol") == symbol]

    def open_position(self, symbol: str) -> dict[str, Any] | None:
        return self.positions.get(symbol.upper())

    def status_summary(self) -> dict[str, Any]:
        last_entry = self._last_event({"entry"})
        last_close = self._last_event({"exit"})
        last_trade = self._last_event({"entry", "exit", "sell_signal"})
        return {
            "open_positions": self.positions,
            "open_position_count": len(self.positions),
            "last_trade": last_trade,
            "last_entry": last_entry,
            "last_close": last_close,
        }

    def _last_event(self, event_types: set[str]) -> dict[str, Any] | None:
        for event in reversed(self.events):
            if event.get("type") in event_types:
                return event
        return None

    def _event(
        self,
        symbol: str,
        event_type: str,
        price: float,
        strategy: str,
        reason: str,
        mode: str,
        timestamp: int,
    ) -> dict[str, Any]:
        return {
            "symbol": symbol,
            "type": event_type,
            "time": timestamp,
            "iso_time": time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(timestamp)),
            "price": price,
            "strategy": strategy,
            "reason": reason,
            "mode": mode,
        }
