"""
Test for task-131.1: Project Memory Separation in team_prompts.py and dispatch.py

This test module validates the project-specific memory separation functionality:
- Ensures system tasks use WORKSPACE_ROOT/memory/
- Ensures project tasks use PROJECTS_ROOT/{project_id}/memory/
- Verifies path formats for reports, plans, and isolation rules
"""

import json
import os
import tempfile
from pathlib import Path
from unittest import mock

import pytest

# Import modules to test
from prompts.team_prompts import build_prompt, TEAM_INFO
from dispatch import PROJECTS_ROOT, register_batch_task


class TestTeamPromptsProjectMemorySeparation:
    """Test team_prompts.py project memory separation functionality"""

    @pytest.fixture
    def temp_dirs(self):
        """Create temporary workspace and projects directories"""
        workspace_tmp = tempfile.mkdtemp()
        projects_tmp = tempfile.mkdtemp()

        # Create necessary subdirectories
        Path(workspace_tmp, "memory", "tasks").mkdir(parents=True, exist_ok=True)
        Path(workspace_tmp, "memory", "reports").mkdir(parents=True, exist_ok=True)
        Path(workspace_tmp, "memory", "events").mkdir(parents=True, exist_ok=True)
        Path(workspace_tmp, "teams", "dev1").mkdir(parents=True, exist_ok=True)
        Path(workspace_tmp, "teams", "dev3").mkdir(parents=True, exist_ok=True)

        # Create project directories
        Path(projects_tmp, "insuwiki", "memory", "reports").mkdir(parents=True, exist_ok=True)
        Path(projects_tmp, "insuwiki", "plans").mkdir(parents=True, exist_ok=True)

        yield {
            "workspace": workspace_tmp,
            "projects": projects_tmp,
        }

        # Cleanup
        import shutil
        shutil.rmtree(workspace_tmp, ignore_errors=True)
        shutil.rmtree(projects_tmp, ignore_errors=True)

    def test_system_task_report_path(self, temp_dirs):
        """Test that system tasks (project_id=None) use WORKSPACE_ROOT/memory/reports/"""
        with mock.patch.dict(
            os.environ,
            {
                "WORKSPACE_ROOT": temp_dirs["workspace"],
                "PROJECTS_ROOT": temp_dirs["projects"],
            },
        ):
            # Reimport to apply environment variable changes
            import importlib
            import prompts.team_prompts as team_prompts_module
            importlib.reload(team_prompts_module)

            task_id = "task-1.1"
            task_desc = "System task test"

            prompt = team_prompts_module.build_prompt(
                "dev1-team", task_id, task_desc, level="normal", project_id=None
            )

            expected_report_path = (
                f"{temp_dirs['workspace']}/memory/reports/{task_id}.md"
            )
            assert expected_report_path in prompt, (
                f"Expected report path {expected_report_path} not found in prompt"
            )

    def test_project_task_report_path(self, temp_dirs):
        """Test that project tasks use PROJECTS_ROOT/{project_id}/memory/reports/"""
        with mock.patch.dict(
            os.environ,
            {
                "WORKSPACE_ROOT": temp_dirs["workspace"],
                "PROJECTS_ROOT": temp_dirs["projects"],
            },
        ):
            import importlib
            import prompts.team_prompts as team_prompts_module
            importlib.reload(team_prompts_module)

            task_id = "task-2.1"
            task_desc = "Project task test"
            project_id = "insuwiki"

            prompt = team_prompts_module.build_prompt(
                "dev1-team", task_id, task_desc, level="normal", project_id=project_id
            )

            expected_report_path = (
                f"{temp_dirs['projects']}/{project_id}/memory/reports/{task_id}.md"
            )
            assert expected_report_path in prompt, (
                f"Expected report path {expected_report_path} not found in prompt"
            )

    def test_system_task_plan_path(self, temp_dirs):
        """Test that system tasks (project_id=None) use teams/dev{N}/plan-{task_id}.md format"""
        with mock.patch.dict(
            os.environ,
            {
                "WORKSPACE_ROOT": temp_dirs["workspace"],
                "PROJECTS_ROOT": temp_dirs["projects"],
            },
        ):
            import importlib
            import prompts.team_prompts as team_prompts_module
            importlib.reload(team_prompts_module)

            task_id = "task-1.1"
            task_desc = "System task with plan"

            prompt = team_prompts_module.build_prompt(
                "dev1-team", task_id, task_desc, level="normal", project_id=None
            )

            expected_plan_path = f"teams/dev1/plan-{task_id}.md"
            assert expected_plan_path in prompt, (
                f"Expected plan path {expected_plan_path} not found in prompt"
            )

    def test_project_task_plan_path(self, temp_dirs):
        """Test that project tasks use projects/{project_id}/plans/plan-{task_id}.md format"""
        with mock.patch.dict(
            os.environ,
            {
                "WORKSPACE_ROOT": temp_dirs["workspace"],
                "PROJECTS_ROOT": temp_dirs["projects"],
            },
        ):
            import importlib
            import prompts.team_prompts as team_prompts_module
            importlib.reload(team_prompts_module)

            task_id = "task-2.1"
            task_desc = "Project task with plan"
            project_id = "insuwiki"

            prompt = team_prompts_module.build_prompt(
                "dev1-team", task_id, task_desc, level="normal", project_id=project_id
            )

            expected_plan_path = f"projects/{project_id}/plans/plan-{task_id}.md"
            assert expected_plan_path in prompt, (
                f"Expected plan path {expected_plan_path} not found in prompt"
            )

    def test_glm_project_plan_path(self, temp_dirs):
        """Test dev3-team + project_id uses projects/{project_id}/plans/plan-{task_id}.md format"""
        with mock.patch.dict(
            os.environ,
            {
                "WORKSPACE_ROOT": temp_dirs["workspace"],
                "PROJECTS_ROOT": temp_dirs["projects"],
            },
        ):
            import importlib
            import prompts.team_prompts as team_prompts_module
            importlib.reload(team_prompts_module)

            task_id = "task-3.1"
            task_desc = "GLM project task with plan"
            project_id = "insuwiki"

            prompt = team_prompts_module.build_prompt(
                "dev3-team", task_id, task_desc, level="normal", project_id=project_id
            )

            expected_plan_path = f"projects/{project_id}/plans/plan-{task_id}.md"
            assert expected_plan_path in prompt, (
                f"Expected plan path {expected_plan_path} not found in prompt for dev3-team"
            )

    def test_project_isolation_rule_uses_projects_root(self, temp_dirs):
        """Test that project tasks use PROJECTS_ROOT in isolation rule (not WORKSPACE_ROOT)"""
        with mock.patch.dict(
            os.environ,
            {
                "WORKSPACE_ROOT": temp_dirs["workspace"],
                "PROJECTS_ROOT": temp_dirs["projects"],
            },
        ):
            import importlib
            import prompts.team_prompts as team_prompts_module
            importlib.reload(team_prompts_module)

            task_id = "task-2.1"
            task_desc = "Project isolation test"
            project_id = "insuwiki"

            prompt = team_prompts_module.build_prompt(
                "dev1-team", task_id, task_desc, level="normal", project_id=project_id
            )

            # Check that PROJECTS_ROOT is in the isolation rule
            expected_isolation = (
                f"{temp_dirs['projects']}/{project_id}/"
            )
            assert expected_isolation in prompt, (
                f"Expected PROJECTS_ROOT path {expected_isolation} not found in isolation rule"
            )

            # Ensure WORKSPACE_ROOT is NOT in the isolation rule for project tasks
            # (it should be in general rules but not as the project isolation path)
            # The isolation rule should use PROJECTS_ROOT specifically
            assert "프로젝트 격리" in prompt, "Project isolation rule marker not found"

    def test_system_task_paths_unchanged(self, temp_dirs):
        """Test that system tasks (project_id=None) use existing WORKSPACE_ROOT/memory/ paths"""
        with mock.patch.dict(
            os.environ,
            {
                "WORKSPACE_ROOT": temp_dirs["workspace"],
                "PROJECTS_ROOT": temp_dirs["projects"],
            },
        ):
            import importlib
            import prompts.team_prompts as team_prompts_module
            importlib.reload(team_prompts_module)

            task_id = "task-1.1"
            task_desc = "System task paths test"

            prompt = team_prompts_module.build_prompt(
                "dev1-team", task_id, task_desc, level="normal", project_id=None
            )

            # System tasks should use WORKSPACE_ROOT for memory paths
            assert f"{temp_dirs['workspace']}/memory/" in prompt, (
                "WORKSPACE_ROOT memory path not found for system task"
            )

            # Check done_file path
            expected_done_file = f"{temp_dirs['workspace']}/memory/events/{task_id}.done"
            assert expected_done_file in prompt, (
                f"Expected done_file path {expected_done_file} not found in prompt"
            )

            # Check task_file path
            expected_task_file = f"{temp_dirs['workspace']}/memory/tasks/{task_id}.md"
            assert expected_task_file in prompt, (
                f"Expected task_file path {expected_task_file} not found in prompt"
            )


