import unittest
from unittest import mock
from devsecops_engine_tools.engine_core.src.infrastructure.entry_points.entry_point_core import (
    init_engine_core,
)


class TestEntryPointCore(unittest.TestCase):

    @mock.patch(
        "devsecops_engine_tools.engine_core.src.infrastructure.entry_points.entry_point_core.HandleScan"
    )
    @mock.patch(
        "devsecops_engine_tools.engine_core.src.infrastructure.entry_points.entry_point_core.BreakBuild"
    )
    @mock.patch(
        "devsecops_engine_tools.engine_core.src.infrastructure.entry_points.entry_point_core.MetricsManager"
    )
    def test_init_engine_core(
        self,
        mock_metrics_manager,
        mock_break_build,
        mock_handle_scan
    ):
        # Set up mock arguments

        mock_config_tool = {"BANNER": "DevSecOps Engine Tools", "WARNING_RELEASE": False, "ENGINE_IAC": {"ENABLED": "true", "TOOL": "tool"}, "SBOM_MANAGER": {"TOOL": "SYFT"}, "BREAK_BUILD_MANAGER": {"MODEL": "severity", "CLASSIFICATION": ["critical", "high", "medium", "low"]}, "LICENSE_ANALYZER": {"TOOL": "dependency_track"}}
        mock_findings_list = []
        mock_input_core = {}
        mock_scan_result = {}

        mock_devops_platform_gateway = mock.Mock()
        mock_remote_config_source_gateway = mock.Mock()

        mock_remote_config_source_gateway.get_remote_config.return_value = mock_config_tool

        mock_handle_scan.return_value.process.return_value = (
            mock_findings_list,
            mock_input_core,
        )

        mock_break_build.return_value.process.return_value = mock_scan_result

        args = {
            "remote_config_repo": "https://github.com/example/repo",
            "module": "engine_iac",
            "send_metrics": "true",
            "remote_config_branch": ""
        }

        # Call the function
        init_engine_core(
            vulnerability_management_gateway=mock.Mock(),
            secrets_manager_gateway=mock.Mock(),
            devops_platform_gateway=mock_devops_platform_gateway,
            remote_config_source_gateway=mock_remote_config_source_gateway,
            print_table_gateway=mock.Mock(),
            metrics_manager_gateway=mock.Mock(),
            sbom_tool_gateway=mock.Mock(),
            risk_score_gateway=mock.Mock(),
            context_extraction_gateway=mock.Mock(),
            license_tool_gateway=mock.Mock(),
            args=args,
        )

        # Assert that the function calls were made with the expected arguments
        mock_remote_config_source_gateway.get_remote_config.assert_called_once_with(
            "https://github.com/example/repo", "/engine_core/ConfigTool.json", ""
        )
        mock_handle_scan.return_value.process.assert_called_once_with(
            {
                "remote_config_repo": "https://github.com/example/repo",
                "module": "engine_iac",
                "send_metrics": "true",
                "remote_config_branch": ""
            },
            mock_config_tool,
        )
        mock_break_build.return_value.process.assert_called_once_with(
            mock_findings_list, mock_input_core, args, False, {"MODEL": "severity", "CLASSIFICATION": ["critical", "high", "medium", "low"]}
        )
        mock_metrics_manager.return_value.process.assert_called_once_with(
            mock_config_tool,
            mock_input_core,
            args,
            mock_scan_result,
        )

    @mock.patch("builtins.print")
    def test_init_engine_core_disabled(self, mock_print):
        # Set up mock arguments

        mock_config_tool = {
            "BANNER": "DevSecOps Engine Tools",
            "ENGINE_IAC": {"ENABLED": False, "TOOL": "tool"},
            "SBOM_MANAGER": {
                "TOOL": "SYFT"
            },
            "LICENSE_ANALYZER": {"TOOL": "dependency_track"}
        }
        mock_devops_platform_gateway = mock.Mock()
        mock_remote_config_source_gateway = mock.Mock()

        mock_remote_config_source_gateway.get_remote_config.return_value = mock_config_tool

        # Call the function
        init_engine_core(
            vulnerability_management_gateway=mock.Mock(),
            secrets_manager_gateway=mock.Mock(),
            devops_platform_gateway=mock_devops_platform_gateway,
            remote_config_source_gateway=mock_remote_config_source_gateway,
            print_table_gateway=mock.Mock(),
            metrics_manager_gateway=mock.Mock(),
            sbom_tool_gateway=mock.Mock(),
            risk_score_gateway=mock.Mock(),
            context_extraction_gateway=mock.Mock(),
            license_tool_gateway=mock.Mock(),
            args={"remote_config_repo": "test", "module": "engine_iac", "remote_config_branch": ""},
        )

        # Assert
        assert mock_print.called

    @mock.patch(
        "devsecops_engine_tools.engine_core.src.infrastructure.entry_points.entry_point_core.HandleRisk"
    )
    @mock.patch(
        "devsecops_engine_tools.engine_core.src.infrastructure.entry_points.entry_point_core.MetricsManager"
    )
    def test_init_engine_core_risk(self, mock_metrics, mock_handle_risk):
        # Set up mock arguments

        mock_config_tool = {
            "BANNER": "DevSecOps Engine Tools",
            "ENGINE_RISK": {"ENABLED": "true"},
            "SBOM_MANAGER": {"TOOL": "SYFT"},
            "LICENSE_ANALYZER": {"TOOL": "dependency_track"}
        }
        mock_devops_platform_gateway = mock.Mock()
        mock_remote_config_source_gateway = mock.Mock()
        mock_remote_config_source_gateway.get_remote_config.return_value = mock_config_tool
        mock_handle_risk.return_value.process.return_value = (
            mock.Mock(),
            mock.Mock(),
        )


        # Call the function
        init_engine_core(
            vulnerability_management_gateway=mock.Mock(),
            secrets_manager_gateway=mock.Mock(),
            devops_platform_gateway=mock_devops_platform_gateway,
            remote_config_source_gateway=mock_remote_config_source_gateway,
            print_table_gateway=mock.Mock(),
            metrics_manager_gateway=mock.Mock(),
            sbom_tool_gateway=mock.Mock(),
            risk_score_gateway=mock.Mock(),
            context_extraction_gateway=mock.Mock(),
            license_tool_gateway=mock.Mock(),
            args={"remote_config_repo": "test", "module": "engine_risk", "send_metrics": "true", "remote_config_branch": ""},
        )

        #Assert
        mock_handle_risk.return_value.process.assert_called_once()
        mock_metrics.return_value.process.assert_called_once()


    @mock.patch(
        "devsecops_engine_tools.engine_core.src.infrastructure.entry_points.entry_point_core.HandleScan"
    )
    @mock.patch(
        "devsecops_engine_tools.engine_core.src.infrastructure.entry_points.entry_point_core.BreakBuild"
    )
    @mock.patch(
        "devsecops_engine_tools.engine_core.src.infrastructure.entry_points.entry_point_core.MetricsManager"
    )
    def test_init_engine_core_with_tool_flag(
        self,
        mock_metrics_manager,
        mock_break_build,
        mock_handle_scan
    ):
        # Set up mock arguments

        mock_config_tool = {"BANNER": "DevSecOps Engine Tools", "WARNING_RELEASE": "false", "ENGINE_IAC": {"ENABLED": "true", "TOOL": "tool"}, "SBOM_MANAGER": {"TOOL": "SYFT"}, "BREAK_BUILD_MANAGER": {"MODEL": "severity", "CLASSIFICATION": ["critical", "high", "medium", "low"]}, "LICENSE_ANALYZER": {"TOOL": "dependency_track"}}
        mock_config_tool_flag = {"BANNER": "DevSecOps Engine Tools", "WARNING_RELEASE": "false", "ENGINE_IAC": {"ENABLED": "true", "TOOL": "OTHER_TOOL"}, "SBOM_MANAGER": {"TOOL": "SYFT"}, "BREAK_BUILD_MANAGER": {"MODEL": "severity", "CLASSIFICATION": ["critical", "high", "medium", "low"]}, "LICENSE_ANALYZER": {"TOOL": "dependency_track"}}
        mock_findings_list = []
        mock_input_core = {}
        mock_scan_result = {}

        mock_devops_platform_gateway = mock.Mock()
        mock_remote_config_source_gateway = mock.Mock()

        mock_remote_config_source_gateway.get_remote_config.return_value = mock_config_tool

        mock_handle_scan.return_value.process.return_value = (
            mock_findings_list,
            mock_input_core,
        )

        mock_break_build.return_value.process.return_value = mock_scan_result

        args = {
            "remote_config_repo": "https://github.com/example/repo",
            "module": "engine_iac",
            "tool": "other_tool",
            "send_metrics": "true",
            "remote_config_branch": ""
        }

        # Call the function
        init_engine_core(
            vulnerability_management_gateway=mock.Mock(),
            secrets_manager_gateway=mock.Mock(),
            devops_platform_gateway=mock_devops_platform_gateway,
            remote_config_source_gateway=mock_remote_config_source_gateway,
            print_table_gateway=mock.Mock(),
            metrics_manager_gateway=mock.Mock(),
            sbom_tool_gateway=mock.Mock(),
            risk_score_gateway=mock.Mock(),
            context_extraction_gateway=mock.Mock(),
            license_tool_gateway=mock.Mock(),
            args=args,
        )

        # Assert that the function calls were made with the expected arguments
        mock_handle_scan.return_value.process.assert_called_once_with(
            {
                "remote_config_repo": "https://github.com/example/repo",
                "module": "engine_iac",
                "tool": "other_tool",
                "send_metrics": "true",
                "remote_config_branch": ""
            },
            mock_config_tool_flag,
        )
        mock_metrics_manager.return_value.process.assert_called_once_with(
            mock_config_tool_flag,
            mock_input_core,
            args,
            mock_scan_result,
        )

    @mock.patch(
        "devsecops_engine_tools.engine_core.src.infrastructure.entry_points.entry_point_core.HandleScan"
    )
    @mock.patch(
        "devsecops_engine_tools.engine_core.src.infrastructure.entry_points.entry_point_core.BreakBuild"
    )
    def test_init_engine_core_with_sbom_tool_override(
        self,
        mock_break_build,
        mock_handle_scan
    ):
        """Test that TOOL_OVERRIDE_PIPELINES correctly overrides the default SBOM tool"""
        # Set up mock config with tool override
        mock_config_tool = {
            "BANNER": "DevSecOps Engine Tools",
            "WARNING_RELEASE": False,
            "ENGINE_IAC": {"ENABLED": "true", "TOOL": "checkov"},
            "SBOM_MANAGER": {
                "TOOL": "CDXGEN",  # Default tool
                "TOOL_OVERRIDE_PIPELINES": {
                    "my_special_pipeline": "SYFT"  # Override for specific pipeline
                }
            },
            "BREAK_BUILD_MANAGER": {
                "MODEL": "severity", 
                "CLASSIFICATION": ["critical", "high", "medium", "low"]
            },
            "LICENSE_ANALYZER": {"TOOL": "dependency_track"}
        }
        mock_findings_list = []
        mock_input_core = {}
        mock_scan_result = {}

        mock_devops_platform_gateway = mock.Mock()
        mock_remote_config_source_gateway = mock.Mock()
        mock_sbom_tool_gateway = mock.Mock()

        # Configure mocks
        mock_devops_platform_gateway.get_variable.return_value = "my_special_pipeline"
        mock_remote_config_source_gateway.get_remote_config.return_value = mock_config_tool
        mock_sbom_tool_gateway.get.return_value = mock.Mock()

        mock_handle_scan.return_value.process.return_value = (
            mock_findings_list,
            mock_input_core,
        )
        mock_break_build.return_value.process.return_value = mock_scan_result

        args = {
            "remote_config_repo": "https://github.com/example/repo",
            "module": "engine_iac",
            "send_metrics": "false",
            "remote_config_branch": ""
        }

        # Call the function
        init_engine_core(
            vulnerability_management_gateway=mock.Mock(),
            secrets_manager_gateway=mock.Mock(),
            devops_platform_gateway=mock_devops_platform_gateway,
            remote_config_source_gateway=mock_remote_config_source_gateway,
            print_table_gateway=mock.Mock(),
            metrics_manager_gateway=mock.Mock(),
            sbom_tool_gateway=mock_sbom_tool_gateway,
            risk_score_gateway=mock.Mock(),
            context_extraction_gateway=mock.Mock(),
            license_tool_gateway=mock.Mock(),
            args=args,
        )

        # Assert that get_variable was called to get pipeline name
        mock_devops_platform_gateway.get_variable.assert_called_with("pipeline_name")
        
        # Assert that the SBOM tool was selected with the override (SYFT instead of CDXGEN)
        mock_sbom_tool_gateway.get.assert_called_once_with("syft")
