"""Tests for credit risk pipeline."""

from __future__ import annotations

from orxaq.orchestration.integration import OrxaqEngine
from orxaq.orchestration.pipeline import CreditPipeline, StepStatus


class TestPipelineBasic:
    def test_empty_pipeline(self) -> None:
        engine = OrxaqEngine()
        result = CreditPipeline(engine).run()
        assert result.success is True
        assert result.steps == []
        assert result.total_duration_ms >= 0

    def test_single_step_ontology(self) -> None:
        engine = OrxaqEngine()
        result = CreditPipeline(engine).load_ontology().run()
        assert result.success is True
        assert len(result.steps) == 1
        assert result.steps[0].name == "load_ontology"
        assert result.steps[0].status == StepStatus.COMPLETED

    def test_step_output_has_data(self) -> None:
        engine = OrxaqEngine()
        result = CreditPipeline(engine).load_ontology().run()
        output = result.steps[0].output
        assert isinstance(output, dict)
        assert "nodes" in output
        assert "edges" in output

    def test_data_generation(self) -> None:
        engine = OrxaqEngine()
        result = CreditPipeline(engine).generate_data(n=50).run()
        assert result.success is True
        assert result.steps[0].output["rows"] == 50


class TestPipelineChain:
    def test_ontology_data_pd(self) -> None:
        engine = OrxaqEngine()
        result = CreditPipeline(engine).load_ontology().generate_data(n=100).fit_pd().run()
        assert result.success is True
        assert len(result.steps) == 3
        assert all(s.status == StepStatus.COMPLETED for s in result.steps)

    def test_full_pipeline(self) -> None:
        engine = OrxaqEngine()
        result = (
            CreditPipeline(engine)
            .load_ontology()
            .generate_data(n=100)
            .fit_pd()
            .compute_ecl()
            .stress_test("adverse")
            .portfolio_analysis()
            .fairness_audit("age")
            .generate_report()
            .run()
        )
        assert result.success is True
        assert len(result.steps) == 8
        assert all(s.status == StepStatus.COMPLETED for s in result.steps)

    def test_full_pipeline_has_report(self) -> None:
        engine = OrxaqEngine()
        result = (
            CreditPipeline(engine)
            .load_ontology()
            .generate_data(n=50)
            .fit_pd()
            .compute_ecl()
            .portfolio_analysis()
            .generate_report()
            .run()
        )
        report_step = result.steps[-1]
        assert report_step.name == "generate_report"
        assert "risk_rating" in report_step.output
        assert "report_id" in report_step.output


class TestPipelineErrors:
    def test_fit_pd_without_data_fails(self) -> None:
        engine = OrxaqEngine()
        result = CreditPipeline(engine).fit_pd().run()
        assert result.success is False
        assert result.steps[0].status == StepStatus.FAILED
        assert "data" in result.steps[0].error.lower()

    def test_skips_remaining_on_failure(self) -> None:
        engine = OrxaqEngine()
        result = (
            CreditPipeline(engine)
            .fit_pd()  # fails — no data
            .compute_ecl()  # should be skipped
            .run()
        )
        assert result.success is False
        assert result.steps[0].status == StepStatus.FAILED
        assert result.steps[1].status == StepStatus.SKIPPED

    def test_ecl_without_data_fails(self) -> None:
        engine = OrxaqEngine()
        result = CreditPipeline(engine).compute_ecl().run()
        assert result.success is False
        assert result.steps[0].status == StepStatus.FAILED


class TestPipelineResult:
    def test_to_dict(self) -> None:
        engine = OrxaqEngine()
        result = CreditPipeline(engine).load_ontology().run()
        d = result.to_dict()
        assert d["success"] is True
        assert len(d["steps"]) == 1
        assert d["steps"][0]["status"] == "completed"
        assert "total_duration_ms" in d

    def test_step_duration_positive(self) -> None:
        engine = OrxaqEngine()
        result = CreditPipeline(engine).generate_data(n=50).run()
        assert result.steps[0].duration_ms > 0

    def test_total_duration_positive(self) -> None:
        engine = OrxaqEngine()
        result = CreditPipeline(engine).load_ontology().generate_data(n=50).run()
        assert result.total_duration_ms > 0

    def test_failed_step_to_dict(self) -> None:
        engine = OrxaqEngine()
        result = CreditPipeline(engine).fit_pd().run()
        d = result.to_dict()
        assert d["success"] is False
        assert d["steps"][0]["status"] == "failed"
        assert d["steps"][0]["error"] != ""


class TestPipelineStressScenarios:
    def test_baseline_scenario(self) -> None:
        engine = OrxaqEngine()
        result = (
            CreditPipeline(engine)
            .load_ontology()
            .generate_data(n=50)
            .fit_pd()
            .stress_test("baseline")
            .run()
        )
        assert result.success is True
        stress = result.steps[3].output
        assert stress["scenario"] == "baseline"

    def test_severely_adverse_scenario(self) -> None:
        engine = OrxaqEngine()
        result = (
            CreditPipeline(engine)
            .load_ontology()
            .generate_data(n=50)
            .fit_pd()
            .stress_test("severely_adverse")
            .run()
        )
        assert result.success is True
        stress = result.steps[3].output
        assert stress["scenario"] == "severely_adverse"


# ── Targeted coverage (lines 152-153, 204-205) ──────────


class TestPipelineMissingContext:
    """Cover lines 152-153 and 204-205: steps fail without data/model."""

    def test_stress_test_no_data(self) -> None:
        """Cover lines 152-153: stress_test without generate_data."""
        engine = OrxaqEngine()
        engine.load_credit_ontology()
        result = CreditPipeline(engine).stress_test().run()
        assert result.success is False
        assert result.steps[0].status == StepStatus.FAILED

    def test_portfolio_analysis_no_data(self) -> None:
        """Cover lines 204-205: portfolio_analysis without generate_data."""
        engine = OrxaqEngine()
        engine.load_credit_ontology()
        result = CreditPipeline(engine).portfolio_analysis().run()
        assert result.success is False
        assert result.steps[0].status == StepStatus.FAILED
