"""Pattern memory for closure fingerprints and lightweight runtime adaptation."""

from __future__ import annotations

import hashlib
import json
from typing import Any


def build_closure_fingerprint(state_before_close: dict[str, Any] | None) -> tuple[str, dict[str, Any]]:
    state = state_before_close if isinstance(state_before_close, dict) else {}
    fingerprint = {
        "strategy_id": str(
            state.get("position_entry_owner_strategy_id", state.get("position_strategy_id", "")) or ""
        ),
        "side": str(state.get("position_side", "") or "").upper(),
        "regime": str(state.get("position_regime", "UNKNOWN") or "UNKNOWN").upper(),
        "session": str(state.get("position_session", state.get("session_name", "UNKNOWN")) or "UNKNOWN").upper(),
        "entry_style": str(state.get("position_entry_style", "UNKNOWN") or "UNKNOWN").upper(),
        "agent_direction": str(state.get("position_agent_direction", "UNKNOWN") or "UNKNOWN").upper(),
    }
    raw = json.dumps(fingerprint, sort_keys=True, ensure_ascii=False)
    fingerprint_id = hashlib.sha256(raw.encode("utf-8")).hexdigest()[:16]
    return fingerprint_id, fingerprint


def classify_failure_success(
    state_before_close: dict[str, Any] | None,
    pnl: float,
    exit_price: float,
    close_action: str,
) -> tuple[str, str]:
    state = state_before_close if isinstance(state_before_close, dict) else {}
    entry_price = float(state.get("position_entry", 0.0) or 0.0)
    side = str(state.get("position_side", "") or "").upper()
    pnl_value = float(pnl or 0.0)
    if pnl_value > 0:
        if side == "BUY" and exit_price > entry_price:
            return "NONE", "TREND_CAPTURE"
        if side == "SELL" and entry_price > exit_price:
            return "NONE", "TREND_CAPTURE"
        return "NONE", "PROFITABLE_EXIT"
    if pnl_value < 0:
        if close_action == "TIME_STOP":
            return "TIME_STOP", "NONE"
        if close_action in {"STOP", "STOPLOSS", "SL"}:
            return "STOP_LOSS", "NONE"
        return "LOSS_EXIT", "NONE"
    return "BREAKEVEN", "BREAKEVEN"


def record_closure_pattern(
    state_before_close: dict[str, Any] | None,
    pnl: float,
    exit_price: float,
    close_action: str,
) -> dict[str, Any]:
    fingerprint_id, fingerprint = build_closure_fingerprint(state_before_close)
    failure_mode, success_mode = classify_failure_success(
        state_before_close,
        pnl,
        exit_price,
        close_action,
    )
    return {
        "fingerprint_id": fingerprint_id,
        "fingerprint": fingerprint,
        "failure_mode": failure_mode,
        "success_mode": success_mode,
        "pnl": round(float(pnl or 0.0), 2),
    }


def attach_runtime_adaptation(state: dict[str, Any] | None, pattern_payload: dict[str, Any] | None) -> None:
    if not isinstance(state, dict) or not isinstance(pattern_payload, dict):
        return
    memory = state.get("pattern_memory", {})
    if not isinstance(memory, dict):
        memory = {}
    fingerprint_id = str(pattern_payload.get("fingerprint_id", "") or "")
    if not fingerprint_id:
        return
    memory[fingerprint_id] = {
        "last_seen_at": pattern_payload.get("seen_at"),
        "failure_mode": pattern_payload.get("failure_mode", "NONE"),
        "success_mode": pattern_payload.get("success_mode", "NONE"),
        "pnl": pattern_payload.get("pnl", 0.0),
    }
    # Keep only the most recent 40 fingerprints to avoid uncontrolled state growth.
    if len(memory) > 40:
        for key in list(memory.keys())[:-40]:
            memory.pop(key, None)
    state["pattern_memory"] = memory
