# src/web/api/v2/routers/calibration_risk.py

import logging

from fastapi import APIRouter, Depends, HTTPException
from fastapi.responses import FileResponse, JSONResponse
from pathlib import Path
import uuid
import re

from src.data.storage import StorageManager
from src.calibration.risk_inspector import (
    inspect_risk_config,
    StopConfig,
    RiskConfig,
    GlobalRiskRules,
)

from ..schemas.calibration_risk import (
    CalibrationRiskInspectRequest,
    CalibrationRiskInspectResponse,
    CalibrationRiskValidateResponse,
)

from src.calibration.reports.risk_report import generate_risk_report_pdf

logger = logging.getLogger("tradingbot.api.v2")

router = APIRouter(
    prefix="/calibration/risk",
    tags=["calibration"],
)

# =================================================
# Dependencies
# =================================================

def get_storage() -> StorageManager:
    return StorageManager.from_env()


# =================================================
# INSPECT (RISK & STOPS)
# =================================================

@router.post(
    "/inspect",
    response_model=CalibrationRiskInspectResponse,
)
def inspect_calibration_risk(
    payload: CalibrationRiskInspectRequest,
    storage: StorageManager = Depends(get_storage),
):
    logger.info(
        f"🛡️ Inspecting risk | {payload.symbol} {payload.timeframe}"
    )

    # --------------------------------------------------
    # Step 1 dependency check
    # --------------------------------------------------
    # Por ahora: recalculamos data_quality igual que Step 1
    # (más adelante se puede cachear si quieres)
    df = storage.load_ohlcv(
        symbol=payload.symbol,
        timeframe=payload.timeframe,
    )

    if df is None or df.empty:
        raise HTTPException(
            status_code=400,
            detail="No OHLCV data found. Run Step 1 first.",
        )

    # reutilizamos la misma función que en calibration_data
    from .calibration_data import analyze_data_quality

    data_quality = analyze_data_quality(df, payload.timeframe)

    # --------------------------------------------------
    # Map schemas -> domain models
    # --------------------------------------------------
    stop = StopConfig(
        type=payload.stop.type,
        stop_fraction=payload.stop.stop_fraction,
        atr_period=payload.stop.atr_period,
        atr_multiplier=payload.stop.atr_multiplier,
    )

    risk = RiskConfig(
        risk_fraction=payload.risk.risk_fraction,
        max_position_fraction=payload.risk.max_position_fraction,
    )

    rules = GlobalRiskRules(
        max_drawdown_pct=payload.global_rules.max_drawdown_pct,
        daily_loss_limit_pct=payload.global_rules.daily_loss_limit_pct,
        max_consecutive_losses=payload.global_rules.max_consecutive_losses,
        cooldown_bars=payload.global_rules.cooldown_bars,
    )

    # --------------------------------------------------
    # Domain inspection
    # --------------------------------------------------
    result = inspect_risk_config(
        storage=storage,
        symbol=payload.symbol,
        timeframe=payload.timeframe,
        stop=stop,
        risk=risk,
        rules=rules,
        account_equity=payload.account_equity,
        data_quality=data_quality,
    )

    logger.info(
        f"🧪 Risk inspect result | status={result['status']}"
    )

    return CalibrationRiskInspectResponse(**result)

# =================================================
# VALIDATE (RISK & STOPS — with series for plots)
# =================================================

@router.post(
    "/validate",
    response_model=CalibrationRiskValidateResponse,
)
def validate_calibration_risk(
    payload: CalibrationRiskInspectRequest,
    storage: StorageManager = Depends(get_storage),
):
    logger.info(
        f"📊 Validating risk (with series) | {payload.symbol} {payload.timeframe}"
    )

    df = storage.load_ohlcv(
        symbol=payload.symbol,
        timeframe=payload.timeframe,
    )

    if df is None or df.empty:
        raise HTTPException(
            status_code=400,
            detail="No OHLCV data found. Run Step 1 first.",
        )

    from .calibration_data import analyze_data_quality

    data_quality = analyze_data_quality(df, payload.timeframe)

    stop = StopConfig(
        type=payload.stop.type,
        stop_fraction=payload.stop.stop_fraction,
        atr_period=payload.stop.atr_period,
        atr_multiplier=payload.stop.atr_multiplier,
    )

    risk = RiskConfig(
        risk_fraction=payload.risk.risk_fraction,
        max_position_fraction=payload.risk.max_position_fraction,
    )

    rules = GlobalRiskRules(
        max_drawdown_pct=payload.global_rules.max_drawdown_pct,
        daily_loss_limit_pct=payload.global_rules.daily_loss_limit_pct,
        max_consecutive_losses=payload.global_rules.max_consecutive_losses,
        cooldown_bars=payload.global_rules.cooldown_bars,
    )

    result = inspect_risk_config(
        storage=storage,
        symbol=payload.symbol,
        timeframe=payload.timeframe,
        stop=stop,
        risk=risk,
        rules=rules,
        account_equity=payload.account_equity,
        data_quality=data_quality,
    )

    logger.info(
        f"📈 Risk validate result | status={result['status']}"
    )

    return CalibrationRiskValidateResponse(**result)

