"""Functional tests for pysourcepack."""

from __future__ import annotations

from pathlib import Path

import pytest

from ..components.sourcepacker import PySourcePacker, main


@pytest.fixture
def sample_project_structure(tmp_path: Path) -> tuple[Path, Path]:
    """Create a sample project structure for testing."""
    # Create project directory
    project_dir = tmp_path / "sample_project"
    project_dir.mkdir()

    # Create pyproject.toml
    pyproject_content = """[project]
name = "sample_project"
version = "1.0.0"
description = "A sample project for testing"
readme = "README.md"
requires-python = ">=3.8"
dependencies = []
"""
    (project_dir / "pyproject.toml").write_text(pyproject_content, encoding="utf-8")

    # Create source files
    (project_dir / "main.py").write_text("def main():\n    print('Hello World')\n", encoding="utf-8")
    (project_dir / "utils.py").write_text("# Utility functions\n", encoding="utf-8")
    (project_dir / "README.md").write_text("# Sample Project\n", encoding="utf-8")

    # Create excluded directories/files
    (project_dir / "tests").mkdir()
    (project_dir / "tests" / "test_main.py").write_text("def test_main(): pass\n", encoding="utf-8")

    (project_dir / "__pycache__").mkdir()
    (project_dir / "__pycache__" / "main.cpython-38.pyc").write_text("", encoding="utf-8")

    return tmp_path, project_dir


class TestFunctional:
    """Functional tests for pysourcepack."""

    def test_pack_single_project(self, sample_project_structure):
        """Test packing a single project."""
        root_dir, _project_dir = sample_project_structure

        # Create another directory to simulate multi-project structure
        other_project = root_dir / "other_project"
        other_project.mkdir()
        (other_project / "pyproject.toml").write_text("[project]\nname = 'other'\n", encoding="utf-8")

        packer = PySourcePacker(root_dir=root_dir)
        result = packer.pack_project("sample_project")

        assert result is True

        # Check that output directory was created
        output_dir = root_dir / "dist" / "src" / "sample_project"
        assert output_dir.exists()

        # Check that included files were copied
        assert (output_dir / "main.py").exists()
        assert (output_dir / "utils.py").exists()
        assert (output_dir / "README.md").exists()
        assert (output_dir / "pyproject.toml").exists()

        # Check that excluded files/directories were not copied
        assert not (output_dir / "tests").exists()
        assert not (output_dir / "__pycache__").exists()

    def test_pack_all_projects(self, sample_project_structure):
        """Test packing all projects."""
        root_dir, _project_dir = sample_project_structure

        packer = PySourcePacker(root_dir=root_dir)

        # Mock the run method to avoid actual execution
        with pytest.MonkeyPatch().context() as m:
            m.setattr(
                "pytola.dev.pypack.components.sourcepacker.PySourcePacker.pack_project",
                lambda self, name: True,
            )

            # This should not raise an exception
            packer.run()

    def test_pack_nonexistent_project(self, tmp_path: Path):
        """Test packing a non-existent project."""
        packer = PySourcePacker(root_dir=tmp_path)
        result = packer.pack_project("nonexistent")
        assert result is False

    def test_with_custom_patterns(self, sample_project_structure):
        """Test packing with custom include/exclude patterns."""
        root_dir, _project_dir = sample_project_structure

        # Custom patterns: include only .py files, exclude utils.py
        custom_include = {"*.py"}
        custom_exclude = {"utils.py", "tests", "__pycache__"}

        packer = PySourcePacker(
            root_dir=root_dir,
            include_patterns=custom_include,
            exclude_patterns=custom_exclude,
        )

        result = packer.pack_project("sample_project")
        assert result is True

        output_dir = root_dir / "dist" / "src" / "sample_project"

        # Should include main.py
        assert (output_dir / "main.py").exists()
        # Should exclude utils.py due to custom exclude pattern
        assert not (output_dir / "utils.py").exists()
        # Should exclude README.md due to custom include pattern
        assert not (output_dir / "README.md").exists()


def test_main_entry_point():
    """Test that main function can be imported and exists."""
    assert callable(main)
