"""S/R Levels router — support/resistance detection endpoints."""

from fastapi import APIRouter, Depends, Query
from sqlalchemy.ext.asyncio import AsyncSession

from app.dependencies import get_db, require_access
from app.schemas.common import APIEnvelope
from app.schemas.sr_level import (
    GateTargetLadderResponse,
    GateTargetLevelResult,
    SRLevelResponse,
    SRLevelResult,
    SRZoneResult,
)
from app.services.price_service import query_ohlcv
from app.services.sr_service import (
    cluster_sr_zones,
    detect_gate_target_ladder,
    get_sr_levels,
)

router = APIRouter(tags=["sr-levels"])


@router.get("/gate-target-ladder/{symbol}", response_model=APIEnvelope)
async def read_gate_target_ladder(
    symbol: str,
    _user=Depends(require_access),
    db: AsyncSession = Depends(get_db),
) -> APIEnvelope:
    """Return the transient, volume-free GTL for chart diagnostics.

    These proposals are not persisted ``SRLevel`` rows and must not be
    presented as structural support/resistance.
    """
    records = await query_ohlcv(db, symbol)
    if not records:
        data = GateTargetLadderResponse(
            symbol=symbol.upper(),
            levels=[],
            count=0,
            lookback_bars=0,
        )
        return APIEnvelope(status="success", data=data.model_dump())

    highs = [float(record.high) for record in records]
    lows = [float(record.low) for record in records]
    closes = [float(record.close) for record in records]
    detected = detect_gate_target_ladder(highs, lows, closes)
    levels = [
        GateTargetLevelResult(
            price_level=float(level["price_level"]),
            type=level["type"],
            strength=int(level["strength"]),
            detection_method=str(level.get("detection_method", "unknown")),
            sources=list(level.get("sources") or []),
            traffic_count=int(level.get("rejection_count", 0) or 0),
        )
        for level in sorted(detected, key=lambda row: float(row["price_level"]))
    ]
    data = GateTargetLadderResponse(
        symbol=symbol.upper(),
        levels=levels,
        count=len(levels),
        lookback_bars=len(records),
    )
    return APIEnvelope(status="success", data=data.model_dump())


@router.get("/sr-levels/{symbol}", response_model=APIEnvelope)
async def read_sr_levels(
    symbol: str,
    tolerance: float | None = Query(
        None,
        ge=0,
        le=0.1,
        description="Merge tolerance as fraction of price; omit for ATR-adaptive default",
    ),
    max_zones: int = Query(6, ge=0, description="Max S/R zones to return (default 6)"),
    _user=Depends(require_access),
    db: AsyncSession = Depends(get_db),
) -> APIEnvelope:
    """Get support/resistance levels for a symbol, sorted by strength descending."""
    levels = await get_sr_levels(db, symbol, tolerance)

    level_results = [
        SRLevelResult(
            id=lvl.id,
            price_level=lvl.price_level,
            type=lvl.type,
            strength=lvl.strength,
            detection_method=lvl.detection_method,
            created_at=lvl.created_at,
        )
        for lvl in levels
    ]

    # Compute S/R zones from the fetched levels
    zones: list[SRZoneResult] = []
    if levels and max_zones > 0:
        # Get current price from latest OHLCV close
        ohlcv_records = await query_ohlcv(db, symbol)
        if ohlcv_records:
            current_price = ohlcv_records[-1].close
            level_dicts = [
                {"price_level": lvl.price_level, "strength": lvl.strength}
                for lvl in levels
            ]
            raw_zones = cluster_sr_zones(
                level_dicts, current_price, tolerance=0.02, max_zones=max_zones
            )
            zones = [SRZoneResult(**z) for z in raw_zones]

    # Filter levels to only those within at least one zone's [low, high] range
    visible_levels: list[SRLevelResult] = []
    if zones:
        visible_levels = [
            lvl
            for lvl in level_results
            if any(z.low <= lvl.price_level <= z.high for z in zones)
        ]

    data = SRLevelResponse(
        symbol=symbol.upper(),
        levels=level_results,
        zones=zones,
        visible_levels=visible_levels,
        count=len(levels),
    )
    return APIEnvelope(status="success", data=data.model_dump())