# =================================================
# REPORT (PDF)
# =================================================

@router.post("/report")
def generate_risk_report(
    payload: CalibrationRiskInspectRequest,
    storage: StorageManager = Depends(get_storage),
):
    logger.info(
        f"🧾 Generating risk report | {payload.symbol} {payload.timeframe}"
    )

    df = storage.load_ohlcv(
        symbol=payload.symbol,
        timeframe=payload.timeframe,
    )

    if df is None or df.empty:
        raise HTTPException(
            status_code=400,
            detail="No OHLCV data found. Run Step 1 first.",
        )

    from .calibration_data import analyze_data_quality

    data_quality = analyze_data_quality(df, payload.timeframe)

    stop = StopConfig(
        type=payload.stop.type,
        stop_fraction=payload.stop.stop_fraction,
        atr_period=payload.stop.atr_period,
        atr_multiplier=payload.stop.atr_multiplier,
    )

    risk = RiskConfig(
        risk_fraction=payload.risk.risk_fraction,
        max_position_fraction=payload.risk.max_position_fraction,
    )

    rules = GlobalRiskRules(
        max_drawdown_pct=payload.global_rules.max_drawdown_pct,
        daily_loss_limit_pct=payload.global_rules.daily_loss_limit_pct,
        max_consecutive_losses=payload.global_rules.max_consecutive_losses,
        cooldown_bars=payload.global_rules.cooldown_bars,
    )

    result = inspect_risk_config(
        storage=storage,
        symbol=payload.symbol,
        timeframe=payload.timeframe,
        stop=stop,
        risk=risk,
        rules=rules,
        account_equity=payload.account_equity,
        data_quality=data_quality,
    )

    # ---------------------------------------------
    # Prepare PDF data
    # ---------------------------------------------

    context = {
        "Symbol": payload.symbol,
        "Timeframe": payload.timeframe,
        "Account equity": payload.account_equity,
    }

    config = {
        "Stop type": payload.stop.type,
        "Risk per trade (%)": payload.risk.risk_fraction * 100,
        "Max position fraction (%)": payload.risk.max_position_fraction * 100,
        "Max drawdown (%)": payload.global_rules.max_drawdown_pct * 100,
    }

    results = result

    # ============================================================
    # BUILD SAFE OUTPUT PATH (OUTSIDE src/)
    # ============================================================

    # Project root (3 niveles arriba desde router)
    project_root = Path(__file__).resolve().parents[5]

    # Reports folder outside src
    reports_dir = project_root / "reports" / "risk"
    reports_dir.mkdir(parents=True, exist_ok=True)

    # Sanitize symbol for filesystem
    safe_symbol = re.sub(r"[^a-zA-Z0-9_-]", "_", payload.symbol)

    # Unique filename
    file_id = uuid.uuid4().hex

    filename = f"risk_report_{safe_symbol}_{payload.timeframe}_{file_id}.pdf"

    symbol_dir = reports_dir / safe_symbol
    symbol_dir.mkdir(exist_ok=True)

    output_path = symbol_dir / filename

    generate_risk_report_pdf(
        output_path=output_path,
        context=context,
        config=config,
        results=results,
    )

    # ---------------------------------------------
    # Create public URL
    # ---------------------------------------------

    public_url = f"/reports/risk/{safe_symbol}/{filename}"

    return JSONResponse(
        content={
            "status": "ok",
            "url": public_url,
        }
    )

    # return FileResponse(
    #     path=str(output_path),
    #     media_type="application/pdf",
    #     filename=output_path.name,
    #     headers={
    #         "Content-Disposition": f'inline; filename="{output_path.name}"'
    #     },
    # )
