import pandas as pd
import numpy as np
from typing import Dict, List


def detect_levels(df: pd.DataFrame, lookback: int = 50) -> Dict[str, List[float]]:
    """
    Detect support and resistance levels using pivot points.

    Args:
        df: OHLCV DataFrame with at least `lookback` rows.
        lookback: Number of candles to analyze.

    Returns:
        dict with keys "support" and "resistance", each a sorted list of price levels.
    """
    data = df.tail(lookback).copy()
    highs = data["high"].values
    lows = data["low"].values

    support_levels: List[float] = []
    resistance_levels: List[float] = []

    # A pivot high: candle whose high is greater than its two neighbours on each side
    for i in range(2, len(highs) - 2):
        if highs[i] > highs[i - 1] and highs[i] > highs[i - 2] \
                and highs[i] > highs[i + 1] and highs[i] > highs[i + 2]:
            resistance_levels.append(round(highs[i], 6))

    # A pivot low: candle whose low is less than its two neighbours on each side
    for i in range(2, len(lows) - 2):
        if lows[i] < lows[i - 1] and lows[i] < lows[i - 2] \
                and lows[i] < lows[i + 1] and lows[i] < lows[i + 2]:
            support_levels.append(round(lows[i], 6))

    # Cluster nearby levels (within 0.5% of each other) to avoid duplicates
    def cluster(levels: List[float], tolerance: float = 0.005) -> List[float]:
        if not levels:
            return []
        sorted_lvls = sorted(levels)
        clustered = [sorted_lvls[0]]
        for lvl in sorted_lvls[1:]:
            if abs(lvl - clustered[-1]) / clustered[-1] > tolerance:
                clustered.append(lvl)
        return clustered

    return {
        "support": cluster(support_levels),
        "resistance": cluster(resistance_levels),
    }


def nearest_level(price: float, levels: List[float]) -> float:
    """Return the level closest to `price` from a list of levels."""
    if not levels:
        return price
    return min(levels, key=lambda lvl: abs(lvl - price))
