"""
Performance reporter: persists trades to JSON, computes statistics,
and prints a dashboard summary.
"""
import json
import logging
import math
import os
from typing import List, Optional

from tabdeal_bot.exchange.models import Trade, TradeResult

logger = logging.getLogger(__name__)


class Reporter:
    def __init__(self, trades_file: str):
        self.trades_file = trades_file
        self._trades: List[Trade] = []
        self._load()

    def _load(self):
        if os.path.exists(self.trades_file):
            try:
                with open(self.trades_file, "r") as f:
                    raw = json.load(f)
                # We store minimal serializable dicts
                self._trades_raw: List[dict] = raw
            except Exception:
                self._trades_raw = []
        else:
            self._trades_raw = []

    def _save(self):
        os.makedirs(os.path.dirname(self.trades_file) or ".", exist_ok=True)
        with open(self.trades_file, "w") as f:
            json.dump(self._trades_raw, f, indent=2)

    def record_open(self, trade: Trade):
        d = {
            "id": trade.id,
            "symbol": trade.symbol,
            "direction": trade.direction.value,
            "entry_price": trade.entry_price,
            "sl_price": trade.sl_price,
            "tp_price": trade.tp_price,
            "quantity": trade.quantity,
            "leverage": trade.leverage,
            "open_time": trade.open_time,
            "status": "OPEN",
            "notes": trade.notes,
        }
        self._trades_raw.append(d)
        self._save()

    def record_close(self, trade: Trade):
        for d in reversed(self._trades_raw):
            if d["id"] == trade.id:
                d["close_time"] = trade.close_time
                d["exit_price"] = trade.exit_price
                d["pnl_usdt"] = trade.pnl_usdt
                d["fees_usdt"] = trade.fees_usdt
                d["net_pnl"] = trade.net_pnl
                d["result"] = trade.result.value if trade.result else None
                d["status"] = "CLOSED"
                break
        self._save()

    def print_dashboard(self, balance: float, open_trade: Optional[Trade] = None):
        closed = [t for t in self._trades_raw if t.get("status") == "CLOSED"]
        wins = [t for t in closed if t.get("result") == TradeResult.WIN.value]
        losses = [t for t in closed if t.get("result") == TradeResult.LOSS.value]

        total = len(closed)
        win_rate = len(wins) / total * 100 if total > 0 else 0.0
        net_pnls = [t.get("net_pnl", 0) for t in closed if t.get("net_pnl") is not None]
        total_pnl = sum(net_pnls)

        avg_win = (
            sum(t.get("net_pnl", 0) for t in wins) / len(wins) if wins else 0.0
        )
        avg_loss = (
            abs(sum(t.get("net_pnl", 0) for t in losses)) / len(losses) if losses else 0.0
        )
        profit_factor = (
            (len(wins) * avg_win) / (len(losses) * avg_loss)
            if losses and avg_loss > 0 else float("inf")
        )
        expected_value = (win_rate / 100 * avg_win) - ((1 - win_rate / 100) * avg_loss)

        # Drawdown
        running = 0.0
        peak = 0.0
        max_dd = 0.0
        for p in net_pnls:
            running += p
            if running > peak:
                peak = running
            dd = peak - running
            if dd > max_dd:
                max_dd = dd

        # Sharpe (simplified, using net PnL per trade as returns)
        if len(net_pnls) > 1:
            mean_r = sum(net_pnls) / len(net_pnls)
            variance = sum((r - mean_r) ** 2 for r in net_pnls) / len(net_pnls)
            std_r = math.sqrt(variance)
            sharpe = mean_r / std_r if std_r > 0 else 0.0
        else:
            sharpe = 0.0

        # Consecutive losses
        max_consec_loss = 0
        cur_consec = 0
        for t in closed:
            if t.get("result") == TradeResult.LOSS.value:
                cur_consec += 1
                max_consec_loss = max(max_consec_loss, cur_consec)
            else:
                cur_consec = 0

        sep = "─" * 50
        print(f"\n{'═' * 50}")
        print(f"  TABDEAL BOT DASHBOARD")
        print(f"{'═' * 50}")
        print(f"  Balance (USDT):       {balance:>12.2f}")
        print(f"  Total PnL (net):      {total_pnl:>+12.2f}")
        print(sep)
        print(f"  Trades total:         {total:>12d}")
        print(f"  Wins / Losses:        {len(wins):>5d} / {len(losses):<5d}")
        print(f"  Win Rate:             {win_rate:>11.1f}%")
        print(f"  Avg Win:              {avg_win:>+12.4f}")
        print(f"  Avg Loss:             {avg_loss:>+12.4f}")
        print(f"  Profit Factor:        {profit_factor:>12.3f}")
        print(f"  Expected Value:       {expected_value:>+12.4f}")
        print(f"  Sharpe Ratio:         {sharpe:>12.3f}")
        print(f"  Max Drawdown:         {max_dd:>+12.4f}")
        print(f"  Max Consec. Losses:   {max_consec_loss:>12d}")
        print(sep)
        if open_trade:
            print(f"  Open Trade:           {open_trade.direction.value} {open_trade.symbol}")
            print(f"    Entry: {open_trade.entry_price:.4f}  SL: {open_trade.sl_price:.4f}  TP: {open_trade.tp_price:.4f}")
        else:
            print("  Open Trade:           None")
        print(f"{'═' * 50}\n")
