"""CLI behavior tests."""

from __future__ import annotations

import json

from osm_lead_source_service import __version__
from osm_lead_source_service.cli import main


def test_package_import_and_version_command(capsys: object) -> None:
    exit_code = main(["version"])
    assert exit_code == 0
    captured = capsys.readouterr()  # type: ignore[attr-defined]
    assert captured.out.strip() == __version__
    assert captured.err == ""


def test_validate_config_is_offline_and_successful(capsys: object) -> None:
    exit_code = main(["validate-config"])
    assert exit_code == 0
    captured = capsys.readouterr()  # type: ignore[attr-defined]
    assert captured.out.strip() == "configuration valid"


def test_validate_config_rejects_prohibited_environment_value(
    monkeypatch: object, capsys: object
) -> None:
    monkeypatch.setenv(  # type: ignore[attr-defined]
        "OSM_LEAD_SOURCE_NOCO_WRITE_ENABLED", "true"
    )
    exit_code = main(["validate-config"])
    assert exit_code == 2
    captured = capsys.readouterr()  # type: ignore[attr-defined]
    assert "noco_write_enabled" in captured.err


def test_offline_doctor(capsys: object) -> None:
    exit_code = main(["doctor", "--offline"])
    assert exit_code == 0
    captured = capsys.readouterr()  # type: ignore[attr-defined]
    assert captured.out.strip() == "doctor: ok"


def test_json_doctor_output_is_machine_readable_and_deterministic(capsys: object) -> None:
    exit_code = main(["doctor", "--offline", "--json"])
    assert exit_code == 0
    captured = capsys.readouterr()  # type: ignore[attr-defined]
    result = json.loads(captured.out)
    assert result["command"] == "doctor"
    assert result["offline"] is True
    assert result["ok"] is True
    assert result["phase"] == "2A.6"
    assert all(check["ok"] for check in result["checks"].values())
    assert captured.out == json.dumps(result, sort_keys=True, separators=(",", ":")) + "\n"


def test_doctor_rejects_invalid_configuration(monkeypatch: object, capsys: object) -> None:
    monkeypatch.setenv(  # type: ignore[attr-defined]
        "OSM_LEAD_SOURCE_STALE_DELETION_ENABLED", "true"
    )
    exit_code = main(["doctor", "--offline", "--json"])
    assert exit_code == 1
    captured = capsys.readouterr()  # type: ignore[attr-defined]
    result = json.loads(captured.out)
    assert result["ok"] is False
    assert "stale_deletion_enabled" in result["config_error"]


def test_geofabrik_acquire_preview_is_offline(tmp_path: object, capsys: object) -> None:
    exit_code = main(
        [
            "geofabrik-acquire",
            "--region",
            "au-act",
            "--cache-dir",
            str(tmp_path),
        ]
    )
    assert exit_code == 0
    captured = capsys.readouterr()  # type: ignore[attr-defined]
    result = json.loads(captured.out)
    assert result["execute"] is False
    assert result["network_access"] is False
    assert result["region"]["region_id"] == "au-act"
    assert result["cache_dir"] == str(tmp_path)


def test_act_shadow_pilot_preview_is_offline(tmp_path: object, capsys: object) -> None:
    output = tmp_path / "report.json"  # type: ignore[operator]
    evidence = tmp_path / "evidence.json"  # type: ignore[operator]
    exit_code = main(
        [
            "geofabrik-shadow-pilot",
            "--cache-dir",
            str(tmp_path),
            "--output",
            str(output),
            "--evidence-output",
            str(evidence),
        ]
    )
    assert exit_code == 0
    captured = capsys.readouterr()  # type: ignore[attr-defined]
    result = json.loads(captured.out)
    assert result["execute"] is False
    assert result["network_access"] is False
    assert result["noco_access"] is False
    assert result["writes_enabled"] is False
    assert result["scheduler_enabled"] is False
    assert result["region"]["region_id"] == "au-act"
    assert not output.exists()
    assert not evidence.exists()


