# app/src/trading/market_analysis/quality.py

from __future__ import annotations

from collections.abc import Sequence

from src.integrations.exchange.models import Kline
from src.trading.market_analysis.models import TrendDirection


def candle_noise_score(
    candles: Sequence[Kline],
    *,
    candle_noise_window: int,
    min_clean_body_ratio: float,
) -> float | None:
    window = candles[-candle_noise_window:]

    if not window:
        return None

    clean_count = 0
    total_count = 0

    for candle in window:
        high = getattr(candle, "high_price", None)
        low = getattr(candle, "low_price", None)
        open_price = getattr(candle, "open_price", None)
        close_price = getattr(candle, "close_price", None)

        if (
            high is None
            or low is None
            or open_price is None
            or close_price is None
            or high <= low
        ):
            continue

        candle_range = high - low
        body = abs(close_price - open_price)
        body_ratio = body / candle_range

        total_count += 1

        if body_ratio >= min_clean_body_ratio:
            clean_count += 1

    if total_count == 0:
        return None

    return clean_count / total_count


def price_position_score(
    *,
    closes: list[float],
    ema_fast: float,
    trend: TrendDirection,
    price_position_window: int,
) -> float | None:
    window = closes[-price_position_window:]

    if not window:
        return None

    valid_count = 0

    for close_price in window:
        if trend == TrendDirection.UP:
            if close_price > ema_fast:
                valid_count += 1

        elif trend == TrendDirection.DOWN:
            if close_price < ema_fast:
                valid_count += 1

        else:
            return None

    return valid_count / len(window)