class TestDispatchProjectMemorySeparation:
    """Test dispatch.py project memory separation functionality"""

    def test_projects_root_variable_exists(self):
        """Test that dispatch.py defines PROJECTS_ROOT variable"""
        import dispatch as dispatch_module

        assert hasattr(dispatch_module, "PROJECTS_ROOT"), (
            "dispatch.py must define PROJECTS_ROOT variable"
        )
        assert isinstance(dispatch_module.PROJECTS_ROOT, Path), (
            "PROJECTS_ROOT should be a Path object"
        )

    @pytest.fixture
    def temp_dispatch_dirs(self):
        """Create temporary workspace and projects directories for dispatch tests"""
        workspace_tmp = tempfile.mkdtemp()
        projects_tmp = tempfile.mkdtemp()

        # Create necessary subdirectories
        Path(workspace_tmp, "memory", "batches").mkdir(parents=True, exist_ok=True)
        Path(projects_tmp, "insuwiki", "memory", "reports").mkdir(
            parents=True, exist_ok=True
        )

        yield {
            "workspace": workspace_tmp,
            "projects": projects_tmp,
        }

        # Cleanup
        import shutil
        shutil.rmtree(workspace_tmp, ignore_errors=True)
        shutil.rmtree(projects_tmp, ignore_errors=True)

    def test_register_batch_task_with_project_id(self, temp_dispatch_dirs):
        """Test that register_batch_task accepts and uses project_id parameter"""
        with mock.patch.dict(
            os.environ,
            {
                "WORKSPACE_ROOT": temp_dispatch_dirs["workspace"],
                "PROJECTS_ROOT": temp_dispatch_dirs["projects"],
            },
        ):
            import importlib
            import dispatch as dispatch_module
            importlib.reload(dispatch_module)

            batch_id = "batch-20260302-001"
            task_id = "task-1.1"
            team_id = "dev1-team"
            project_id = "insuwiki"

            # Call register_batch_task with project_id
            dispatch_module.register_batch_task(
                batch_id, task_id, team_id, project_id=project_id
            )

            # Verify batch file was created
            batch_file = (
                Path(temp_dispatch_dirs["workspace"])
                / "memory"
                / "batches"
                / f"{batch_id}.json"
            )
            assert batch_file.exists(), f"Batch file {batch_file} was not created"

            # Verify batch data contains correct project-specific report path
            with open(batch_file, "r", encoding="utf-8") as f:
                batch_data = json.load(f)

            assert "tasks" in batch_data, "Batch data should contain 'tasks' array"
            assert len(batch_data["tasks"]) > 0, "Tasks array should not be empty"

            task_entry = batch_data["tasks"][0]
            assert task_entry["task_id"] == task_id
            assert task_entry["team"] == team_id

            expected_report_path = (
                f"{temp_dispatch_dirs['projects']}/{project_id}/memory/reports/{task_id}.md"
            )
            assert task_entry["report_path"] == expected_report_path, (
                f"Expected report_path {expected_report_path}, got {task_entry['report_path']}"
            )

    def test_register_batch_task_without_project_id(self, temp_dispatch_dirs):
        """Test that register_batch_task works without project_id (system tasks)"""
        with mock.patch.dict(
            os.environ,
            {
                "WORKSPACE_ROOT": temp_dispatch_dirs["workspace"],
                "PROJECTS_ROOT": temp_dispatch_dirs["projects"],
            },
        ):
            import importlib
            import dispatch as dispatch_module
            importlib.reload(dispatch_module)

            batch_id = "batch-20260302-002"
            task_id = "task-1.2"
            team_id = "dev1-team"

            # Call register_batch_task without project_id
            dispatch_module.register_batch_task(batch_id, task_id, team_id)

            # Verify batch file was created
            batch_file = (
                Path(temp_dispatch_dirs["workspace"])
                / "memory"
                / "batches"
                / f"{batch_id}.json"
            )
            assert batch_file.exists(), f"Batch file {batch_file} was not created"

            # Verify batch data uses system memory path
            with open(batch_file, "r", encoding="utf-8") as f:
                batch_data = json.load(f)

            task_entry = batch_data["tasks"][0]
            expected_report_path = f"memory/reports/{task_id}.md"
            assert task_entry["report_path"] == expected_report_path, (
                f"Expected report_path {expected_report_path}, got {task_entry['report_path']}"
            )