def test_market_run_once_preview_is_offline(
    monkeypatch: object, tmp_path: object, capsys: object
) -> None:
    from osm_lead_source_service import worker

    monkeypatch.setenv(  # type: ignore[attr-defined]
        "OSM_LEAD_SOURCE_COUNTRIES", "IE,NZ,SG"
    )
    monkeypatch.setenv(  # type: ignore[attr-defined]
        "OSM_LEAD_SOURCE_CACHE_DIR", str(tmp_path / "cache")
    )
    monkeypatch.setenv(  # type: ignore[attr-defined]
        "OSM_LEAD_SOURCE_REPORT_DIR", str(tmp_path / "reports")
    )
    monkeypatch.setenv(  # type: ignore[attr-defined]
        "OSM_LEAD_SOURCE_DASHBOARD_SNAPSHOT_PATH", str(tmp_path / "dashboard.json")
    )

    def fail_if_executed(config: object) -> dict[str, object]:
        del config
        raise AssertionError("preview must not execute the worker")

    monkeypatch.setattr(  # type: ignore[attr-defined]
        worker, "run_worker_once", fail_if_executed
    )

    exit_code = main(["market-run-once"])

    assert exit_code == 0
    captured = capsys.readouterr()  # type: ignore[attr-defined]
    result = json.loads(captured.out)
    assert result == {
        "cache_dir": str(tmp_path / "cache"),
        "command": "market-run-once",
        "countries": ["IE", "NZ", "SG"],
        "dashboard_snapshot_path": str(tmp_path / "dashboard.json"),
        "execute": False,
        "network_access": False,
        "noco_access": False,
        "report_dir": str(tmp_path / "reports"),
        "scheduler_required": False,
        "scheduler_started": False,
        "writes_enabled": False,
    }
    assert captured.err == ""


def test_market_run_once_executes_shared_worker_exactly_once(
    monkeypatch: object, tmp_path: object, capsys: object
) -> None:
    from osm_lead_source_service import worker

    monkeypatch.setenv(  # type: ignore[attr-defined]
        "OSM_LEAD_SOURCE_COUNTRIES", "IE,NZ,SG"
    )
    monkeypatch.setenv(  # type: ignore[attr-defined]
        "OSM_LEAD_SOURCE_CACHE_DIR", str(tmp_path / "cache")
    )
    monkeypatch.setenv(  # type: ignore[attr-defined]
        "OSM_LEAD_SOURCE_REPORT_DIR", str(tmp_path / "reports")
    )
    monkeypatch.setenv(  # type: ignore[attr-defined]
        "OSM_LEAD_SOURCE_DASHBOARD_SNAPSHOT_PATH", str(tmp_path / "dashboard.json")
    )
    calls: list[object] = []

    def fake_run(config: object) -> dict[str, object]:
        calls.append(config)
        summary = {
            "event": "read_only_cycle_completed",
            "status": "completed",
            "writes_enabled": False,
        }
        print(json.dumps(summary, sort_keys=True, separators=(",", ":")))
        return summary

    monkeypatch.setattr(worker, "run_worker_once", fake_run)  # type: ignore[attr-defined]

    exit_code = main(["market-run-once", "--execute"])

    assert exit_code == 0
    assert len(calls) == 1
    config = calls[0]
    assert isinstance(config, worker.WorkerConfig)
    assert tuple(market.country_code for market in config.markets) == ("IE", "NZ", "SG")
    assert config.cache_dir == tmp_path / "cache"
    assert config.report_dir == tmp_path / "reports"
    assert config.dashboard_snapshot_path == tmp_path / "dashboard.json"
    captured = capsys.readouterr()  # type: ignore[attr-defined]
    assert json.loads(captured.out) == {
        "event": "read_only_cycle_completed",
        "status": "completed",
        "writes_enabled": False,
    }
    assert captured.err == ""


