"""
Test cases for the main initialization module.

Tests cover:
- Successful template directory copying
- Skipping existing directories (idempotency)
- Error handling for missing templates
- Console output validation
"""

import shutil
import sys
from pathlib import Path
from unittest.mock import patch, MagicMock

import pytest

from dsai_synapsis_agent_init.main import run, FOLDERS_TO_INIT


class TestTemplateInitialization:
    """Test suite for template initialization logic."""

    @pytest.fixture
    def temp_work_dir(self, tmp_path):
        """Create a temporary working directory for tests."""
        original_cwd = Path.cwd()
        work_dir = tmp_path / "work"
        work_dir.mkdir()
        yield work_dir
        # Cleanup: restore original directory
        if Path.cwd() != original_cwd:
            import os
            os.chdir(original_cwd)

    def test_folders_to_init_defined(self):
        """Test that FOLDERS_TO_INIT contains expected folder names."""
        assert isinstance(FOLDERS_TO_INIT, (list, tuple))
        assert ".agent" in FOLDERS_TO_INIT
        assert ".agents" in FOLDERS_TO_INIT
        assert ".claude" in FOLDERS_TO_INIT
        assert len(FOLDERS_TO_INIT) == 3

    def test_run_function_exists_and_callable(self):
        """Test that run function is properly defined and callable."""
        assert callable(run)

    @patch("dsai_synapsis_agent_init.main.files")
    @patch("dsai_synapsis_agent_init.main.Path.cwd")
    @patch("builtins.print")
    def test_run_prints_startup_message(self, mock_print, mock_cwd, mock_files):
        """Test that run() prints the startup message."""
        mock_cwd.return_value = Path("/tmp/work")
        mock_pkg = MagicMock()
        mock_files.return_value = mock_pkg

        # Mock the templates folder to have the required subdirectories
        for folder in FOLDERS_TO_INIT:
            mock_folder = MagicMock()
            mock_folder.exists.return_value = False
            setattr(mock_pkg, "__truediv__", lambda self, x: MagicMock(exists=MagicMock(return_value=False)))

        run()
        # Check that startup message was printed
        calls = [str(call) for call in mock_print.call_args_list]
        assert any("🚀" in str(call) for call in calls), "Startup message not printed"

    @patch("dsai_synapsis_agent_init.main.files")
    @patch("dsai_synapsis_agent_init.main.Path.cwd")
    @patch("dsai_synapsis_agent_init.main.shutil.copytree")
    @patch("builtins.print")
    def test_run_processes_existing_directories(self, mock_print, mock_copytree, mock_cwd, mock_files):
        """Test that run() processes directories that already exist instead of skipping."""
        mock_cwd.return_value = Path("/tmp/work")
        mock_pkg = MagicMock()
        mock_templates = MagicMock()
        mock_files.return_value = mock_templates

        # Should attempt to copy even if destination exists (dirs_exist_ok=True)
        with patch("dsai_synapsis_agent_init.main.Path.exists", return_value=True):
            run()
            assert mock_copytree.call_count == len(FOLDERS_TO_INIT)
            for call in mock_copytree.call_args_list:
                assert call.kwargs.get('dirs_exist_ok') is True


    @patch("dsai_synapsis_agent_init.main.files")
    @patch("dsai_synapsis_agent_init.main.Path.cwd")
    @patch("dsai_synapsis_agent_init.main.shutil.copytree")
    @patch("builtins.print")
    def test_run_merges_into_existing_directories(self, mock_print, mock_copytree, mock_cwd, mock_files):
        """Test that run() merges files into existing directories instead of skipping."""
        mock_cwd.return_value = Path("/tmp/work")
        mock_pkg = MagicMock()
        mock_files.return_value = mock_pkg

        # Mock that all folders exist in destination
        # We need to mock Path.exists for the destination paths
        with patch("dsai_synapsis_agent_init.main.Path.exists", return_value=True):
            run()
            
            # Should NOT print "sudah ada, dilewati"
            calls = [str(call) for call in mock_print.call_args_list]
            assert not any("dilewati" in str(call) for call in calls)
            
            # Should call copytree for all folders with dirs_exist_ok=True
            assert mock_copytree.call_count == len(FOLDERS_TO_INIT)
            for call in mock_copytree.call_args_list:
                assert call.kwargs.get('dirs_exist_ok') is True

class TestDocumentation:
    """Test suite for code documentation."""

    def test_main_module_has_docstring(self):
        """Test that main module is properly documented."""
        from dsai_synapsis_agent_init import main
        assert main.__doc__ is not None
        assert len(main.__doc__) > 0

    def test_run_function_has_docstring(self):
        """Test that run() function has clear documentation."""
        from dsai_synapsis_agent_init.main import run
        assert run.__doc__ is not None
        assert len(run.__doc__) > 0


class TestErrorHandling:
    """Test suite for error handling and edge cases."""

    @patch("dsai_synapsis_agent_init.main.files")
    @patch("dsai_synapsis_agent_init.main.Path.cwd")
    @patch("builtins.print")
    def test_git_warning_if_no_git_dir(self, mock_print, mock_cwd, mock_files):
        """Test that a warning is printed if .git directory is not found."""
        temp_dir = Path("/tmp/work")
        mock_cwd.return_value = temp_dir
        
        mock_pkg = MagicMock()
        mock_files.return_value = mock_pkg
        
        # Mock template_base / folder_name to return something that exists or not, 
        # but we care about the git check which should happen before or during run
        
        run()
        
        # Check that warning message about .git was printed
        # Note: We need to implement this in main.py for it to pass
        calls = [str(call) for call in mock_print.call_args_list]
        assert any("⚠️  Direktori .git tidak ditemukan" in str(call) for call in [c[0][0] for c in mock_print.call_args_list if c[0]])

    @patch("dsai_synapsis_agent_init.main.files")
    def test_missing_package_resources_handled(self, mock_files):
        """Test that missing package resources are handled gracefully."""
        mock_files.side_effect = Exception("Package resources not found")

        with patch("builtins.print"):
            with patch("sys.exit") as mock_exit:
                run()
                # Should call sys.exit on resource error
                mock_exit.assert_called()

    @patch("dsai_synapsis_agent_init.main.files")
    @patch("dsai_synapsis_agent_init.main.Path.cwd")
    @patch("dsai_synapsis_agent_init.main.shutil.copytree")
    def test_copy_error_handled(self, mock_copytree, mock_cwd, mock_files):
        """Test that copy errors are handled without crashing."""
        mock_copytree.side_effect = OSError("Permission denied")
        mock_cwd.return_value = Path("/tmp/work")
        mock_pkg = MagicMock()
        mock_files.return_value = mock_pkg

        # Should not raise exception
        with patch("builtins.print"):
            run()
