"""Database persistence for signal engine outputs.

Persists ``SignalOutput`` instances to the ``signal_engine_outputs`` table.
Persistence failures are logged and swallowed — they never block signal
emission to the trading queue.

Requirements: 15.1, 15.4
"""

from __future__ import annotations

import json
import logging

import asyncpg

from services.signal_engine.models import SignalOutput

logger = logging.getLogger(__name__)

# INSERT statement for the signal_engine_outputs table.
_INSERT_SQL = """
INSERT INTO signal_engine_outputs (
    id,
    ticker,
    evaluated_at,
    price,
    heuristic_verdict,
    heuristic_confidence,
    heuristic_s_total,
    probabilistic_verdict,
    probabilistic_p_up,
    probabilistic_entropy,
    probabilistic_ev_r,
    delta_agreement,
    delta_confidence_delta,
    delta_reasons,
    trade_plan,
    full_output,
    exit_signals,
    pipeline_mode,
    shadow_mode
) VALUES (
    $1, $2, $3, $4, $5, $6, $7, $8, $9, $10,
    $11, $12, $13, $14, $15, $16, $17, $18, $19
)
"""


async def persist_signal_output(
    pool: asyncpg.Pool,
    output: SignalOutput,
) -> None:
    """Persist a SignalOutput to the signal_engine_outputs table.

    Logs and continues on database errors (non-blocking).

    Requirements: 15.1, 15.4
    """
    try:
        trade_plan_json: str | None = None
        if output.trade_plan is not None:
            trade_plan_json = json.dumps(output.trade_plan.model_dump())

        exit_signals_json = json.dumps(
            [e.model_dump() for e in output.exit_signals]
        )

        delta_reasons_json = json.dumps(output.delta_reasons)

        full_output_json = output.model_dump_json()

        await pool.execute(
            _INSERT_SQL,
            output.output_id,                   # $1  id
            output.ticker,                      # $2  ticker
            output.timestamp,                   # $3  evaluated_at
            output.price,                       # $4  price
            output.heuristic_verdict,           # $5  heuristic_verdict
            output.heuristic_confidence,        # $6  heuristic_confidence
            output.heuristic_s_total,           # $7  heuristic_s_total
            output.probabilistic_verdict,       # $8  probabilistic_verdict
            output.probabilistic_p_up,          # $9  probabilistic_p_up
            output.probabilistic_entropy,       # $10 probabilistic_entropy
            output.probabilistic_ev_r,          # $11 probabilistic_ev_r
            output.delta_agreement,             # $12 delta_agreement
            output.delta_confidence_delta,      # $13 delta_confidence_delta
            delta_reasons_json,                 # $14 delta_reasons (JSONB)
            trade_plan_json,                    # $15 trade_plan (JSONB, nullable)
            full_output_json,                   # $16 full_output (JSONB)
            exit_signals_json,                  # $17 exit_signals (JSONB)
            output.pipeline_mode,               # $18 pipeline_mode
            output.shadow_mode,                 # $19 shadow_mode
        )

        logger.debug(
            "Persisted signal output %s for %s",
            output.output_id,
            output.ticker,
        )
    except Exception:
        logger.error(
            "Failed to persist signal output %s for %s — continuing",
            output.output_id,
            output.ticker,
            exc_info=True,
        )
