"""Stability validation: a test must pass 3 consecutive executions to be accepted.

Pure logic — no AI, no network calls.

A test that fails on any run has its pass_count reset to 0.
The repair_engine handles recovery before re-entry into this module.
"""

from __future__ import annotations

from .models import BaselineTest, TestStatus
from .test_executor import run_tests

REQUIRED_PASSES = 3


def validate_stability(
    tests: list[BaselineTest],
    browser: str = "chromium",
    required_passes: int = REQUIRED_PASSES,
    progress_callback=None,
) -> None:
    """Run each test up to required_passes times and track consecutive passes.

    A test is PASSING (stable) only if it accumulates required_passes consecutive
    successful executions without a single failure.

    Tests already marked UNSTABLE are skipped.
    After the loop, any test with pass_count < required_passes is marked UNSTABLE.

    Args:
        tests: List of BaselineTest objects to validate.
        browser: Playwright browser engine to use.
        required_passes: Number of consecutive passes required (default 3).
        progress_callback: Optional callable(test_name, run_num, passed: bool).
    """
    # Only validate tests that are in a runnable state
    candidates = [
        t for t in tests
        if t.status not in (TestStatus.UNSTABLE,)
        and t.script_path
    ]

    for run_num in range(1, required_passes + 1):
        if not candidates:
            break
        # Run only tests that haven't failed yet this round
        active = [t for t in candidates if t.status != TestStatus.FAILING]
        if not active:
            break

        run_tests(active, browser)

        for t in active:
            if t.status == TestStatus.PASSING:
                t.pass_count += 1
                if progress_callback:
                    progress_callback(t.name, run_num, True)
            else:
                # Any failure resets the consecutive-pass counter
                t.pass_count = 0
                if progress_callback:
                    progress_callback(t.name, run_num, False)
                # Remove from active candidates — needs repair
                candidates = [c for c in candidates if c is not t]

    # Final gate: any test that didn't reach required_passes is unstable
    for t in tests:
        if t.status == TestStatus.UNSTABLE:
            continue
        if t.pass_count < required_passes:
            t.status = TestStatus.UNSTABLE
            if not t.failure_reason:
                t.failure_reason = (
                    f"did not pass {required_passes} consecutive times "
                    f"(passed {t.pass_count})"
                )
