"""Integration tests for test_runner.capture.runner (with mocked executor)."""

from __future__ import annotations

import json
from pathlib import Path
from unittest.mock import MagicMock

import pytest

from test_runner.common.config import TestRunnerConfig
from test_runner.common.container import TestRunnerContainer
from test_runner.common.database_dialect import DatabaseDialect
from test_runner.common.database_executor import DatabaseExecutor
from test_runner.common.models import TestCaseResult
from test_runner.capture.runner import run_capture


class _FakeExecutor(DatabaseExecutor):
    """A fake executor that returns canned results instead of hitting a real DB."""

    def __init__(self, result: TestCaseResult | None = None) -> None:
        self._result = result or TestCaseResult(
            result_sets=[[{"Id": 1, "Name": "Widget"}]],
            row_counts=[1],
            success=True,
        )

    def close(self) -> None:
        pass

    def execute(self, sql: str, steps=None, fetch_stmts=None) -> TestCaseResult:
        return self._result


def _make_config(**overrides) -> TestRunnerConfig:
    defaults = dict(
        source_dialect=DatabaseDialect.SQL_SERVER,
        source_connection_raw={
            "host": "localhost",
            "database": "TestDB",
            "username": "sa",
            "password": "secret",
        },
    )
    defaults.update(overrides)
    return TestRunnerConfig(**defaults)


def _make_registry(executor=None):
    """Build a factory registry, optionally mocking the source executor."""
    container = TestRunnerContainer()
    registry = container.factory_registry()
    if executor is not None:
        factory = registry[DatabaseDialect.SQL_SERVER]
        factory.build_config = MagicMock(return_value=MagicMock())
        factory.create_executor = MagicMock(return_value=executor)
    return registry


class TestRunCapture:
    def test_end_to_end_with_fake_executor(self, tmp_project: Path):
        stats = run_capture(
            config=_make_config(),
            factory_registry=_make_registry(_FakeExecutor()),
            project_root=tmp_project,
        )

        assert stats.total == 4
        assert stats.succeeded == 4
        assert stats.failed == 0
        assert len(stats.baseline_files) == 4

        for path_str in stats.baseline_files:
            p = Path(path_str)
            assert p.exists()
            data = json.loads(p.read_text())
            assert "procedure" in data
            assert data["success"] is True

    def test_failed_execution_tracked(self, tmp_project: Path):
        fake = _FakeExecutor(TestCaseResult(
            result_sets=[], row_counts=[], success=False, error="Procedure not found",
        ))

        stats = run_capture(
            config=_make_config(),
            factory_registry=_make_registry(fake),
            project_root=tmp_project,
        )

        assert stats.total == 4
        assert stats.succeeded == 0
        assert stats.failed == 4

        for path_str in stats.baseline_files:
            data = json.loads(Path(path_str).read_text())
            assert data["success"] is False

    def test_custom_baseline_dir(self, tmp_project: Path):
        custom_dir = tmp_project / "my_baselines"

        stats = run_capture(
            config=_make_config(),
            factory_registry=_make_registry(_FakeExecutor()),
            project_root=tmp_project,
            baseline_dir=custom_dir,
        )

        assert stats.total > 0
        for path_str in stats.baseline_files:
            assert str(custom_dir) in path_str

    def test_parameters_in_baseline(self, tmp_project: Path):
        stats = run_capture(
            config=_make_config(),
            factory_registry=_make_registry(_FakeExecutor()),
            project_root=tmp_project,
        )

        orders_baselines = [p for p in stats.baseline_files if "GetCustomerOrders" in p]
        assert len(orders_baselines) == 3

        data = json.loads(Path(orders_baselines[0]).read_text())
        assert "customerId" in data["parameters"]
        assert "status" in data["parameters"]

    def test_no_test_files_returns_empty_stats(self, tmp_path: Path):
        settings = tmp_path / "settings"
        settings.mkdir()
        (settings / "test_config.yaml").write_text(
            "source_platform: sqlserver\ntarget_platform: snowflake\n"
        )

        stats = run_capture(
            config=_make_config(),
            factory_registry=_make_registry(_FakeExecutor()),
            project_root=tmp_path,
        )

        assert stats.total == 0
        assert stats.baseline_files == []
