from __future__ import annotations

import hashlib
import json
from pathlib import Path

import pandas as pd

from psx_signal.config import Settings
from psx_signal.models import ProbabilisticModel
from psx_signal.predictions import JsonlPredictionStore, PredictionRecord, probabilities_to_signals


def generate_eod_predictions(
    dataset: pd.DataFrame,
    settings: Settings,
    artifact_path: str | Path,
    as_of: str | None = None,
    symbols: list[str] | None = None,
    ledger_path: str | Path = "reports/predictions.jsonl",
) -> list[PredictionRecord]:
    metadata = json.loads(Path(f"{artifact_path}.json").read_text(encoding="utf-8"))
    model = ProbabilisticModel.load(artifact_path)
    date = pd.Timestamp(as_of) if as_of else dataset["date"].max()
    rows = dataset[dataset["date"] == date].copy()
    if symbols:
        rows = rows[rows["symbol"].isin([symbol.upper() for symbol in symbols])]
    if rows.empty:
        raise ValueError(f"No feature rows found for {date.date()}")
    columns = metadata["feature_columns"]
    missing = sorted(set(columns) - set(rows.columns))
    if missing:
        raise ValueError(f"Artifact requires missing features: {', '.join(missing)}")
    probabilities = model.predict_proba(rows[columns])
    signals = probabilities_to_signals(probabilities, settings.signals)
    horizon = int(metadata["horizon"])
    execution_column = f"execution_date_{horizon}d"
    records: list[PredictionRecord] = []
    for position, (_, row) in enumerate(rows.iterrows()):
        snapshot = hashlib.sha256(pd.util.hash_pandas_object(row[columns]).values.tobytes()).hexdigest()
        execution = row.get(execution_column)
        execution_date = None if pd.isna(execution) else str(pd.Timestamp(execution).date())
        sell, neutral, buy = probabilities[position]
        records.append(PredictionRecord.create(
            model_version=metadata["model_version"], feature_version=metadata["feature_version"],
            symbol=str(row["symbol"]), as_of_date=str(date.date()), execution_date=execution_date,
            prediction_horizon=horizon, buy_probability=float(buy), neutral_probability=float(neutral),
            sell_probability=float(sell), final_signal=signals[position], confidence=float(max(probabilities[position])),
            market_regime=None if pd.isna(row.get("market_regime")) else str(row.get("market_regime")),
            feature_snapshot=snapshot, signal_state="EOD_SIGNAL",
        ))
    JsonlPredictionStore(ledger_path).append(records)
    return records

