"""
Trade Planner — расчёт параметров сделки на основе ATR.

Рассчитывает:
    - Точка входа (entry)
    - Стоп-лосс (SL)
    - Тейк-профит (TP) — базовый и лесенка
    - Лесенка: 3 цели с частичным закрытием

Использует ATR(14) и мультипликаторы из config.py:
    SL = entry ± 1.5 × ATR
    TP = entry ± 3.0 × ATR
"""
from typing import Optional

import numpy as np
import pandas as pd

from config import get_target_config
from data.loader import load_dataframe

# MOEX стандартные размеры лотов
MOEX_LOT_SIZES: dict[str, int] = {
    'ASTR': 10, 'SBER': 10, 'VTBR': 1000, 'ROSN': 10,
    'NVTK': 1, 'PHOR': 1, 'SNGSP': 10, 'PLZL': 1,
    'X5': 1, 'MTSS': 10, 'LKOH': 1, 'GAZP': 10,
    'MOEX': 10, 'NSVZ': 10,
}

# Шаг цены для MOEX (рубли)
MOEX_PRICE_STEPS: dict[str, float] = {
    'ASTR': 0.01, 'SBER': 0.01, 'VTBR': 0.0001, 'ROSN': 0.01,
    'NVTK': 1.0, 'PHOR': 1.0, 'SNGSP': 0.01, 'PLZL': 1.0,
    'X5': 1.0, 'MTSS': 0.01, 'LKOH': 1.0, 'GAZP': 0.01,
    'MOEX': 0.01, 'NSVZ': 0.01,
}


def calculate_atr(df: pd.DataFrame, period: int = 14) -> pd.Series:
    """Расчёт ATR (Average True Range)."""
    high, low, close = df['High'].astype(float), df['Low'].astype(float), df['Close'].astype(float)
    prev_close = close.shift(1)
    tr = pd.concat([
        (high - low).abs(),
        (high - prev_close).abs(),
        (low - prev_close).abs(),
    ], axis=1).max(axis=1)
    return tr.rolling(window=period).mean()


def round_to_step(price: float, step: float) -> float:
    """Округление до шага цены."""
    return round(price / step) * step