class TestPathFormats:
    """Test path format consistency across teams and project types"""

    @pytest.fixture
    def temp_path_dirs(self):
        """Create temporary directories for path format tests"""
        workspace_tmp = tempfile.mkdtemp()
        projects_tmp = tempfile.mkdtemp()

        # Create necessary subdirectories
        Path(workspace_tmp, "memory", "tasks").mkdir(parents=True, exist_ok=True)
        Path(workspace_tmp, "memory", "reports").mkdir(parents=True, exist_ok=True)
        Path(workspace_tmp, "teams", "dev1").mkdir(parents=True, exist_ok=True)
        Path(workspace_tmp, "teams", "dev2").mkdir(parents=True, exist_ok=True)
        Path(workspace_tmp, "teams", "dev3").mkdir(parents=True, exist_ok=True)

        # Create project directories
        Path(projects_tmp, "insuwiki", "memory", "reports").mkdir(
            parents=True, exist_ok=True
        )
        Path(projects_tmp, "insuwiki", "plans").mkdir(parents=True, exist_ok=True)
        Path(projects_tmp, "project2", "memory", "reports").mkdir(
            parents=True, exist_ok=True
        )
        Path(projects_tmp, "project2", "plans").mkdir(parents=True, exist_ok=True)

        yield {
            "workspace": workspace_tmp,
            "projects": projects_tmp,
        }

        # Cleanup
        import shutil
        shutil.rmtree(workspace_tmp, ignore_errors=True)
        shutil.rmtree(projects_tmp, ignore_errors=True)

    def test_dev1_team_system_paths(self, temp_path_dirs):
        """Test dev1-team system task paths"""
        with mock.patch.dict(
            os.environ,
            {
                "WORKSPACE_ROOT": temp_path_dirs["workspace"],
                "PROJECTS_ROOT": temp_path_dirs["projects"],
            },
        ):
            import importlib
            import prompts.team_prompts as team_prompts_module
            importlib.reload(team_prompts_module)

            task_id = "task-1.1"
            prompt = team_prompts_module.build_prompt(
                "dev1-team", task_id, "Test task", project_id=None
            )

            assert "teams/dev1/plan-" in prompt
            assert f"{temp_path_dirs['workspace']}/memory/reports/" in prompt

    def test_dev2_team_system_paths(self, temp_path_dirs):
        """Test dev2-team system task paths"""
        with mock.patch.dict(
            os.environ,
            {
                "WORKSPACE_ROOT": temp_path_dirs["workspace"],
                "PROJECTS_ROOT": temp_path_dirs["projects"],
            },
        ):
            import importlib
            import prompts.team_prompts as team_prompts_module
            importlib.reload(team_prompts_module)

            task_id = "task-1.1"
            prompt = team_prompts_module.build_prompt(
                "dev2-team", task_id, "Test task", project_id=None
            )

            assert "teams/dev2/plan-" in prompt
            assert f"{temp_path_dirs['workspace']}/memory/reports/" in prompt

    def test_dev3_team_system_paths(self, temp_path_dirs):
        """Test dev3-team system task paths"""
        with mock.patch.dict(
            os.environ,
            {
                "WORKSPACE_ROOT": temp_path_dirs["workspace"],
                "PROJECTS_ROOT": temp_path_dirs["projects"],
            },
        ):
            import importlib
            import prompts.team_prompts as team_prompts_module
            importlib.reload(team_prompts_module)

            task_id = "task-1.1"
            prompt = team_prompts_module.build_prompt(
                "dev3-team", task_id, "Test task", project_id=None
            )

            assert "teams/dev3/plan-" in prompt
            assert f"{temp_path_dirs['workspace']}/memory/reports/" in prompt

    def test_all_teams_project_paths(self, temp_path_dirs):
        """Test that all teams use consistent project paths"""
        with mock.patch.dict(
            os.environ,
            {
                "WORKSPACE_ROOT": temp_path_dirs["workspace"],
                "PROJECTS_ROOT": temp_path_dirs["projects"],
            },
        ):
            import importlib
            import prompts.team_prompts as team_prompts_module
            importlib.reload(team_prompts_module)

            project_id = "insuwiki"
            task_id = "task-1.1"

            for team_id in ["dev1-team", "dev2-team", "dev3-team"]:
                prompt = team_prompts_module.build_prompt(
                    team_id, task_id, "Test task", project_id=project_id
                )

                # All teams should use projects/ path for project tasks
                expected_report = (
                    f"{temp_path_dirs['projects']}/{project_id}/memory/reports/"
                )
                expected_plan = f"projects/{project_id}/plans/plan-"

                assert expected_report in prompt, (
                    f"{team_id} should use projects report path"
                )
                assert expected_plan in prompt, (
                    f"{team_id} should use projects plan path"
                )


