"""Tests for durable writes mode."""

from pathlib import Path

from codex_autorunner.core.config import (
    DEFAULT_HUB_CONFIG,
    DEFAULT_REPO_CONFIG,
    load_repo_config,
)
from codex_autorunner.core.flows.store import FlowStore
from codex_autorunner.core.sqlite_utils import (
    SQLITE_PRAGMAS,
    SQLITE_PRAGMAS_DURABLE,
    connect_sqlite,
)
from codex_autorunner.core.state import RunnerState, load_state, save_state
from codex_autorunner.core.utils import atomic_write


def test_atomic_write_without_durable(tmp_path: Path) -> None:
    """Test atomic_write without durable mode."""
    file_path = tmp_path / "test.txt"
    content = "test content"
    atomic_write(file_path, content, durable=False)
    assert file_path.exists()
    assert file_path.read_text() == content


def test_atomic_write_with_durable(tmp_path: Path) -> None:
    """Test atomic_write with durable mode."""
    file_path = tmp_path / "test.txt"
    content = "test content"
    atomic_write(file_path, content, durable=True)
    assert file_path.exists()
    assert file_path.read_text() == content


def test_connect_sqlite_without_durable(tmp_path: Path) -> None:
    """Test connect_sqlite without durable mode."""
    db_path = tmp_path / "test.db"
    conn = connect_sqlite(db_path, durable=False)
    assert conn is not None
    # Check that synchronous pragma is NORMAL (default)
    cursor = conn.execute("PRAGMA synchronous;")
    synchronous = cursor.fetchone()[0]
    assert synchronous == 1  # 1 = NORMAL in SQLite
    conn.close()


def test_connect_sqlite_with_durable(tmp_path: Path) -> None:
    """Test connect_sqlite with durable mode."""
    db_path = tmp_path / "test.db"
    conn = connect_sqlite(db_path, durable=True)
    assert conn is not None
    # Check that synchronous pragma is FULL (durable mode)
    cursor = conn.execute("PRAGMA synchronous;")
    synchronous = cursor.fetchone()[0]
    assert synchronous == 2  # 2 = FULL in SQLite
    conn.close()


def test_sqlite_pragmas_differ() -> None:
    """Verify that durable and normal pragmas differ in synchronous setting."""
    # Extract synchronous setting from each set
    normal_sync = None
    durable_sync = None
    for pragma in SQLITE_PRAGMAS:
        if pragma.startswith("PRAGMA synchronous="):
            normal_sync = pragma.split("=")[1].rstrip(";")
    for pragma in SQLITE_PRAGMAS_DURABLE:
        if pragma.startswith("PRAGMA synchronous="):
            durable_sync = pragma.split("=")[1].rstrip(";")
    assert normal_sync == "NORMAL"
    assert durable_sync == "FULL"
    assert normal_sync != durable_sync


def test_flow_store_without_durable(tmp_path: Path) -> None:
    """Test FlowStore without durable mode."""
    db_path = tmp_path / "flows.db"
    with FlowStore(db_path, durable=False) as store:
        # Check that synchronous is NORMAL using the store's connection
        conn = store._get_conn()
        cursor = conn.execute("PRAGMA synchronous;")
        synchronous = cursor.fetchone()[0]
        assert synchronous == 1  # 1 = NORMAL


def test_flow_store_with_durable(tmp_path: Path) -> None:
    """Test FlowStore with durable mode."""
    db_path = tmp_path / "flows.db"
    with FlowStore(db_path, durable=True) as store:
        # Check that synchronous is FULL using the store's connection
        conn = store._get_conn()
        cursor = conn.execute("PRAGMA synchronous;")
        synchronous = cursor.fetchone()[0]
        assert synchronous == 2  # 2 = FULL


def test_state_load_save_without_durable(tmp_path: Path) -> None:
    """Test load_state and save_state without durable mode."""
    state_path = tmp_path / "state.sqlite3"
    state = RunnerState(None, "idle", None, None, None)
    save_state(state_path, state, durable=False)
    loaded = load_state(state_path, durable=False)
    assert loaded.status == "idle"
    assert loaded.last_run_id is None


def test_state_load_save_with_durable(tmp_path: Path) -> None:
    """Test load_state and save_state with durable mode."""
    state_path = tmp_path / "state.sqlite3"
    state = RunnerState(None, "idle", None, None, None)
    save_state(state_path, state, durable=True)
    loaded = load_state(state_path, durable=True)
    assert loaded.status == "idle"
    assert loaded.last_run_id is None


def test_default_config_has_durable_writes() -> None:
    """Verify that default config has durable_writes setting."""
    assert "storage" in DEFAULT_REPO_CONFIG
    assert "durable_writes" in DEFAULT_REPO_CONFIG["storage"]
    assert DEFAULT_REPO_CONFIG["storage"]["durable_writes"] is False

    assert "storage" in DEFAULT_HUB_CONFIG
    assert "durable_writes" in DEFAULT_HUB_CONFIG["storage"]
    assert DEFAULT_HUB_CONFIG["storage"]["durable_writes"] is False


def test_load_repo_config_with_durable_writes(tmp_path: Path) -> None:
    """Test that load_repo_config correctly reads durable_writes setting from repo override."""
    from tests.conftest import write_test_config

    hub_root = tmp_path / "hub"
    hub_root.mkdir()
    write_test_config(
        hub_root / ".codex-autorunner" / "config.yml",
        {"mode": "hub"},
    )

    repo_root = hub_root / "repo"
    repo_root.mkdir()
    (repo_root / ".git").mkdir()
    write_test_config(
        repo_root / ".codex-autorunner" / "repo.override.yml",
        {"storage": {"durable_writes": True}},
    )

    config = load_repo_config(repo_root, hub_path=hub_root)
    assert config.durable_writes is True


def test_load_repo_config_default_durable_writes(tmp_path: Path) -> None:
    """Test that load_repo_config defaults durable_writes to False."""
    from tests.conftest import write_test_config

    hub_root = tmp_path / "hub"
    hub_root.mkdir()
    write_test_config(
        hub_root / ".codex-autorunner" / "config.yml",
        {"mode": "hub"},
    )

    repo_root = hub_root / "repo"
    repo_root.mkdir()
    (repo_root / ".git").mkdir()

    config = load_repo_config(repo_root, hub_path=hub_root)
    assert config.durable_writes is False
