"""Tests for `abreka exp session` command."""

from __future__ import annotations

from pathlib import Path
from unittest.mock import patch

from click.testing import CliRunner

from abreka.cli import main
from abreka.models import Experiment
from abreka.persistence import create_experiment_dir, save_experiment, update_index_entry
from abreka.stage_sessions import stage_session_path


def _seed_experiment_with_session(abreka_project: Path, exp_id: str, stage: str) -> Path:
    abreka_dir = abreka_project / "abreka"
    exp = Experiment(id=exp_id, hypothesis="test")
    create_experiment_dir(abreka_dir, exp_id)
    save_experiment(exp, abreka_dir)
    update_index_entry(abreka_dir, exp)
    session_path = stage_session_path(abreka_dir, exp_id, stage)
    session_path.parent.mkdir(parents=True, exist_ok=True)
    session_path.write_text('{"type":"session","version":3}\n')
    return session_path


class TestExpSession:
    def test_prints_session_path_by_default(self, abreka_project, monkeypatch):
        session_path = _seed_experiment_with_session(abreka_project, "0001", "implement")
        monkeypatch.chdir(abreka_project)
        runner = CliRunner()

        result = runner.invoke(main, ["exp", "session", "1", "implement"])

        assert result.exit_code == 0, result.output
        assert str(session_path) in result.output

    def test_open_launches_pi_with_session_file(self, abreka_project, monkeypatch):
        session_path = _seed_experiment_with_session(abreka_project, "0001", "test")
        monkeypatch.chdir(abreka_project)
        runner = CliRunner()
        execvp_calls = []

        def fake_execvp(file, args):
            execvp_calls.append((file, args))
            raise SystemExit(0)

        with (
            patch("shutil.which", return_value="/usr/bin/pi"),
            patch("os.execvp", side_effect=fake_execvp),
        ):
            result = runner.invoke(main, ["exp", "session", "1", "test", "--open"])

        assert result.exit_code == 0, result.output
        assert execvp_calls == [("pi", ["pi", "--session", str(session_path)])]

    def test_export_invokes_pi_export(self, abreka_project, monkeypatch, tmp_path):
        session_path = _seed_experiment_with_session(abreka_project, "0001", "evaluate")
        monkeypatch.chdir(abreka_project)
        runner = CliRunner()
        output_path = tmp_path / "session.html"

        with patch("subprocess.run") as mock_run:
            result = runner.invoke(
                main,
                ["exp", "session", "1", "evaluate", "--export", str(output_path)],
            )

        assert result.exit_code == 0, result.output
        mock_run.assert_called_once_with(
            ["pi", "--export", str(session_path), str(output_path)],
            check=True,
        )
        assert str(output_path) in result.output

    def test_missing_session_errors(self, abreka_project, monkeypatch):
        abreka_dir = abreka_project / "abreka"
        exp = Experiment(id="0001", hypothesis="test")
        create_experiment_dir(abreka_dir, "0001")
        save_experiment(exp, abreka_dir)
        update_index_entry(abreka_dir, exp)
        monkeypatch.chdir(abreka_project)
        runner = CliRunner()

        result = runner.invoke(main, ["exp", "session", "1", "propose"])

        assert result.exit_code != 0
        assert "No propose session found" in result.output
