from __future__ import annotations

from dataclasses import dataclass, field
from sqlite3 import Connection

from jarvis_finance.audit.log import record_audit_event
from jarvis_finance.imports.common import utc_now
from jarvis_finance.quality.alerts import create_alert

HEDGE_STATUSES = {"hedged", "unhedged", "unknown"}
INSTRUMENT_STATUSES = {"active", "delisted", "suspended", "merged", "inactive", "unknown", "suspected_inactive"}
VALUATION_POLICIES = {"live_price", "last_known_price", "manual_value", "exclude_from_auto_price_update"}
CORPORATE_ACTION_STATUSES = {"none_known", "suspected", "confirmed", "adjusted", "ignored", "unknown", "not_checked"}


@dataclass
class InstrumentMetadataResult:
    instrument_id: str
    quality_flags: list[str] = field(default_factory=list)


def _instrument(conn: Connection, instrument_id: str):
    row = conn.execute("SELECT * FROM instruments WHERE instrument_id=?", (instrument_id,)).fetchone()
    if row is None:
        raise ValueError(f"instrument not found: {instrument_id}")
    return row


def resolve_instrument_alerts(conn: Connection, *, instrument_id: str, rule_ids: list[str]) -> int:
    now = utc_now()
    if not rule_ids:
        return 0
    rows = conn.execute(
        "SELECT alert_id FROM alerts WHERE status='active' AND entity_type='instrument' AND entity_id=? AND rule_id IN (" + ",".join("?" for _ in rule_ids) + ")",
        (instrument_id, *rule_ids),
    ).fetchall()
    for row in rows:
        conn.execute("UPDATE alerts SET status='resolved', resolved_at=?, last_seen_at=? WHERE alert_id=?", (now, now, row["alert_id"]))
    return len(rows)


def ensure_instrument_metadata_quality(conn: Connection, *, instrument_id: str) -> InstrumentMetadataResult:
    inst = _instrument(conn, instrument_id)
    result = InstrumentMetadataResult(instrument_id=instrument_id)
    hedge_status = inst["hedge_status"] or "unknown"
    instrument_status = inst["instrument_status"] or "unknown"
    corporate_action_status = inst["corporate_action_status"] or "not_checked"
    if hedge_status == "unknown":
        result.quality_flags.append("hedge_status_unknown")
        create_alert(conn, priority="warnung", category="market_data", entity_type="instrument", entity_id=instrument_id, rule_id="hedge_status_unknown", message="Currency hedge status is unknown and must be reviewed before precise valuation attribution.", evidence={"isin": inst["isin"]}, fingerprint="hedge_status_unknown")
    else:
        resolve_instrument_alerts(conn, instrument_id=instrument_id, rule_ids=["hedge_status_unknown"])
    if instrument_status == "unknown":
        result.quality_flags.append("instrument_status_unknown")
        create_alert(conn, priority="warnung", category="market_data", entity_type="instrument", entity_id=instrument_id, rule_id="instrument_status_unknown", message="Instrument status is unknown and must be reviewed before automatic valuation confidence.", evidence={"isin": inst["isin"]}, fingerprint="instrument_status_unknown")
    elif instrument_status in {"delisted", "suspended", "merged", "inactive"}:
        result.quality_flags.append("delisted_or_suspended")
        create_alert(conn, priority="warnung", category="market_data", entity_type="instrument", entity_id=instrument_id, rule_id="delisted_or_suspended", message="Instrument is not active; automatic price update must be excluded or manually valued.", evidence={"status": instrument_status}, fingerprint=f"delisted_or_suspended:{instrument_status}")
    if corporate_action_status in {"unknown", "not_checked"}:
        # Visible status, not necessarily blocking; alert only when explicit review flag is set.
        if inst["split_or_corporate_action_review_required"]:
            result.quality_flags.append("split_or_corporate_action_review_required")
            create_alert(conn, priority="warnung", category="market_data", entity_type="instrument", entity_id=instrument_id, rule_id="split_or_corporate_action_review_required", message="Corporate action review is required before high-confidence valuation.", evidence={"corporate_action_status": corporate_action_status}, fingerprint="split_or_corporate_action_review_required")
    conn.commit()
    return result


