"""Persist factory funnel + deployed allocation into the cockpit DB (mission-control)."""
from __future__ import annotations

import datetime as dt

from sqlalchemy import create_engine, desc, select
from sqlalchemy.orm import Session
from sqlalchemy.pool import StaticPool

from fxhnt.adapters.persistence.cockpit_models import CockpitBase, FactoryAllocationRow, FactoryCycleRow, FactoryFlagRow


class FactoryStore:
    def __init__(self, dsn: str) -> None:
        kw = {"future": True}
        if dsn == "sqlite://":
            kw |= {"connect_args": {"check_same_thread": False}, "poolclass": StaticPool}
        self._engine = create_engine(dsn, **kw)
        CockpitBase.metadata.create_all(self._engine)

    def record_cycle(self, *, cycle_id, proposed, tested, survived, forward, deployed, retired,
                     global_trials, at) -> None:
        with Session(self._engine) as s:
            s.merge(FactoryCycleRow(cycle_id=cycle_id, proposed=proposed, tested=tested, survived=survived,
                                    forward=forward, deployed=deployed, retired=retired,
                                    global_trials=global_trials, at=at))
            s.commit()

    def record_allocation(self, cycle_id: str, weights: dict[str, float], at: dt.datetime) -> None:
        with Session(self._engine) as s:
            for sid, w in weights.items():
                s.merge(FactoryAllocationRow(cycle_id=cycle_id, strategy_id=sid, weight=w, at=at))
            s.commit()

    def latest_cycle(self) -> FactoryCycleRow | None:
        with Session(self._engine) as s:
            return s.scalars(select(FactoryCycleRow).order_by(desc(FactoryCycleRow.at))).first()

    def allocation(self, cycle_id: str) -> list[FactoryAllocationRow]:
        with Session(self._engine) as s:
            return list(s.scalars(select(FactoryAllocationRow).where(FactoryAllocationRow.cycle_id == cycle_id)))

    def latest_weights(self) -> dict[str, float] | None:
        """Return the HRP weights from the most-recent recorded cycle, or None if no cycle has ever
        been recorded (distinguishes "no allocation" from "empty allocation")."""
        with Session(self._engine) as s:
            row = s.scalars(select(FactoryCycleRow).order_by(desc(FactoryCycleRow.at))).first()
            if row is None:
                return None
            stmt = select(FactoryAllocationRow).where(FactoryAllocationRow.cycle_id == row.cycle_id)
            alloc_rows = list(s.scalars(stmt))
        return {r.strategy_id: r.weight for r in alloc_rows} if alloc_rows else {}

    # Fix 6: persisted kill-switch
    def set_kill(self, on: bool) -> None:
        """Persist the kill flag (key="kill", value="1"/"0") so it survives pod restarts."""
        with Session(self._engine) as s:
            s.merge(FactoryFlagRow(key="kill", value="1" if on else "0"))
            s.commit()

    def is_killed(self) -> bool:
        """Return True if the persisted kill flag is set. Defaults to False when no row exists."""
        with Session(self._engine) as s:
            row = s.scalars(select(FactoryFlagRow).where(FactoryFlagRow.key == "kill")).first()
            return row is not None and row.value == "1"
