# ═══════════════════════════════════════════════════════════════
#  risk_manager.py — Gestão de Risco e Sizing de Posição
# ═══════════════════════════════════════════════════════════════

import logging
from datetime import datetime, date
from typing import Optional
import config as cfg

logger = logging.getLogger("BotBTC.RiskManager")


class RiskManager:
    """
    Controla tamanho de posição, stop loss, take profit,
    trailing stop e limites diários de trading.
    """

    def __init__(self):
        self.trades_hoje: int         = 0
        self.pnl_hoje: float          = 0.0
        self.pnl_total: float         = 0.0
        self.ultimo_dia: date         = date.today()
        self.posicao_aberta: bool     = False
        self.entrada_preco: float     = 0.0
        self.entrada_qtd: float       = 0.0
        self.stop_atual: float        = 0.0
        self.alvo1: float             = 0.0
        self.alvo2: float             = 0.0
        self.alvo1_atingido: bool     = False
        self.maxima_posicao: float    = 0.0
        self.capital: float           = cfg.CAPITAL_TOTAL
        self.wins: int                = 0
        self.losses: int              = 0

    def _resetar_dia(self):
        if date.today() > self.ultimo_dia:
            self.trades_hoje = 0
            self.pnl_hoje    = 0.0
            self.ultimo_dia  = date.today()
            logger.info("📅 Novo dia — contadores resetados")

    def pode_operar(self) -> tuple[bool, str]:
        """Verifica se está permitido abrir novo trade."""
        self._resetar_dia()
        hora_atual = datetime.now().hour
        h_inicio, h_fim = cfg.HORARIO_OPERACAO

        if self.posicao_aberta:
            return False, "Já existe posição aberta"
        if self.trades_hoje >= cfg.MAX_TRADES_DIA:
            return False, f"Limite diário atingido ({cfg.MAX_TRADES_DIA} trades)"
        if not (h_inicio <= hora_atual < h_fim):
            return False, f"Fora do horário de operação ({h_inicio}h–{h_fim}h)"
        if self.capital < 10:
            return False, f"Capital insuficiente (${self.capital:.2f})"

        return True, "OK"

    def calcular_tamanho(self, preco_entrada: float, stop: float) -> float:
        """
        Calcula quantidade de BTC a comprar baseado no risco por trade.
        Método: (Capital × Risco%) / (Entrada − Stop)
        """
        risco_usd   = self.capital * cfg.RISCO_POR_TRADE
        distancia   = abs(preco_entrada - stop)

        if distancia <= 0:
            logger.warning("⚠️ Distância de stop inválida")
            return 0.0

        qtd = risco_usd / distancia
        custo_total = qtd * preco_entrada

        # Limita ao máximo de posição configurado
        limite = self.capital * cfg.MAX_POSICAO
        if custo_total > limite:
            qtd = limite / preco_entrada
            logger.info(f"📏 Tamanho ajustado ao limite: {qtd:.6f} BTC")

        qtd = round(qtd, 5)
        logger.info(
            f"📐 Sizing: risco=${risco_usd:.2f} | "
            f"distância=${distancia:.2f} | qtd={qtd:.5f} BTC | "
            f"custo=${qtd * preco_entrada:.2f}"
        )
        return qtd

    def registrar_entrada(self, preco: float, qtd: float, stop: float, alvo1: float, alvo2: float):
        self.posicao_aberta   = True
        self.entrada_preco    = preco
        self.entrada_qtd      = qtd
        self.stop_atual       = stop
        self.alvo1            = alvo1
        self.alvo2            = alvo2
        self.alvo1_atingido   = False
        self.maxima_posicao   = preco
        self.capital          -= qtd * preco
        self.trades_hoje      += 1
        logger.info(
            f"📥 ENTRADA registrada: {qtd:.5f} BTC @ ${preco:,.2f} | "
            f"Stop: ${stop:,.2f} | A1: ${alvo1:,.2f} | A2: ${alvo2:,.2f}"
        )

    def atualizar_trailing(self, preco_atual: float) -> Optional[str]:
        """
        Atualiza trailing stop e verifica se deve fechar posição.
        Retorna: "STOP" | "ALVO1" | "ALVO2" | None
        """
        if not self.posicao_aberta:
            return None

        # Atualiza máxima
        if preco_atual > self.maxima_posicao:
            self.maxima_posicao = preco_atual

        # Verifica Alvo 1
        if not self.alvo1_atingido and preco_atual >= self.alvo1:
            self.alvo1_atingido = True
            # Move stop para entrada (break-even) + trailing
            novo_stop = max(self.entrada_preco, preco_atual * (1 - cfg.TRAILING_PCT))
            if novo_stop > self.stop_atual:
                self.stop_atual = novo_stop
                logger.info(f"🎯 ALVO 1 atingido! Stop movido para ${novo_stop:,.2f}")
            return "ALVO1"

        # Trailing stop após alvo 1
        if self.alvo1_atingido and cfg.TRAILING_STOP:
            trailing = self.maxima_posicao * (1 - cfg.TRAILING_PCT)
            if trailing > self.stop_atual:
                self.stop_atual = trailing
                logger.debug(f"📈 Trailing stop: ${self.stop_atual:,.2f}")

        # Verifica Alvo 2
        if preco_atual >= self.alvo2:
            return "ALVO2"

        # Verifica Stop Loss
        if preco_atual <= self.stop_atual:
            return "STOP"

        return None

    def registrar_saida(self, preco: float, qtd: float, motivo: str):
        receita  = qtd * preco
        custo    = qtd * self.entrada_preco
        pnl      = receita - custo
        pnl_pct  = (pnl / custo) * 100

        self.capital        += receita
        self.pnl_hoje       += pnl
        self.pnl_total      += pnl
        self.posicao_aberta  = False

        if pnl >= 0:
            self.wins += 1
        else:
            self.losses += 1

        logger.info(
            f"📤 SAÍDA [{motivo}]: {qtd:.5f} BTC @ ${preco:,.2f} | "
            f"P&L: {'+'if pnl>=0 else ''}{pnl:.2f} ({pnl_pct:.2f}%) | "
            f"Capital: ${self.capital:.2f}"
        )
        return pnl, pnl_pct

    def win_rate(self) -> float:
        total = self.wins + self.losses
        return (self.wins / total * 100) if total > 0 else 0.0

    def status(self) -> dict:
        return {
            "capital":        round(self.capital, 2),
            "pnl_hoje":       round(self.pnl_hoje, 2),
            "pnl_total":      round(self.pnl_total, 2),
            "trades_hoje":    self.trades_hoje,
            "wins":           self.wins,
            "losses":         self.losses,
            "win_rate":       round(self.win_rate(), 1),
            "posicao_aberta": self.posicao_aberta,
            "entrada_preco":  self.entrada_preco,
            "stop_atual":     round(self.stop_atual, 2),
        }
