import json
import unittest
from pathlib import Path
from tempfile import TemporaryDirectory
from unittest.mock import patch

from mixersystem.__main__ import main


def _setup_project(root: Path, team_prefix: str = "ENG") -> None:
    (root / "app").mkdir(parents=True, exist_ok=True)
    (root / "app" / "_app.md").write_text("# App\n")

    settings = {
        "modules": {
            "app": {
                "doc": "./app/_app.md",
                "children": {},
            }
        },
        "linear": {
            "team_prefix": team_prefix,
            "team_id": "",
        },
    }
    (root / ".mixer").mkdir(parents=True, exist_ok=True)
    (root / ".mixer" / "settings.json").write_text(json.dumps(settings, indent=2) + "\n")


class TaskLinearPrefixTest(unittest.TestCase):
    def test_settings_prefix_triggers_linear_path(self) -> None:
        with TemporaryDirectory() as tmpdir:
            root = Path(tmpdir)
            _setup_project(root, team_prefix="ENG")

            def fake_load(issue_id: str, task_path: str, api_key: str | None = None) -> str:
                Path(task_path).parent.mkdir(parents=True, exist_ok=True)
                Path(task_path).write_text("# Imported from Linear\n")
                return task_path

            with patch("mixersystem.workflows.task.create_task.linear_sync.load", side_effect=fake_load) as load_mock:
                code = main(
                    [
                        "run",
                        "task",
                        f"--project_root={tmpdir}",
                        "--session_folder=./.mixer/sessions/ENG-101",
                        "--modules=app",
                    ]
                )
            self.assertEqual(code, 0)
            load_mock.assert_called_once()

    def test_non_matching_prefix_is_local_and_requires_description(self) -> None:
        with TemporaryDirectory() as tmpdir:
            root = Path(tmpdir)
            _setup_project(root, team_prefix="ENG")

            with self.assertRaisesRegex(ValueError, "description is required for local tasks"):
                main(
                    [
                        "run",
                        "task",
                        f"--project_root={tmpdir}",
                        "--session_folder=./.mixer/sessions/ABC-101",
                        "--modules=app",
                    ]
                )

    def test_mismatched_task_prefix_is_local(self) -> None:
        with TemporaryDirectory() as tmpdir:
            root = Path(tmpdir)
            _setup_project(root, team_prefix="ENG")

            with self.assertRaisesRegex(ValueError, "description is required for local tasks"):
                main(
                    [
                        "run",
                        "task",
                        f"--project_root={tmpdir}",
                        "--session_folder=./.mixer/sessions/ENG-101",
                        "--task_prefix=TST",
                        "--modules=app",
                    ]
                )

    def test_task_prefix_without_settings_prefix_is_local(self) -> None:
        with TemporaryDirectory() as tmpdir:
            root = Path(tmpdir)
            _setup_project(root, team_prefix="")

            def fake_load(issue_id: str, task_path: str, api_key: str | None = None) -> str:
                Path(task_path).parent.mkdir(parents=True, exist_ok=True)
                Path(task_path).write_text("# Imported from Linear\n")
                return task_path

            with patch("mixersystem.workflows.task.create_task.linear_sync.load", side_effect=fake_load) as load_mock:
                code = main(
                    [
                        "run",
                        "task",
                        f"--project_root={tmpdir}",
                        "--session_folder=./.mixer/sessions/TST-101",
                        "--task_prefix=TST",
                        "--description=Local task description",
                        "--modules=app",
                    ]
                )
            self.assertEqual(code, 0)
            load_mock.assert_not_called()

    def test_existing_local_task_without_description(self) -> None:
        with TemporaryDirectory() as tmpdir:
            root = Path(tmpdir)
            _setup_project(root, team_prefix="ENG")
            task_dir = root / ".mixer" / "sessions" / "test-003"
            task_dir.mkdir(parents=True, exist_ok=True)
            (task_dir / "task.md").write_text(
                "---\n"
                "name: json-output-format\n"
                "modules:\n"
                "  - app\n"
                "---\n\n"
                "# Existing Task\n\n"
                "## Description\n\n"
                "Existing description.\n"
            )

            with patch("mixersystem.workflows.task.create_task.linear_sync.load") as load_mock:
                code = main(
                    [
                        "run",
                        "task",
                        f"--project_root={tmpdir}",
                        "--session_folder=./.mixer/sessions/test-003",
                        "--task_prefix=test",
                    ]
                )
            self.assertEqual(code, 0)
            load_mock.assert_not_called()


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