"""Tests for core RunManifest mapper."""

from __future__ import annotations

import re

from dpe.core_bridge._run_manifest_core import build_core_manifest
from dpe.models.config import DPEConfig
from dpe.models.manifest import RunManifest


class TestBuildCoreManifest:
    def test_schema_version(
        self, completed_manifest: RunManifest, default_config: DPEConfig
    ) -> None:
        cm = build_core_manifest(completed_manifest, default_config)
        assert cm["schema_version"] == "run-manifest/1.0"

    def test_run_id_is_8_chars(
        self, completed_manifest: RunManifest, default_config: DPEConfig
    ) -> None:
        cm = build_core_manifest(completed_manifest, default_config)
        assert cm["run_id"] == "aabbccdd"
        assert re.match(r"^[0-9a-f]{8}$", cm["run_id"])

    def test_gate_is_custom(
        self, completed_manifest: RunManifest, default_config: DPEConfig
    ) -> None:
        cm = build_core_manifest(completed_manifest, default_config)
        assert cm["gate"] == "custom"

    def test_simulation_mode_is_dry_run(
        self, completed_manifest: RunManifest
    ) -> None:
        config = DPEConfig(simulation_mode=True)
        cm = build_core_manifest(completed_manifest, config)
        assert cm["mode"] == "dry-run"

    def test_non_simulation_mode_is_production(
        self, completed_manifest: RunManifest
    ) -> None:
        config = DPEConfig(simulation_mode=False)
        cm = build_core_manifest(completed_manifest, config)
        assert cm["mode"] == "production"

    def test_trigger_is_manual(
        self, completed_manifest: RunManifest, default_config: DPEConfig
    ) -> None:
        cm = build_core_manifest(completed_manifest, default_config)
        assert cm["trigger"] == "manual"

    def test_intent_gate_hash_format(
        self, completed_manifest: RunManifest, default_config: DPEConfig
    ) -> None:
        cm = build_core_manifest(completed_manifest, default_config)
        assert re.match(r"^sha256:[0-9a-f]{64}$", cm["intent_gate_hash"])

    def test_intent_gate_hash_deterministic(
        self, completed_manifest: RunManifest, default_config: DPEConfig
    ) -> None:
        cm1 = build_core_manifest(completed_manifest, default_config)
        cm2 = build_core_manifest(completed_manifest, default_config)
        assert cm1["intent_gate_hash"] == cm2["intent_gate_hash"]

    def test_timestamps_are_iso8601(
        self, completed_manifest: RunManifest, default_config: DPEConfig
    ) -> None:
        cm = build_core_manifest(completed_manifest, default_config)
        # Should end with Z (UTC)
        assert cm["started_at"].endswith("Z")
        assert cm["completed_at"].endswith("Z")

    def test_hashing_status_ok(
        self, completed_manifest: RunManifest, default_config: DPEConfig
    ) -> None:
        cm = build_core_manifest(completed_manifest, default_config)
        assert cm["hashing"]["jcs"]["status"] == "ok"

    def test_no_manifest_hash_field(
        self, completed_manifest: RunManifest, default_config: DPEConfig
    ) -> None:
        cm = build_core_manifest(completed_manifest, default_config)
        assert "manifest_hash_jcs_sha256" not in cm


class TestCompletedRunVerdict:
    def test_verdict_pass(
        self, completed_manifest: RunManifest, default_config: DPEConfig
    ) -> None:
        cm = build_core_manifest(completed_manifest, default_config)
        assert cm["verdict"] == "pass"

    def test_summary_counts(
        self, completed_manifest: RunManifest, default_config: DPEConfig
    ) -> None:
        cm = build_core_manifest(completed_manifest, default_config)
        s = cm["summary"]
        assert s["total"] == 12
        assert s["passed"] == 8
        assert s["skipped"] == 4
        assert s["failed"] == 0
        assert s["blocker"] == 0


class TestBudgetExceededVerdict:
    def test_verdict_warn(
        self, budget_exceeded_manifest: RunManifest, default_config: DPEConfig
    ) -> None:
        cm = build_core_manifest(budget_exceeded_manifest, default_config)
        assert cm["verdict"] == "warn"

    def test_summary_blocker_zero(
        self, budget_exceeded_manifest: RunManifest, default_config: DPEConfig
    ) -> None:
        cm = build_core_manifest(budget_exceeded_manifest, default_config)
        assert cm["summary"]["blocker"] == 0


class TestErrorRunVerdict:
    def test_verdict_fail(
        self, error_manifest: RunManifest, default_config: DPEConfig
    ) -> None:
        cm = build_core_manifest(error_manifest, default_config)
        assert cm["verdict"] == "fail"

    def test_summary_blocker_one(
        self, error_manifest: RunManifest, default_config: DPEConfig
    ) -> None:
        cm = build_core_manifest(error_manifest, default_config)
        assert cm["summary"]["blocker"] == 1

    def test_summary_failed_count(
        self, error_manifest: RunManifest, default_config: DPEConfig
    ) -> None:
        cm = build_core_manifest(error_manifest, default_config)
        assert cm["summary"]["failed"] == 1


class TestNotes:
    def test_contains_dpe_run_id(
        self, completed_manifest: RunManifest, default_config: DPEConfig
    ) -> None:
        cm = build_core_manifest(completed_manifest, default_config)
        assert "dpe_run_id=aabbccdd1122" in cm["notes"]

    def test_contains_source_pointer(
        self, completed_manifest: RunManifest, default_config: DPEConfig
    ) -> None:
        cm = build_core_manifest(completed_manifest, default_config)
        assert "source=run_manifest.json" in cm["notes"]

    def test_includes_warnings(
        self, budget_exceeded_manifest: RunManifest, default_config: DPEConfig
    ) -> None:
        cm = build_core_manifest(budget_exceeded_manifest, default_config)
        assert "Budget exceeded" in cm["notes"]
