"""Shared fixtures for core bridge tests."""

from __future__ import annotations

from datetime import UTC, datetime

import pytest

from dpe.models.config import DPEConfig
from dpe.models.manifest import (
    ArtifactRecord,
    BudgetActuals,
    RunManifest,
    StageRecord,
)

_NOW = datetime(2026, 2, 25, 12, 0, 0, tzinfo=UTC)
_LATER = datetime(2026, 2, 25, 12, 5, 0, tzinfo=UTC)


def _make_stage_record(
    stage: str,
    *,
    adapter: str = "simulation",
    skipped: bool = False,
    error: str | None = None,
) -> StageRecord:
    return StageRecord(
        stage=stage,
        adapter_used=adapter if not skipped else "none",
        started_at=_NOW,
        finished_at=_LATER,
        skipped=skipped,
        error=error,
    )


def _make_artifact(stage: str, filename: str) -> ArtifactRecord:
    return ArtifactRecord(
        filename=filename,
        stage=stage,
        sha256="a" * 64,
        size_bytes=100,
        written_at=_NOW,
    )


@pytest.fixture()
def completed_manifest() -> RunManifest:
    """A fully completed simulation run manifest (no cross-critique, 1 critique round)."""
    return RunManifest(
        run_id="aabbccdd1122",
        timestamp=_NOW,
        config_hash="b" * 64,
        models_used={
            "INPUT_NORMALIZE": "simulation",
            "IDEATION_A": "simulation",
            "IDEATION_B": "simulation",
            "SYNTHESIS": "simulation",
            "PRD_V1": "simulation",
            "PRD_CRITIQUE_R1": "simulation",
            "PRD_REVISION_R1": "simulation",
            "FINALIZE": "simulation",
        },
        budget_limits={"max_total_calls": 10, "max_premium_calls": 6},
        budget_actuals=BudgetActuals(
            total_calls_used=8,
            premium_calls_used=4,
            wall_time_seconds=5.0,
            critique_rounds_used=1,
        ),
        stages=[
            _make_stage_record("INPUT_NORMALIZE"),
            _make_stage_record("IDEATION_A"),
            _make_stage_record("IDEATION_B"),
            _make_stage_record("CROSS_CRITIQUE_A", skipped=True),
            _make_stage_record("CROSS_CRITIQUE_B", skipped=True),
            _make_stage_record("SYNTHESIS"),
            _make_stage_record("PRD_V1"),
            _make_stage_record("PRD_CRITIQUE_R1"),
            _make_stage_record("PRD_REVISION_R1"),
            _make_stage_record("PRD_CRITIQUE_R2", skipped=True),
            _make_stage_record("PRD_REVISION_R2", skipped=True),
            _make_stage_record("FINALIZE"),
        ],
        artifacts=[
            _make_artifact("INPUT_NORMALIZE", "00_input_normalized.md"),
            _make_artifact("IDEATION_A", "10_ideation_a.md"),
            _make_artifact("IDEATION_B", "11_ideation_b.md"),
            _make_artifact("SYNTHESIS", "30_synthesis.md"),
            _make_artifact("PRD_V1", "40_prd_v1.md"),
            _make_artifact("PRD_CRITIQUE_R1", "50_critique_r1.md"),
            _make_artifact("PRD_REVISION_R1", "60_prd_v2.md"),
            _make_artifact("FINALIZE", "80_prd_final.md"),
        ],
        stop_reason="completed",
        warnings=[],
    )


@pytest.fixture()
def budget_exceeded_manifest() -> RunManifest:
    """A manifest where budget was exceeded at PRD_CRITIQUE_R1."""
    return RunManifest(
        run_id="aabbccdd1122",
        timestamp=_NOW,
        config_hash="b" * 64,
        models_used={
            "INPUT_NORMALIZE": "simulation",
            "IDEATION_A": "simulation",
            "IDEATION_B": "simulation",
            "SYNTHESIS": "simulation",
            "PRD_V1": "simulation",
        },
        budget_limits={"max_total_calls": 5, "max_premium_calls": 3},
        budget_actuals=BudgetActuals(
            total_calls_used=5,
            premium_calls_used=3,
            wall_time_seconds=3.0,
            critique_rounds_used=0,
        ),
        stages=[
            _make_stage_record("INPUT_NORMALIZE"),
            _make_stage_record("IDEATION_A"),
            _make_stage_record("IDEATION_B"),
            _make_stage_record("CROSS_CRITIQUE_A", skipped=True),
            _make_stage_record("CROSS_CRITIQUE_B", skipped=True),
            _make_stage_record("SYNTHESIS"),
            _make_stage_record("PRD_V1"),
        ],
        artifacts=[
            _make_artifact("INPUT_NORMALIZE", "00_input_normalized.md"),
            _make_artifact("IDEATION_A", "10_ideation_a.md"),
            _make_artifact("IDEATION_B", "11_ideation_b.md"),
            _make_artifact("SYNTHESIS", "30_synthesis.md"),
            _make_artifact("PRD_V1", "40_prd_v1.md"),
        ],
        stop_reason="budget_exceeded",
        warnings=["Budget exceeded: premium calls limit reached"],
    )


@pytest.fixture()
def error_manifest() -> RunManifest:
    """A manifest where an adapter error occurred at SYNTHESIS."""
    return RunManifest(
        run_id="aabbccdd1122",
        timestamp=_NOW,
        config_hash="b" * 64,
        models_used={
            "INPUT_NORMALIZE": "simulation",
            "IDEATION_A": "simulation",
            "IDEATION_B": "simulation",
        },
        budget_limits={"max_total_calls": 10},
        budget_actuals=BudgetActuals(
            total_calls_used=3,
            premium_calls_used=2,
            wall_time_seconds=2.0,
            critique_rounds_used=0,
        ),
        stages=[
            _make_stage_record("INPUT_NORMALIZE"),
            _make_stage_record("IDEATION_A"),
            _make_stage_record("IDEATION_B"),
            _make_stage_record("SYNTHESIS", error="ConnectionError"),
        ],
        artifacts=[
            _make_artifact("INPUT_NORMALIZE", "00_input_normalized.md"),
            _make_artifact("IDEATION_A", "10_ideation_a.md"),
            _make_artifact("IDEATION_B", "11_ideation_b.md"),
        ],
        stop_reason="error: ConnectionError",
        warnings=["ConnectionError"],
    )


@pytest.fixture()
def default_config() -> DPEConfig:
    return DPEConfig(simulation_mode=True)


@pytest.fixture()
def sample_stage_outputs() -> dict:
    from dpe.engine.states import Stage

    return {
        Stage.INPUT_NORMALIZE: "Normalized idea text",
        Stage.IDEATION_A: "Ideation A output",
        Stage.IDEATION_B: "Ideation B output",
        Stage.SYNTHESIS: "Synthesis output",
        Stage.PRD_V1: "PRD v1 output",
        Stage.PRD_CRITIQUE_R1: "Critique R1 output",
        Stage.PRD_REVISION_R1: "PRD v2 output",
        Stage.FINALIZE: "# Final PRD\n\n## Overview\nFinal output",
    }
