# Copyright (c) 2026 PULSE Contributors. Proprietary. All rights reserved.
"""Reward propagation — extracted from reward_signal.py to keep that file under 300 lines.

Provides propagate_reward(): applies credit/blame to SQLite brain items.
"""
import logging
from datetime import datetime, timezone

log = logging.getLogger("pulse.reward_propagation")

REINFORCE_DELTA = 0.2
CONTRADICT_DELTA = 0.4


def propagate_reward(credits: dict) -> int:
    """Apply credit/blame to brain items. Positive=reinforce, Negative=contradict."""
    if not credits:
        return 0
    updated = 0
    try:
        from pulse.brain.plasticity.reconsolidation import reinforce, contradict, mark_labile
        from pulse.core.brain_db import get_conn

        conn = get_conn()
        now_iso = datetime.now(timezone.utc).isoformat()
        try:
            from pulse.core.reward.volatility import get_volatility_multiplier
            vol_mult = get_volatility_multiplier()
        except Exception:
            vol_mult = 1.0
        for item_id, credit in credits.items():
            try:
                row = conn.execute(
                    "SELECT table_name FROM knowledge_fts WHERE item_id = ? LIMIT 1",
                    (item_id,)
                ).fetchone()
                if not row:
                    continue
                table = row["table_name"]
            except Exception:
                continue

            magnitude = abs(credit) * vol_mult
            mark_labile(item_id, table, prediction_error=min(1.0, abs(credit) / 2.0))
            if credit > 0:
                sal_delta = round(REINFORCE_DELTA * min(magnitude * 2, 1.5), 3)
                # Item 128: Emotional regulation -- dampen extreme salience (P30)
                try:
                    _row_sal = conn.execute(
                        f"SELECT salience FROM {table} WHERE id=?", (item_id,)
                    ).fetchone()
                    if _row_sal:
                        _cur_sal = float(_row_sal[0] or 1.0)
                        _new_sal = _cur_sal + sal_delta
                        if _new_sal > 6.0:
                            # Diminishing returns above 6.0
                            _overflow = _new_sal - 6.0
                            _new_sal = 6.0 + _overflow * 0.5
                            sal_delta = round(_new_sal - _cur_sal, 3)
                            try:
                                from pulse.core.reward.reward_regulation import increment_regulation_count
                                increment_regulation_count()
                            except Exception: pass
                except Exception:
                    pass  # fail-open
                with conn:
                    conn.execute(f"""
                        UPDATE {table}
                        SET salience = MIN(salience + ?, 7.0),
                            last_accessed = ?, last_reinforced = ?,
                            access_count = access_count + 1
                        WHERE id = ?
                    """, (sal_delta, now_iso, now_iso, item_id))
                row = conn.execute(f"SELECT confidence FROM {table} WHERE id=?", (item_id,)).fetchone()
                if row and (row["confidence"] or 1.0) < 0.1:
                    conn.execute(f"UPDATE {table} SET confidence=0.3 WHERE id=?", (item_id,))
                updated += 1
                try:
                    from pulse.brain.integrity.grounding import maybe_promote
                    maybe_promote(item_id, table, trigger="reward",
                                  evidence={"credit": round(credit, 4), "sal_delta": sal_delta, "relevance": 0.5})
                except Exception:
                    pass
                try:
                    _dr = conn.execute(f"SELECT domain FROM {table} WHERE id=?", (item_id,)).fetchone()
                    if _dr and _dr["domain"]:
                        for _tt in ("lessons", "failures", "patterns"):
                            conn.execute(
                                f"UPDATE {_tt} SET confidence=MIN(confidence+0.15,1.0) "
                                f"WHERE domain=? AND confidence<0.4 AND confidence>0.05",
                                (_dr["domain"],)
                            )
                        conn.commit()
                except Exception:
                    pass
            elif credit < 0:
                conf_delta = round(CONTRADICT_DELTA * min(magnitude * 2, 1.5), 3)
                with conn:
                    conn.execute(f"""
                        UPDATE {table}
                        SET confidence = MAX(confidence - ?, 0.0),
                            validity = CASE WHEN confidence - ? <= 0.0 THEN 'contested' ELSE validity END
                        WHERE id = ?
                    """, (conf_delta, conf_delta, item_id))
                updated += 1
                log.debug("Contradicted %s (credit=%.3f, conf_delta=-%.3f)", item_id, credit, conf_delta)
    except ImportError:
        log.warning("Reconsolidation module not available for reward propagation")
    except Exception as e:
        log.warning("Reward propagation failed: %s", e)
    return updated
