#!/usr/bin/env python3
# (c) 2024-26 Prof. Flavio ABREU ARAUJO. All rights reserved.
#
# Unit tests for git-aware OTA deployment


from neng_wifi_tools.ota_client import GitDeployManager, GitToDeviceMapper  # type: ignore


class TestGitToDeviceMapper:
    """Test git path to device path mapping."""

    def setup_method(self):
        """Setup test fixtures."""
        self.mapper = GitToDeviceMapper()

    def test_application_file_mapping(self):
        """Test mapping of application files from TMP117/CircuitPython/."""
        # Python files
        assert self.mapper.git_to_device_path("TMP117/CircuitPython/code.py") == "/code.py"
        assert (
            self.mapper.git_to_device_path("TMP117/CircuitPython/code_pid_async.py")
            == "/code_pid_async.py"
        )
        assert self.mapper.git_to_device_path("TMP117/CircuitPython/boot.py") == "/boot.py"

        # Config files
        assert (
            self.mapper.git_to_device_path("TMP117/CircuitPython/wifi_config.json")
            == "/wifi_config.json"
        )
        assert (
            self.mapper.git_to_device_path("TMP117/CircuitPython/settings.toml") == "/settings.toml"
        )
        assert (
            self.mapper.git_to_device_path("TMP117/CircuitPython/usb_config.txt")
            == "/usb_config.txt"
        )

    def test_library_file_mapping(self):
        """Test mapping of library files from neng_* modules."""
        # neng_scpi_base library
        assert (
            self.mapper.git_to_device_path("neng_scpi_base/ota_scpi_server.py")
            == "/lib/neng_scpi_base/ota_scpi_server.py"
        )
        assert (
            self.mapper.git_to_device_path("neng_scpi_base/scpi_server.py")
            == "/lib/neng_scpi_base/scpi_server.py"
        )
        assert (
            self.mapper.git_to_device_path("neng_scpi_base/__init__.py")
            == "/lib/neng_scpi_base/__init__.py"
        )

        # neng_tmp117 library
        assert (
            self.mapper.git_to_device_path("neng_tmp117/tmp117_scpi_server.py")
            == "/lib/neng_tmp117/tmp117_scpi_server.py"
        )
        assert (
            self.mapper.git_to_device_path("neng_tmp117/__init__.py")
            == "/lib/neng_tmp117/__init__.py"
        )

        # neng_pid_controller library
        assert (
            self.mapper.git_to_device_path("neng_pid_controller/pid_controller.py")
            == "/lib/neng_pid_controller/pid_controller.py"
        )

    def test_excluded_files(self):
        """Test that excluded files return None."""
        # Documentation
        assert self.mapper.git_to_device_path("TMP117/CircuitPython/README.md") is None
        assert self.mapper.git_to_device_path("neng_scpi_base/README.md") is None

        # Help directories
        assert self.mapper.git_to_device_path("neng_scpi_base/help/OTA.md") is None

        # Python cache
        assert self.mapper.git_to_device_path("TMP117/CircuitPython/__pycache__/foo.pyc") is None
        assert self.mapper.git_to_device_path("neng_scpi_base/__pycache__/scpi_server.pyc") is None

        # System files
        assert self.mapper.git_to_device_path("TMP117/CircuitPython/.DS_Store") is None
        assert self.mapper.git_to_device_path("TMP117/CircuitPython/boot_out.txt") is None
        assert self.mapper.git_to_device_path("TMP117/CircuitPython/log.txt") is None

        # Backup/update directories
        assert self.mapper.git_to_device_path("TMP117/CircuitPython/backup/code.py") is None
        assert self.mapper.git_to_device_path("TMP117/CircuitPython/update/code.py") is None

    def test_untracked_paths(self):
        """Test that files outside deployment areas return None."""
        # Root level files
        assert self.mapper.git_to_device_path("README.md") is None
        assert self.mapper.git_to_device_path("manage_version.py") is None

        # Other instrument directories
        assert self.mapper.git_to_device_path("3Dmag/CircuitPython/code.py") is None
        assert self.mapper.git_to_device_path("RelayBank16/CircuitPython/code.py") is None

        # Deploy scripts
        assert self.mapper.git_to_device_path("deploy/deploy_to_hw_opt1.sh") is None

    def test_get_deployable_files(self):
        """Test filtering and mapping of multiple git paths."""
        git_paths = [
            "TMP117/CircuitPython/code.py",
            "TMP117/CircuitPython/boot.py",
            "neng_scpi_base/ota_scpi_server.py",
            "neng_tmp117/__init__.py",
            "TMP117/CircuitPython/README.md",  # Should be excluded
            "README.md",  # Should be excluded
            "__pycache__/foo.pyc",  # Should be excluded
        ]

        # Note: This will only include files that actually exist on disk
        # In a real scenario with actual files, we'd get:
        # {
        #     "/code.py": "TMP117/CircuitPython/code.py",
        #     "/boot.py": "TMP117/CircuitPython/boot.py",
        #     "/lib/neng_scpi_base/ota_scpi_server.py": "neng_scpi_base/ota_scpi_server.py",
        #     "/lib/neng_tmp117/__init__.py": "neng_tmp117/__init__.py",
        # }

        result = self.mapper.get_deployable_files(git_paths)

        # Verify excluded files are not in result
        assert "/README.md" not in result
        assert "/lib/README.md" not in result
        assert "/__pycache__/foo.pyc" not in result


class TestGitDeployManager:
    """Test git deployment management."""

    def setup_method(self):
        """Setup test fixtures."""
        self.manager = GitDeployManager()

    def test_version_file_generation(self):
        """Test version.txt content generation."""
        # Test with clean tree
        content = self.manager.generate_version_file("abc123def456789", dirty=False)

        assert "commit=abc123def456789" in content
        assert "dirty=false" in content
        assert "timestamp=" in content
        assert "deployer=" in content

        # Verify format (4 lines)
        lines = content.strip().split("\n")
        assert len(lines) == 4

        # Verify all lines have key=value format
        for line in lines:
            assert "=" in line
            key, value = line.split("=", 1)
            assert key in ["commit", "timestamp", "deployer", "dirty"]
            assert value  # Value should not be empty

    def test_version_file_generation_dirty(self):
        """Test version.txt generation with dirty flag."""
        content = self.manager.generate_version_file("def456abc123", dirty=True)

        assert "commit=def456abc123" in content
        assert "dirty=true" in content

    def test_version_file_format(self):
        """Test that version file has correct format for CircuitPython parsing."""
        content = self.manager.generate_version_file("1234567890abcdef", dirty=False)

        # Parse it like CircuitPython would
        version_info = {}
        for line in content.strip().split("\n"):
            if "=" in line:
                key, value = line.split("=", 1)
                version_info[key] = value

        # Verify all required keys present
        assert "commit" in version_info
        assert "timestamp" in version_info
        assert "deployer" in version_info
        assert "dirty" in version_info

        # Verify commit is full hash (40 chars)
        assert len(version_info["commit"]) == 16  # Test hash length

        # Verify dirty is boolean string
        assert version_info["dirty"] in ["true", "false"]

        # Verify timestamp is ISO format (contains T and Z)
        assert "T" in version_info["timestamp"]
        assert version_info["timestamp"].endswith("Z")


# Integration tests would go here (require git repository and device)
# These are manual tests covered in the verification plan
