from __future__ import annotations

import subprocess
import sys
from pathlib import Path

from typer.testing import CliRunner

from ocr_pipeline import config as config_module
from ocr_pipeline.cli import app

runner = CliRunner()

SRC_DIR = Path(__file__).parent.parent / "src"


def _isolate_config(tmp_path: Path, monkeypatch) -> None:
    """Pretend no config exists anywhere."""
    monkeypatch.delenv(config_module.CONFIG_ENV_VAR, raising=False)
    monkeypatch.chdir(tmp_path)
    monkeypatch.setattr(config_module, "user_config_dir", lambda: tmp_path / "no-such-dir")


def test_find_config_file_prefers_env_var(tmp_path: Path, monkeypatch) -> None:
    env_cfg = tmp_path / "env.yaml"
    env_cfg.write_text("ocr:\n  engine: tesseract\n", encoding="utf-8")
    cwd_dir = tmp_path / "cwd"
    cwd_dir.mkdir()
    (cwd_dir / "config.yaml").write_text("{}", encoding="utf-8")
    monkeypatch.setenv(config_module.CONFIG_ENV_VAR, str(env_cfg))
    monkeypatch.chdir(cwd_dir)
    assert config_module.find_config_file() == env_cfg


def test_find_config_file_uses_cwd(tmp_path: Path, monkeypatch) -> None:
    monkeypatch.delenv(config_module.CONFIG_ENV_VAR, raising=False)
    (tmp_path / "config.yaml").write_text("{}", encoding="utf-8")
    monkeypatch.chdir(tmp_path)
    assert config_module.find_config_file() == tmp_path / "config.yaml"


def test_find_config_file_none_when_unconfigured(tmp_path: Path, monkeypatch) -> None:
    _isolate_config(tmp_path, monkeypatch)
    assert config_module.find_config_file() is None


def test_import_does_not_read_cwd_config(tmp_path: Path) -> None:
    (tmp_path / "config.yaml").write_text("{invalid yaml: [", encoding="utf-8")
    result = subprocess.run(
        [sys.executable, "-c", "import ocr_pipeline.config; print('ok')"],
        cwd=tmp_path,
        capture_output=True,
        text=True,
        env={"PYTHONPATH": str(SRC_DIR), "PATH": "/usr/bin:/bin"},
    )
    assert result.returncode == 0
    assert "ok" in result.stdout


def test_settings_proxy_delegates() -> None:
    from ocr_pipeline.config import settings

    assert settings.ocr.engine in {"tesseract", "paddleocr", "auto"}
    assert repr(settings)


def test_init_writes_local_config(tmp_path: Path, monkeypatch) -> None:
    _isolate_config(tmp_path, monkeypatch)
    result = runner.invoke(app, ["init", "--local"])
    assert result.exit_code == 0
    content = (tmp_path / "config.yaml").read_text(encoding="utf-8")
    assert "paths:" in content
    assert "tesseract" in content


def test_init_refuses_to_overwrite(tmp_path: Path, monkeypatch) -> None:
    _isolate_config(tmp_path, monkeypatch)
    (tmp_path / "config.yaml").write_text("existing: true\n", encoding="utf-8")
    result = runner.invoke(app, ["init", "--local"])
    assert result.exit_code == 1
    assert (tmp_path / "config.yaml").read_text(encoding="utf-8") == "existing: true\n"


def test_run_guard_without_config_or_input_dir(tmp_path: Path, monkeypatch) -> None:
    _isolate_config(tmp_path, monkeypatch)
    result = runner.invoke(app, ["run"])
    assert result.exit_code == 2
    assert "ocr-pipeline init" in result.output
    assert "ocr-pipeline demo" in result.output


def test_watch_guard_without_config(tmp_path: Path, monkeypatch) -> None:
    _isolate_config(tmp_path, monkeypatch)
    result = runner.invoke(app, ["watch"])
    assert result.exit_code == 2


def test_setup_dry_run_prints_steps_without_executing() -> None:
    result = runner.invoke(app, ["setup", "full", "--dry-run"])
    assert result.exit_code == 0
    assert "uv sync" in result.output or "pip install" in result.output


def test_setup_rejects_unknown_target() -> None:
    result = runner.invoke(app, ["setup", "everything", "--dry-run"])
    assert result.exit_code == 2


def test_demo_image_bundled_and_valid() -> None:
    from PIL import Image

    from ocr_pipeline.demo import demo_image_path

    with Image.open(demo_image_path()) as img:
        assert img.size[0] >= 800
        assert img.format == "PNG"