def update_instrument_metadata(
    conn: Connection,
    *,
    instrument_id: str,
    hedge_status: str | None = None,
    is_currency_hedged: bool | None = None,
    hedged_to_currency: str | None = None,
    instrument_status: str | None = None,
    valuation_policy: str | None = None,
    base_exposure_currency: str | None = None,
    trading_currency: str | None = None,
    corporate_action_status: str | None = None,
    split_or_corporate_action_review_required: bool | None = None,
    note: str,
    created_by: str = "system",
) -> None:
    if not note.strip():
        raise ValueError("instrument metadata update requires a note")
    old = dict(_instrument(conn, instrument_id))
    values: dict[str, object] = {}
    if hedge_status is not None:
        if hedge_status not in HEDGE_STATUSES:
            raise ValueError("invalid hedge_status")
        values["hedge_status"] = hedge_status
        values["is_currency_hedged"] = 1 if hedge_status == "hedged" else 0
    if is_currency_hedged is not None:
        values["is_currency_hedged"] = 1 if is_currency_hedged else 0
    if hedged_to_currency is not None:
        values["hedged_to_currency"] = hedged_to_currency.upper() if hedged_to_currency else None
    if instrument_status is not None:
        if instrument_status not in INSTRUMENT_STATUSES:
            raise ValueError("invalid instrument_status")
        values["instrument_status"] = instrument_status
    if valuation_policy is not None:
        if valuation_policy not in VALUATION_POLICIES:
            raise ValueError("invalid valuation_policy")
        values["valuation_policy"] = valuation_policy
    if base_exposure_currency is not None:
        values["base_exposure_currency"] = base_exposure_currency.upper() if base_exposure_currency else None
    if trading_currency is not None:
        values["trading_currency"] = trading_currency.upper() if trading_currency else None
    if corporate_action_status is not None:
        if corporate_action_status not in CORPORATE_ACTION_STATUSES:
            raise ValueError("invalid corporate_action_status")
        values["corporate_action_status"] = corporate_action_status
    if split_or_corporate_action_review_required is not None:
        values["split_or_corporate_action_review_required"] = 1 if split_or_corporate_action_review_required else 0
    if not values:
        return
    values["updated_at"] = utc_now()
    assignments = ", ".join(f"{k}=?" for k in values)
    conn.execute(f"UPDATE instruments SET {assignments} WHERE instrument_id=?", (*values.values(), instrument_id))
    if values.get("hedge_status") and values["hedge_status"] != "unknown":
        resolve_instrument_alerts(conn, instrument_id=instrument_id, rule_ids=["hedge_status_unknown"])
    if values.get("instrument_status") and values["instrument_status"] != "unknown":
        resolve_instrument_alerts(conn, instrument_id=instrument_id, rule_ids=["instrument_status_unknown"])
    if values.get("instrument_status") == "active":
        resolve_instrument_alerts(conn, instrument_id=instrument_id, rule_ids=["delisted_or_suspended"])
    if values.get("corporate_action_status") in {"none_known", "adjusted", "ignored"}:
        resolve_instrument_alerts(conn, instrument_id=instrument_id, rule_ids=["corporate_action_suspected", "split_or_corporate_action_review_required"])
    record_audit_event(
        conn,
        source="instrument_metadata",
        action="update_instrument_metadata",
        entity_type="instrument",
        entity_id=instrument_id,
        old_values={k: old.get(k) for k in values if k != "updated_at"},
        new_values={k: values[k] for k in values if k != "updated_at"},
        user_text_note=note,
        confirmed=True,
        created_by=created_by,
    )
    conn.commit()
