"""
general_analysis 공통 유틸 (슬라이스·피벗·컬럼 접두사).
"""

from __future__ import annotations

from typing import Any

import numpy as np
import pandas as pd

from deepcoin.analysis.general_analysis_config import GA_COL_PREFIX, LOOKBACK_BARS


def ga_col(name: str) -> str:
    """general_analysis 출력 컬럼명."""
    return f"{GA_COL_PREFIX}{name}"


def interval_tf_prefix(interval: int) -> str:
    """간격 접두사 (m3, d1)."""
    from deepcoin.analysis.general_analysis_config import INTERVAL_PREFIX

    return INTERVAL_PREFIX.get(interval, f"m{interval}")


def prefixed_snapshot(
    row: pd.Series,
    interval: int,
    keys: list[str] | tuple[str, ...],
) -> dict[str, Any]:
    """한 봉의 ga_ 컬럼을 {m3_ga_rsi: ...} 형태로 변환."""
    p = interval_tf_prefix(interval)
    out: dict[str, Any] = {}
    for k in keys:
        col = ga_col(k)
        if col in row.index:
            v = row[col]
            out[f"{p}_{col}"] = None if pd.isna(v) else v
    return out


def slice_to_timestamp(df: pd.DataFrame, ts: pd.Timestamp) -> pd.DataFrame:
    """타점 시각 이전 완성봉만 (해당 시각 봉 미포함)."""
    if df.empty:
        return df
    if not isinstance(df.index, pd.DatetimeIndex):
        df = df.copy()
        df.index = pd.to_datetime(df.index)
    ts = pd.Timestamp(ts)
    if ts.tzinfo is not None and df.index.tz is None:
        ts = ts.tz_localize(None)
    return df[df.index < ts].copy()


def lookback_slice(df: pd.DataFrame, interval: int, end_ts: pd.Timestamp) -> pd.DataFrame:
    """타점 직전 lookback 구간."""
    sliced = slice_to_timestamp(df, end_ts)
    n = LOOKBACK_BARS.get(interval, 80)
    if len(sliced) > n:
        return sliced.iloc[-n:].copy()
    return sliced


def find_pivots(
    highs: np.ndarray,
    lows: np.ndarray,
    order: int = 3,
) -> tuple[list[int], list[int]]:
    """국소 고점·저점 인덱스 (양쪽 order 봉보다 극값)."""
    peak_idx: list[int] = []
    trough_idx: list[int] = []
    n = len(highs)
    if n < order * 2 + 1:
        return peak_idx, trough_idx
    for i in range(order, n - order):
        if highs[i] >= highs[i - order : i + order + 1].max():
            peak_idx.append(i)
        if lows[i] <= lows[i - order : i + order + 1].min():
            trough_idx.append(i)
    return peak_idx, trough_idx


def last_row_dict(df: pd.DataFrame, cols: list[str]) -> dict[str, Any]:
    """마지막 봉의 지정 컬럼 dict."""
    if df.empty:
        return {ga_col(c): None for c in cols}
    row = df.iloc[-1]
    return {
        ga_col(c): (None if c not in row.index or pd.isna(row[c]) else row[c])
        for c in cols
    }
