import io
import unittest
from contextlib import redirect_stdout
from unittest.mock import patch

from mixersystem import __version__
from mixersystem.__main__ import main
from mixersystem.workflows.work.create_work import run as run_work_workflow
from mixersystem.workflows.plan.create_plan import run as run_plan_workflow
from mixersystem.workflows.task.create_task import run as run_task_workflow


class CLITest(unittest.TestCase):
    def test_version(self) -> None:
        out = io.StringIO()
        with redirect_stdout(out):
            code = main(["--version"])
        self.assertEqual(code, 0)
        self.assertEqual(out.getvalue().strip(), __version__)

    @patch("mixersystem.__main__.sync")
    def test_sync_calls_sync(self, sync_mock) -> None:
        code = main(["sync", "--project_root=/tmp/project"])
        self.assertEqual(code, 0)
        sync_mock.assert_called_once_with(project_root="/tmp/project")

    @patch("mixersystem.__main__.sync")
    def test_init_calls_sync(self, sync_mock) -> None:
        out = io.StringIO()
        with redirect_stdout(out):
            code = main(["init", "--project_root=/tmp/project"])
        self.assertEqual(code, 0)
        sync_mock.assert_called_once_with(project_root="/tmp/project")
        self.assertIn("Initialized MixerSystem runtime", out.getvalue())

    @patch("mixersystem.__main__.run_cli")
    def test_run_task_dispatches(self, run_cli_mock) -> None:
        code = main(
            [
                "run",
                "task",
                "--session_folder=./.mixer/sessions/local-001",
                "--task_prefix=TST",
                "--description=smoke",
            ]
        )
        self.assertEqual(code, 0)
        run_cli_mock.assert_called_once_with(run_task_workflow)

    @patch("mixersystem.__main__.run_cli")
    def test_create_plan_alias_dispatches(self, run_cli_mock) -> None:
        code = main(["create-plan", "--session_folder=./.mixer/sessions/task-001"])
        self.assertEqual(code, 0)
        run_cli_mock.assert_called_once_with(run_plan_workflow)

    @patch("mixersystem.__main__.run_cli")
    def test_work_alias_dispatches(self, run_cli_mock) -> None:
        code = main(["work", "--session_folder=./.mixer/sessions/task-001"])
        self.assertEqual(code, 0)
        run_cli_mock.assert_called_once_with(run_work_workflow)

    def test_run_requires_workflow_name(self) -> None:
        code = main(["run"])
        self.assertEqual(code, 1)

    def test_run_unknown_workflow(self) -> None:
        code = main(["run", "unknown", "--session_folder=./.mixer/sessions/task-001"])
        self.assertEqual(code, 1)

    def test_sync_rejects_unknown_arg(self) -> None:
        code = main(["sync", "--foo=bar"])
        self.assertEqual(code, 1)


if __name__ == "__main__":
    unittest.main()