def plan_trade(
    ticker: str,
    direction: str,  # 'BUY' or 'SELL'
    confidence: float,
    capital: float = 100_000.0,  # бюджет в рублях
    risk_percent: float = 1.0,  # риск на сделку, % от капитала
    limit: int = 500,
) -> dict:
    """
    Полный расчёт параметров сделки.

    Args:
        ticker: тикер (напр. 'SNGSP')
        direction: 'BUY' или 'SELL'
        confidence: уверенность сигнала (0..1)
        capital: бюджет в рублях
        risk_percent: риск на сделку, % от капитала
        limit: сколько свечей загрузить для ATR

    Returns:
        dict с полным планом
    """
    # Загружаем данные
    df = load_dataframe(ticker, 'H1', limit=limit)
    if df is None or len(df) < 20:
        return {'error': f'Недостаточно данных для {ticker}'}

    for col in ['Open', 'High', 'Low', 'Close']:
        df[col] = pd.to_numeric(df[col], errors='coerce')
    df['Volume'] = pd.to_numeric(df['Volume'], errors='coerce')

    last = df.iloc[-1]
    current_price = float(last['Close'])

    # ATR
    atr_series = calculate_atr(df)
    atr = float(atr_series.iloc[-1])

    if np.isnan(atr) or atr <= 0:
        return {'error': f'ATR = {atr}, невозможно рассчитать'}

    # Параметры (per-market SL/TP)
    _tcfg = get_target_config(ticker)
    atr_mult_sl = _tcfg.get('atr_mult_sl', 1.5)
    atr_mult_tp = _tcfg.get('atr_mult_tp', 3.0)

    lot_size = MOEX_LOT_SIZES.get(ticker, 1)
    step = MOEX_PRICE_STEPS.get(ticker, 0.01)

    # Entry, SL, TP
    if direction == 'BUY':
        entry = current_price
        sl = entry - atr * atr_mult_sl
        tp = entry + atr * atr_mult_tp
    else:  # SELL
        entry = current_price
        sl = entry + atr * atr_mult_sl
        tp = entry - atr * atr_mult_tp

    entry = round_to_step(entry, step)
    sl = round_to_step(sl, step)
    tp = round_to_step(tp, step)

    # RR (Risk/Reward)
    if direction == 'BUY':
        risk_rub = entry - sl
        reward_rub = tp - entry
    else:
        risk_rub = sl - entry
        reward_rub = entry - tp

    rr_ratio = round(reward_rub / risk_rub, 2) if risk_rub > 0 else 0

    # Размер позиции
    max_risk_rub = capital * risk_percent / 100
    shares_raw = max_risk_rub / risk_rub if risk_rub > 0 else 0
    lots = max(int(shares_raw / lot_size), 1)

    # Капитальное ограничение: позиция не может превышать бюджет
    while lots > 0:
        test_shares = lots * lot_size
        test_cost = test_shares * entry
        if test_cost <= capital:
            break
        lots -= 1

    shares = lots * lot_size if lots > 0 else lot_size
    lots = max(lots, 1)
    shares = lots * lot_size
    position_cost = shares * entry
    actual_risk = shares * risk_rub

    risk_pct_of_capital = actual_risk / capital * 100 if capital > 0 else 0

    # Лесенка (3 уровня)
    if direction == 'BUY':
        tp1 = round_to_step(entry + atr * atr_mult_tp * 0.5, step)
        tp2 = round_to_step(entry + atr * atr_mult_tp * 1.0, step)
        tp3 = round_to_step(entry + atr * atr_mult_tp * 1.5, step)
    else:
        tp1 = round_to_step(entry - atr * atr_mult_tp * 0.5, step)
        tp2 = round_to_step(entry - atr * atr_mult_tp * 1.0, step)
        tp3 = round_to_step(entry - atr * atr_mult_tp * 1.5, step)

    ladder = [
        {'level': 1, 'price': float(tp1), 'size_pct': 30, 'cumulative_pct': 30,
         'rr': round(reward_rub * 0.5 / risk_rub, 2) if risk_rub > 0 else 0},
        {'level': 2, 'price': float(tp2), 'size_pct': 30, 'cumulative_pct': 60,
         'rr': round(reward_rub * 1.0 / risk_rub, 2) if risk_rub > 0 else 0},
        {'level': 3, 'price': float(tp3), 'size_pct': 40, 'cumulative_pct': 100,
         'rr': round(reward_rub * 1.5 / risk_rub, 2) if risk_rub > 0 else 0},
    ]

    return {
        'ticker': ticker,
        'direction': direction,
        'confidence': round(confidence, 3),
        'current_price': float(current_price),
        'atr': round(atr, 4),
        'atr_pct': round(atr / current_price * 100, 2),

        'entry': float(entry),
        'stop_loss': float(sl),
        'take_profit': float(tp),
        'sl_pct': round(risk_rub / entry * 100, 2),
        'tp_pct': round(reward_rub / entry * 100, 2),
        'rr_ratio': rr_ratio,

        'position': {
            'capital': capital,
            'risk_percent': risk_percent,
            'max_risk_rub': round(max_risk_rub, 2),
            'lot_size': lot_size,
            'lots': lots,
            'shares': shares,
            'position_cost': round(position_cost, 2),
            'actual_risk': round(actual_risk, 2),
            'risk_pct_of_capital': round(risk_pct_of_capital, 2),
        },

        'ladder': ladder,

        'data_timestamp': int(last['timestamp']),
        'data_date': str(last.get('Date', '')),
        'data_time': str(last.get('Time', '')),
    }
