"""第1.5段階（ラップ/調整過程の変化検知）補正ロジック。"""
from __future__ import annotations

from datetime import date


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


def _days_between(d1: date | None, d2: date | None) -> int | None:
    if not d1 or not d2:
        return None
    return abs((d1 - d2).days)


def compute_stage1_5_adjustment(history_rows: list[dict]) -> dict:
    """
    直近履歴（新しい順）から第1.5段階の補正値を返す。
    補正は過大評価を避けるため最大12点。
    """
    if not history_rows:
        return {"bonus": 0.0, "reasons": []}

    bonus = 0.0
    reasons: list[str] = []

    recent = history_rows[0]
    prev = history_rows[1] if len(history_rows) >= 2 else None

    # 1) ラップ改善（直近の上がり3F改善）
    if prev:
        recent_l3f = recent.get("last_3f_time")
        prev_l3f = prev.get("last_3f_time")
        if recent_l3f is not None and prev_l3f is not None:
            diff = float(prev_l3f) - float(recent_l3f)
            if diff >= 0.3:
                bonus += 4.0
                reasons.append("lap_improved")

    # 2) 休養明け2走目/立て直しの兆候
    if prev:
        days_gap = _days_between(recent.get("race_date"), prev.get("race_date"))
        recent_pos = int(recent.get("finish_position") or 99)
        if days_gap is not None and days_gap >= 120 and recent_pos <= 5:
            bonus += 5.0
            reasons.append("long_layoff_rebound")

    # 3) 着順の急回復（基礎能力の再評価）
    if prev:
        recent_pos = int(recent.get("finish_position") or 99)
        prev_pos = int(prev.get("finish_position") or 99)
        if prev_pos >= 8 and recent_pos <= 3:
            bonus += 4.0
            reasons.append("finish_sharp_recovery")

    # 4) 馬自身のラップ/位置取り改善（追い上げ型）
    passing = _parse_passing_order(recent.get("passing_order"))
    if passing:
        first_pos = passing[0]
        last_pos = passing[-1]
        gained = max(0, first_pos - last_pos)
        recent_pos = int(recent.get("finish_position") or 99)
        if gained >= 4 and recent_pos <= 5:
            bonus += 3.0
            reasons.append("closing_gain")

    return {"bonus": round(min(12.0, bonus), 2), "reasons": reasons}
