"""第2段階（適性・展開・ローテ・騎手）加点減点ロジック。

騎手はレース日より前の JRA 通算で 3着内率・勝率を用い、サンプル数に応じた多段階補正（合計±5.5クリップ）を行う。
"""
from __future__ import annotations

from datetime import date

from ai.course_knowledge import compute_course_knowledge_bonus


def _parse_passing_order(passing_order: str | None) -> list[int]:
    if not passing_order:
        return []
    out: list[int] = []
    for token in passing_order.split("-"):
        token = token.strip()
        if token.isdigit():
            out.append(int(token))
    return out


def _safe_rate(n: int, d: int) -> float:
    if d <= 0:
        return 0.0
    return float(n) / float(d)


def infer_running_style(history_rows: list[dict]) -> str:
    first_positions: list[int] = []
    for row in history_rows[:5]:
        pos_list = _parse_passing_order(row.get("passing_order"))
        if pos_list:
            first_positions.append(pos_list[0])
    if not first_positions:
        return "unknown"
    avg_first = sum(first_positions) / len(first_positions)
    if avg_first <= 3.0:
        return "front"
    if avg_first <= 7.0:
        return "stalker"
    return "closer"


def _days_since_last(race_date: date | None, history_rows: list[dict]) -> int | None:
    if not race_date or not history_rows:
        return None
    last_date = history_rows[0].get("race_date")
    if not isinstance(last_date, date):
        return None
    return (race_date - last_date).days


def _surface_distance_rates(history_rows: list[dict], race_surface: str | None, race_distance: int | None) -> dict:
    s_runs = 0
    s_top3 = 0
    d_runs = 0
    d_top3 = 0
    for row in history_rows:
        pos = int(row.get("finish_position") or 99)
        if pos <= 0:
            continue
        if race_surface and row.get("surface") == race_surface:
            s_runs += 1
            if pos <= 3:
                s_top3 += 1
        dist = row.get("distance_m")
        if race_distance and dist is not None and abs(int(dist) - int(race_distance)) <= 200:
            d_runs += 1
            if pos <= 3:
                d_top3 += 1
    return {
        "surface_runs": s_runs,
        "surface_top3_rate": _safe_rate(s_top3, s_runs),
        "distance_runs": d_runs,
        "distance_top3_rate": _safe_rate(d_top3, d_runs),
    }


def build_race_context(horse_rows: list[dict]) -> dict:
    front_count = 0
    closer_count = 0
    for row in horse_rows:
        style = row.get("running_style", "unknown")
        if style == "front":
            front_count += 1
        elif style == "closer":
            closer_count += 1
    if front_count >= 4:
        pace = "fast"
    elif front_count <= 1:
        pace = "slow"
    else:
        pace = "mid"
    return {
        "front_count": front_count,
        "closer_count": closer_count,
        "pace_scenario": pace,
    }


def compute_stage2_adjustment(
    history_rows: list[dict],
    race_date: date | None,
    race_surface: str | None,
    race_distance: int | None,
    running_style: str,
    race_context: dict,
    jockey_top3_rate: float | None,
    jockey_samples: int,
    track_code: str | None = None,
    *,
    jockey_win_rate: float | None = None,
) -> dict:
    bonus = 0.0
    reasons: list[str] = []

    rates = _surface_distance_rates(history_rows, race_surface, race_distance)
    if rates["surface_runs"] >= 2:
        if rates["surface_top3_rate"] >= 0.5:
            bonus += 3.0
            reasons.append("surface_fit_plus")
        elif rates["surface_runs"] >= 3 and rates["surface_top3_rate"] < 0.2:
            bonus -= 2.5
            reasons.append("surface_fit_minus")

    if rates["distance_runs"] >= 2:
        if rates["distance_top3_rate"] >= 0.5:
            bonus += 2.5
            reasons.append("distance_fit_plus")
        elif rates["distance_runs"] >= 3 and rates["distance_top3_rate"] < 0.2:
            bonus -= 2.0
            reasons.append("distance_fit_minus")

    pace = race_context.get("pace_scenario", "mid")
    if pace == "fast":
        if running_style == "closer":
            bonus += 2.5
            reasons.append("pace_match_closer")
        elif running_style == "front":
            bonus -= 2.0
            reasons.append("pace_risk_front")
    elif pace == "slow":
        if running_style == "front":
            bonus += 2.0
            reasons.append("pace_match_front")
        elif running_style == "closer":
            bonus -= 1.5
            reasons.append("pace_risk_closer")

    days = _days_since_last(race_date, history_rows)
    if days is not None:
        if days >= 180:
            bonus -= 3.0
            reasons.append("layoff_long_minus")
        elif 35 <= days <= 120:
            bonus += 1.0
            reasons.append("rotation_mid_plus")
        elif days <= 10:
            bonus -= 1.0
            reasons.append("rotation_tight_minus")

    # 騎手: 当該レース日より前の JRA 通算（出走ごと）から 3着内率・勝率を参照。
    # サンプル少のノイズを抑えつつ、従来より効かせるため多段階＋合計クリップ。
    jockey_sub = 0.0
    min_jockey_runs = 18
    if jockey_samples >= min_jockey_runs:
        if jockey_top3_rate is not None:
            if jockey_top3_rate >= 0.38:
                jockey_sub += 4.0
                reasons.append("jockey_form_plus")
            elif jockey_top3_rate >= 0.32:
                jockey_sub += 2.5
                reasons.append("jockey_form_plus_mid")
            elif jockey_top3_rate >= 0.27:
                jockey_sub += 1.25
                reasons.append("jockey_form_plus_light")
            elif jockey_top3_rate < 0.11:
                jockey_sub -= 4.0
                reasons.append("jockey_form_minus")
            elif jockey_top3_rate < 0.15:
                jockey_sub -= 2.5
                reasons.append("jockey_form_minus_mid")
            elif jockey_top3_rate < 0.19:
                jockey_sub -= 1.25
                reasons.append("jockey_form_minus_light")
        if jockey_win_rate is not None and jockey_samples >= 22:
            if jockey_win_rate >= 0.17:
                jockey_sub += 2.0
                reasons.append("jockey_win_plus")
            elif jockey_win_rate >= 0.12:
                jockey_sub += 1.0
                reasons.append("jockey_win_plus_light")
            elif jockey_win_rate < 0.035:
                jockey_sub -= 1.5
                reasons.append("jockey_win_minus")
            elif jockey_win_rate < 0.055:
                jockey_sub -= 0.75
                reasons.append("jockey_win_minus_light")
    jockey_sub = max(-6.0, min(6.0, jockey_sub))
    bonus += jockey_sub

    ck_bonus, ck_reasons = compute_course_knowledge_bonus(
        track_code=track_code,
        distance_m=race_distance,
        surface=race_surface,
        race_date=race_date,
        running_style=running_style,
        history_rows=history_rows,
    )
    bonus += ck_bonus
    reasons.extend(ck_reasons)

    return {
        "bonus": round(max(-13.0, min(13.0, bonus)), 2),
        "reasons": reasons,
        "pace_scenario": pace,
        "running_style": running_style,
        "surface_top3_rate": round(rates["surface_top3_rate"], 4),
        "distance_top3_rate": round(rates["distance_top3_rate"], 4),
    }
