"""ERP, fraud, and FX detection workflow.

Reuses:
    - ``databridge.erp_detect`` (ERP anomaly detection)
    - ``databridge.fraud_detect`` (fraud pattern detection)
    - ``databridge.fx_validate`` (FX rate validation)

IKE integration (optional):
    - P4 Scoring: Calibrate detection confidence via Thompson + SPRT + Platt
"""

from __future__ import annotations

from typing import Any, Dict, List, Optional

from databridge_core.sdk.core.context import SDKContext
from databridge_core.sdk.core.exceptions import NotImplementedStubError
from databridge_core.sdk.core.types import CompiledArtifact, Result
from databridge_core.sdk.workflows.base import BaseWorkflow
from databridge_core.sdk.workflows.result import WorkflowResult
from databridge_core.sdk.workflows.step import workflow_step


class ERPDetectionWorkflow(BaseWorkflow):
    """Run specialized ERP, fraud, and FX detection on a data file.

    Supports batch and single-file modes for ERP anomaly detection,
    fraud pattern detection, and FX rate validation.

    When IKE is available, detection results are scored through
    IKE's P4 engine for calibrated confidence.

    Reuses:
        - ``databridge.erp_detect.detect_erp_anomalies()``
        - ``databridge.fraud_detect.detect_fraud_patterns()``
        - ``databridge.fx_validate.validate_fx_rates()``
    """

    name = "detection.erp_detection"
    category = "detection"
    description = "ERP anomaly, fraud pattern, and FX rate detection"
    required_params = ["file_path"]
    optional_params = {
        "detection_types": ["erp", "fraud", "fx"],
        "batch_mode": False,
        "ike_scoring": True,
    }

    def validate(self, params: Dict[str, Any]) -> Dict[str, Any]:
        self._check_required(params)
        return self._apply_defaults(params)

    def execute(
        self, params: Dict[str, Any], ctx: Optional[SDKContext] = None
    ) -> Result:
        steps = []
        types = params.get("detection_types", ["erp", "fraud", "fx"])
        if "erp" in types:
            steps.append(self._erp_detect(params, ctx))
        if "fraud" in types:
            steps.append(self._fraud_detect(params, ctx))
        if "fx" in types:
            steps.append(self._fx_validate(params, ctx))
        # IKE P4: Score all detection results if IKE is available
        if params.get("ike_scoring") and ctx and ctx.ike.available:
            steps.append(self._ike_score_results(params, ctx))
        # Graph integration
        if ctx and ctx.graphs.available:
            steps.append(self._graph_record_lineage(params, ctx))
            steps.append(self._graph_record_evidence(params, ctx))
            steps.append(self._graph_index_vectors(params, ctx))
            steps.append(self._graph_ingest_kb(params, ctx))
            steps.append(self._graph_notify_codex(params, ctx))
        return WorkflowResult.from_steps(self.name, steps)

    def compile_to_snowflake(
        self, params: Dict[str, Any], ctx: Optional[SDKContext] = None
    ) -> List[CompiledArtifact]:
        raise NotImplementedStubError(
            self.name,
            "compile_to_snowflake",
            "Generate Snowflake Tasks calling SPCS detection endpoints",
        )

    @workflow_step("erp_detect", "Run ERP anomaly detection")
    def _erp_detect(self, params: Dict[str, Any], ctx: Optional[SDKContext] = None):
        # REUSE: databridge.erp_detect.detect_erp_anomalies(file_path)
        #   or   databridge.erp_detect.detect_erp_batch(directory) if batch_mode
        raise NotImplementedStubError(
            self.name,
            "erp_detect",
            "databridge.erp_detect.detect_erp_anomalies(file_path)",
        )

    @workflow_step("fraud_detect", "Run fraud pattern detection")
    def _fraud_detect(self, params: Dict[str, Any], ctx: Optional[SDKContext] = None):
        # REUSE: databridge.fraud_detect.detect_fraud_patterns(file_path)
        raise NotImplementedStubError(
            self.name,
            "fraud_detect",
            "databridge.fraud_detect.detect_fraud_patterns(file_path)",
        )

    @workflow_step("fx_validate", "Run FX rate validation")
    def _fx_validate(self, params: Dict[str, Any], ctx: Optional[SDKContext] = None):
        # REUSE: databridge.fx_validate.validate_fx_rates(file_path)
        raise NotImplementedStubError(
            self.name,
            "fx_validate",
            "databridge.fx_validate.validate_fx_rates(file_path)",
        )

    @workflow_step("ike_score_results", "Calibrate detection scores via IKE P4")
    def _ike_score_results(self, params: Dict[str, Any], ctx: Optional[SDKContext] = None):
        # IKE P4: Batch-score all detection results (ERP + fraud + FX)
        # through Thompson Sampling + SPRT + Platt calibration.
        #
        # Collect findings from prior steps, then:
        #   ctx.ike.batch_score([
        #       {"bandit_id": f"{det_type}_{rule_id}",
        #        "item_id": finding_id,
        #        "raw_confidence": confidence}
        #       for finding in all_findings
        #   ])
        raise NotImplementedStubError(
            self.name,
            "ike_score_results",
            "ctx.ike.batch_score(findings) — IKE P4 calibrated scoring",
        )

    # --- Graph integration ---

    @workflow_step("graph_record_lineage", "Record Finding→RULE edges in lineage")
    def _graph_record_lineage(self, params: Dict[str, Any], ctx: Optional[SDKContext] = None):
        # For each ERP/fraud/FX finding:
        #   ctx.graphs.record_lineage_node("sdk", finding_id, "EXTERNAL")
        #   ctx.graphs.record_lineage_edge("sdk", finding_id, rule_id, "DERIVED")
        raise NotImplementedStubError(
            self.name,
            "graph_record_lineage",
            "ctx.graphs.record_lineage_node/edge — Finding→RULE edges",
        )

    @workflow_step("graph_record_evidence", "Record detection evidence in evidence trail")
    def _graph_record_evidence(self, params: Dict[str, Any], ctx: Optional[SDKContext] = None):
        # ctx.graphs.record_evidence(
        #     account_id=finding["account"], hierarchy_node_id=finding["rule_id"],
        #     method="erp_detection", confidence=finding["confidence"],
        #     evidence_sources=[{"content": finding["description"], ...}],
        # )
        raise NotImplementedStubError(
            self.name,
            "graph_record_evidence",
            "ctx.graphs.record_evidence(account_id, rule_id, 'erp_detection', confidence, ...)",
        )

    @workflow_step("graph_index_vectors", "Index detection findings in vector store")
    def _graph_index_vectors(self, params: Dict[str, Any], ctx: Optional[SDKContext] = None):
        # ctx.graphs.index_content(
        #     doc_id=f"erp_{finding_id}", content=finding_summary,
        #     source_type="detection_finding", metadata={"detection_type": ...},
        # )
        raise NotImplementedStubError(
            self.name,
            "graph_index_vectors",
            "ctx.graphs.index_content(doc_id, content, 'detection_finding', metadata)",
        )

    @workflow_step("graph_ingest_kb", "Ingest detection findings into KB graph")
    def _graph_ingest_kb(self, params: Dict[str, Any], ctx: Optional[SDKContext] = None):
        # ctx.graphs.ingest_kb_nodes(
        #     nodes=[{"id": finding_id, "type": "RULE", "properties": {...}}],
        # )
        raise NotImplementedStubError(
            self.name,
            "graph_ingest_kb",
            "ctx.graphs.ingest_kb_nodes(nodes) — ERP/fraud/FX findings as KB nodes",
        )

    @workflow_step("graph_notify_codex", "Ingest discrepancy events into Codex GraphRAG")
    def _graph_notify_codex(self, params: Dict[str, Any], ctx: Optional[SDKContext] = None):
        # ctx.graphs.notify_runtime_event({
        #     "event_key": f"erp_{finding_id}",
        #     "source_system": "erp_detection",
        #     "finding_id": finding_id,
        #     "account": finding["account"],
        # })
        raise NotImplementedStubError(
            self.name,
            "graph_notify_codex",
            "ctx.graphs.notify_runtime_event(event) — Codex runtime discrepancy ingestion",
        )