class TestMemorySeparationIntegration:
    """Integration tests for memory separation across system and project"""

    @pytest.fixture
    def temp_integration_dirs(self):
        """Create temporary directories for integration tests"""
        workspace_tmp = tempfile.mkdtemp()
        projects_tmp = tempfile.mkdtemp()

        # Create comprehensive directory structure
        for subdir in ["memory/tasks", "memory/reports", "memory/events", "teams/dev1", "teams/dev2", "teams/dev3"]:
            Path(workspace_tmp, subdir).mkdir(parents=True, exist_ok=True)

        for proj in ["insuwiki", "project2"]:
            for subdir in ["memory/reports", "plans"]:
                Path(projects_tmp, proj, subdir).mkdir(parents=True, exist_ok=True)

        yield {
            "workspace": workspace_tmp,
            "projects": projects_tmp,
        }

        # Cleanup
        import shutil
        shutil.rmtree(workspace_tmp, ignore_errors=True)
        shutil.rmtree(projects_tmp, ignore_errors=True)

    def test_system_and_project_tasks_isolated(self, temp_integration_dirs):
        """Test that system and project tasks have completely isolated memory paths"""
        with mock.patch.dict(
            os.environ,
            {
                "WORKSPACE_ROOT": temp_integration_dirs["workspace"],
                "PROJECTS_ROOT": temp_integration_dirs["projects"],
            },
        ):
            import importlib
            import prompts.team_prompts as team_prompts_module
            importlib.reload(team_prompts_module)

            task_id = "task-1.1"

            # Get prompts for system and project tasks
            system_prompt = team_prompts_module.build_prompt(
                "dev1-team", task_id, "System task", project_id=None
            )
            project_prompt = team_prompts_module.build_prompt(
                "dev1-team", task_id, "Project task", project_id="insuwiki"
            )

            # System should use WORKSPACE_ROOT
            assert f"{temp_integration_dirs['workspace']}/memory/reports" in system_prompt
            assert temp_integration_dirs["projects"] not in system_prompt or "격리" not in system_prompt

            # Project should use PROJECTS_ROOT
            assert f"{temp_integration_dirs['projects']}/insuwiki" in project_prompt

    def test_multiple_projects_use_different_paths(self, temp_integration_dirs):
        """Test that different projects use different memory paths"""
        with mock.patch.dict(
            os.environ,
            {
                "WORKSPACE_ROOT": temp_integration_dirs["workspace"],
                "PROJECTS_ROOT": temp_integration_dirs["projects"],
            },
        ):
            import importlib
            import prompts.team_prompts as team_prompts_module
            importlib.reload(team_prompts_module)

            task_id = "task-1.1"

            # Get prompts for different projects
            insuwiki_prompt = team_prompts_module.build_prompt(
                "dev1-team", task_id, "InsuWiki task", project_id="insuwiki"
            )
            project2_prompt = team_prompts_module.build_prompt(
                "dev1-team", task_id, "Project2 task", project_id="project2"
            )

            # Each should use its own project directory
            assert f"{temp_integration_dirs['projects']}/insuwiki" in insuwiki_prompt
            assert f"{temp_integration_dirs['projects']}/project2" in project2_prompt

            # Ensure isolation rule references correct project
            assert "insuwiki" in insuwiki_prompt
            assert "project2" in project2_prompt


if __name__ == "__main__":
    pytest.main([__file__, "-v"])
