"""Quality-gate tests: the gate is fail-closed and its commands come from config."""

from __future__ import annotations

import json
import sys
from pathlib import Path

from adw_modules import quality
from adw_modules.data_types import (ConfigDefaults, ObservabilityConfig, PhaseParams,
                                    QualityCheckConfig, SSSFConfig)
from adw_modules.runner import Run
from adw_modules.tracer import Tracer


def _run(tmp_path: Path, checks: dict[str, QualityCheckConfig]) -> Run:
    cfg = SSSFConfig(
        defaults=ConfigDefaults(data_dir=str(tmp_path / "data")),
        observability=ObservabilityConfig(db=str(tmp_path / "sssf.db")),
        quality=checks,
    )
    tracer = Tracer(Path(cfg.observability.db), tmp_path / "events.jsonl")
    tracer.session_start("adw_test", "tester", repo=tmp_path)
    run = Run(cfg, "adw_test", tracer, "tester")
    run.repo_root = str(tmp_path)
    return run


def _phase(run: Run):
    return run.phase(PhaseParams(name="quality", task_id="quality", kind="code", owner="git",
                                 description="Run the deterministic quality checks."))


def test_undeclared_check_fails(tmp_path: Path) -> None:
    run = _run(tmp_path, {})
    try:
        with _phase(run):
            result = quality.run_tests(run)
        row = run.tracer.conn.execute(
            "SELECT gate,passed,violations_json,checks_json FROM gate_results"
        ).fetchone()
    finally:
        run.tracer.conn.close()

    assert result.passed is False
    assert result.checks[0].returncode == quality.EX_CONFIG
    assert "not configured" in result.checks[0].output_tail
    assert row[0:2] == ("quality:test", 0)
    assert "not configured" in json.loads(row[2])[0]
    assert json.loads(row[3])[0]["exit_code"] == quality.EX_CONFIG


def test_empty_quality_section_fails_the_phase(tmp_path: Path) -> None:
    run = _run(tmp_path, {})
    try:
        with _phase(run):
            result = quality.run_quality(run)
        phase = run.tracer.conn.execute(
            "SELECT status,error FROM phases WHERE name='quality'"
        ).fetchone()
    finally:
        run.tracer.conn.close()

    assert result.passed is False
    assert result.checks == []
    assert "no quality checks configured" in result.failures[0]
    assert phase[0] == "fail"
    assert "no quality checks configured" in phase[1]


def test_declared_checks_run_and_report_the_real_verdict(tmp_path: Path) -> None:
    run = _run(tmp_path, {
        "test": QualityCheckConfig(argv=["true"]),
        "lint": QualityCheckConfig(argv=["false"], operation="lint"),
    })
    try:
        with _phase(run):
            result = quality.run_quality(run)
    finally:
        run.tracer.conn.close()

    assert [c.name for c in result.checks] == ["test", "lint"]
    assert [c.passed for c in result.checks] == [True, False]
    assert result.passed is False
    assert result.failures and result.failures[0].startswith("lint: `false` exited 1")


def test_each_quality_check_writes_a_gate_row_and_failure_marks_phase(
    tmp_path: Path,
) -> None:
    failing_command = [
        sys.executable, "-c",
        "import sys; print('X' * 5000, file=sys.stderr); raise SystemExit(7)",
    ]
    run = _run(tmp_path, {
        "test": QualityCheckConfig(argv=failing_command),
        "typecheck": QualityCheckConfig(argv=["true"], operation="typecheck"),
        "build": QualityCheckConfig(argv=["true"]),
    })
    try:
        with run.phase(PhaseParams(name="verify_1", task_id="verify_1", kind="code", owner="quality",
                                   description="Record a deterministic verification attempt.")):
            result = quality.run_quality(run)
        rows = run.tracer.conn.execute(
            "SELECT gate,passed,violations_json,checks_json FROM gate_results ORDER BY id"
        ).fetchall()
        phase = run.tracer.conn.execute(
            "SELECT status,error FROM phases WHERE name='verify_1'"
        ).fetchone()
    finally:
        run.tracer.conn.close()

    assert [row[0] for row in rows] == [
        "quality:test", "quality:typecheck", "quality:build",
    ]
    assert [row[1] for row in rows] == [0, 1, 1]
    assert all(len(json.loads(row[3])) == 1 for row in rows)
    assert json.loads(rows[1][2]) == []
    assert json.loads(rows[2][2]) == []
    violations = json.loads(rows[0][2])
    assert violations and quality.TAIL_TRUNCATION_MARKER.strip() in violations[0]
    check_evidence = json.loads(rows[0][3])
    assert len(check_evidence) == 1
    assert check_evidence[0]["item"] == result.checks[0].command
    assert check_evidence[0]["ok"] is False
    assert check_evidence[0]["command"] == result.checks[0].command
    assert check_evidence[0]["exit_code"] == 7
    assert isinstance(check_evidence[0]["duration_ms"], int)
    assert check_evidence[0]["command_log"] == str(
        Path(result.checks[0].output_artifact).resolve()
    )
    assert Path(check_evidence[0]["command_log"]).is_absolute()
    assert phase == ("fail", "quality checks failed: test (exit 7)")