def test_market_run_once_returns_nonzero_for_partial_cycle(
    monkeypatch: object, tmp_path: object, capsys: object
) -> None:
    from osm_lead_source_service import worker
    from osm_lead_source_service.errors import PartialCycleError

    monkeypatch.setenv(  # type: ignore[attr-defined]
        "OSM_LEAD_SOURCE_CACHE_DIR", str(tmp_path / "cache")
    )
    monkeypatch.setenv(  # type: ignore[attr-defined]
        "OSM_LEAD_SOURCE_REPORT_DIR", str(tmp_path / "reports")
    )
    monkeypatch.setenv(  # type: ignore[attr-defined]
        "OSM_LEAD_SOURCE_DASHBOARD_SNAPSHOT_PATH", str(tmp_path / "dashboard.json")
    )
    summary = {
        "event": "read_only_cycle_partial",
        "failed_shards": 1,
        "failure_codes": {"PbfParseError.ContractViolation": 1},
        "status": "partial",
        "writes_enabled": False,
    }

    def partial(config: object) -> dict[str, object]:
        del config
        print(json.dumps(summary, sort_keys=True, separators=(",", ":")))
        raise PartialCycleError(summary)

    monkeypatch.setattr(worker, "run_worker_once", partial)  # type: ignore[attr-defined]

    exit_code = main(["market-run-once", "--execute"])

    assert exit_code == 2
    captured = capsys.readouterr()  # type: ignore[attr-defined]
    assert json.loads(captured.out) == summary
    lines = captured.err.splitlines()
    failure = json.loads(lines[0])
    assert failure["error_code"] == "PartialCycleError"
    assert failure["event"] == "read_only_cycle_failed"
    assert lines[1] == "error: read-only cycle completed with failed shards"


def test_market_run_once_refuses_write_capability(monkeypatch: object, capsys: object) -> None:
    monkeypatch.setenv(  # type: ignore[attr-defined]
        "OSM_LEAD_SOURCE_WRITER_ENABLED", "true"
    )

    exit_code = main(["market-run-once"])

    assert exit_code == 2
    captured = capsys.readouterr()  # type: ignore[attr-defined]
    lines = captured.err.splitlines()
    failure = json.loads(lines[0])
    assert failure["command"] == "market-run-once"
    assert failure["error_code"] == "InvalidConfiguration"
    assert failure["event"] == "read_only_cycle_failed"
    assert failure["scheduler_started"] is False
    assert failure["writes_enabled"] is False
    assert "OSM_LEAD_SOURCE_WRITER_ENABLED" in lines[1]


def test_market_run_once_masks_unexpected_failure_detail(
    monkeypatch: object, tmp_path: object, capsys: object
) -> None:
    from osm_lead_source_service import worker

    monkeypatch.setenv(  # type: ignore[attr-defined]
        "OSM_LEAD_SOURCE_CACHE_DIR", str(tmp_path / "cache")
    )
    monkeypatch.setenv(  # type: ignore[attr-defined]
        "OSM_LEAD_SOURCE_REPORT_DIR", str(tmp_path / "reports")
    )
    monkeypatch.setenv(  # type: ignore[attr-defined]
        "OSM_LEAD_SOURCE_DASHBOARD_SNAPSHOT_PATH", str(tmp_path / "dashboard.json")
    )

    def fail(config: object) -> dict[str, object]:
        del config
        raise RuntimeError("sensitive upstream detail")

    monkeypatch.setattr(worker, "run_worker_once", fail)  # type: ignore[attr-defined]

    exit_code = main(["market-run-once", "--execute"])

    assert exit_code == 2
    captured = capsys.readouterr()  # type: ignore[attr-defined]
    lines = captured.err.splitlines()
    failure = json.loads(lines[0])
    assert failure["error_code"] == "RuntimeError"
    assert lines[1] == "error: market-run-once failed"
    assert "sensitive upstream detail" not in captured.err


def test_module_entry_point_is_available() -> None:
    from osm_lead_source_service import __main__

    assert callable(__main__.main)
