from typing import List

from prowler.lib.check.models import Check, CheckReportM365
from prowler.providers.m365.services.defender.defender_client import defender_client


class defender_malware_policy_comprehensive_attachments_filter_applied(Check):
    """
    Verifies if the Common Attachment Types Filter is enabled in the Defender anti-malware policy in a comprehensive way.

    Attributes:
        metadata: Metadata associated with the check (inherited from Check).
    """

    def execute(self) -> List[CheckReportM365]:
        """
        Executes the check to determine if the Common Attachment Types Filter is properly configured.

        This method evaluates the Defender anti-malware policies to ensure the filter is enabled and applied
        to all recommended file types.

        Returns:
            List[CheckReportM365]: A list of reports with the results of the check.
        """
        findings = []

        default_recommended_extensions = [
            "ace",
            "ani",
            "apk",
            "app",
            "appx",
            "arj",
            "bat",
            "cab",
            "cmd",
            "com",
            "deb",
            "dex",
            "dll",
            "docm",
            "elf",
            "exe",
            "hta",
            "img",
            "iso",
            "jar",
            "jnlp",
            "kext",
            "lha",
            "lib",
            "library",
            "lnk",
            "lzh",
            "macho",
            "msc",
            "msi",
            "msix",
            "msp",
            "mst",
            "pif",
            "ppa",
            "ppam",
            "reg",
            "rev",
            "scf",
            "scr",
            "sct",
            "sys",
            "uif",
            "vb",
            "vbe",
            "vbs",
            "vxd",
            "wsc",
            "wsf",
            "wsh",
            "xll",
            "xz",
            "z",
        ]

        recommended_extensions = defender_client.audit_config.get(
            "recommended_blocked_file_types", default_recommended_extensions
        )

        if defender_client.malware_policies:
            # Only Default Defender Malware Policy exists
            if not defender_client.malware_rules:
                policy = defender_client.malware_policies[0]

                report = CheckReportM365(
                    metadata=self.metadata(),
                    resource=policy,
                    resource_name=policy.identity,
                    resource_id=policy.identity,
                )

                if self._is_filter_properly_configured(policy, recommended_extensions):
                    # Case 1: Default policy exists and has filter properly configured
                    report.status = "PASS"
                    report.status_extended = f"{policy.identity} is the only policy and Common Attachment Types Filter is properly configured."
                else:
                    # Case 5: Default policy exists but doesn't have filter properly configured
                    missing = self._get_missing_extensions(
                        policy, recommended_extensions
                    )
                    report.status = "FAIL"
                    report.status_extended = f"{policy.identity} is the only policy and Common Attachment Types Filter is not properly configured. Missing recommended file types: {', '.join(missing)}."
                findings.append(report)

            # Multiple Defender Malware Policies exist
            else:
                default_policy_well_configured = False

                for policy in defender_client.malware_policies:
                    report = CheckReportM365(
                        metadata=self.metadata(),
                        resource=policy,
                        resource_name=policy.identity,
                        resource_id=policy.identity,
                    )

                    if policy.is_default:
                        if not self._is_filter_properly_configured(
                            policy, recommended_extensions
                        ):
                            # Case 4: Default policy is not properly configured
                            missing = self._get_missing_extensions(
                                policy, recommended_extensions
                            )
                            report.status = "FAIL"
                            report.status_extended = (
                                f"{policy.identity} is the default policy and Common Attachment Types Filter is not properly configured, "
                                f"but it could be overridden by another well-configured Custom Policy. Missing recommended file types: {', '.join(missing)}."
                            )
                            findings.append(report)
                        else:
                            # Case 2: Default policy is properly configured
                            report.status = "PASS"
                            report.status_extended = (
                                f"{policy.identity} is the default policy and Common Attachment Types Filter is properly configured, "
                                "but it could be overridden by another misconfigured Custom Policy."
                            )
                            default_policy_well_configured = True
                            findings.append(report)
                    else:
                        if not self._is_filter_properly_configured(
                            policy, recommended_extensions
                        ):
                            included_resources = []

                            if defender_client.malware_rules[policy.identity].users:
                                included_resources.append(
                                    f"users: {', '.join(defender_client.malware_rules[policy.identity].users)}"
                                )
                            if defender_client.malware_rules[policy.identity].groups:
                                included_resources.append(
                                    f"groups: {', '.join(defender_client.malware_rules[policy.identity].groups)}"
                                )
                            if defender_client.malware_rules[policy.identity].domains:
                                included_resources.append(
                                    f"domains: {', '.join(defender_client.malware_rules[policy.identity].domains)}"
                                )

                            included_resources_str = "; ".join(included_resources)
                            missing = self._get_missing_extensions(
                                policy, recommended_extensions
                            )

                            if default_policy_well_configured:
                                # Case 3: Default policy is configured, custom one isn't
                                report.status = "FAIL"
                                report.status_extended = (
                                    f"Custom Malware policy {policy.identity} is not properly configured and includes {included_resources_str}, "
                                    f"with priority {defender_client.malware_rules[policy.identity].priority} (0 is the highest). "
                                    f"Missing recommended file types: {', '.join(missing)}. "
                                    "However, the default policy is properly configured, so entities not included by this custom policy could be correctly protected."
                                )
                                findings.append(report)
                            else:
                                # Case 5: Neither default nor custom policy is properly configured
                                report.status = "FAIL"
                                report.status_extended = (
                                    f"Custom Malware policy {policy.identity} is not properly configured and includes {included_resources_str}, "
                                    f"with priority {defender_client.malware_rules[policy.identity].priority} (0 is the highest). "
                                    f"Missing recommended file types: {', '.join(missing)}. "
                                    "Also, the default policy is not properly configured, so entities not included by this custom policy could not be correctly protected."
                                )
                                findings.append(report)
                        else:
                            included_resources = []

                            if defender_client.malware_rules[policy.identity].users:
                                included_resources.append(
                                    f"users: {', '.join(defender_client.malware_rules[policy.identity].users)}"
                                )
                            if defender_client.malware_rules[policy.identity].groups:
                                included_resources.append(
                                    f"groups: {', '.join(defender_client.malware_rules[policy.identity].groups)}"
                                )
                            if defender_client.malware_rules[policy.identity].domains:
                                included_resources.append(
                                    f"domains: {', '.join(defender_client.malware_rules[policy.identity].domains)}"
                                )

                            included_resources_str = "; ".join(included_resources)

                            if default_policy_well_configured:
                                # Case 2: Both default and custom policies are properly configured
                                report.status = "PASS"
                                report.status_extended = (
                                    f"Custom Malware policy {policy.identity} is properly configured and includes {included_resources_str}, "
                                    f"with priority {defender_client.malware_rules[policy.identity].priority} (0 is the highest). "
                                    "Also, the default policy is properly configured, so entities not included by this custom policy could still be correctly protected."
                                )
                                findings.append(report)
                            else:
                                # Case 6: Default policy not configured, custom policy is
                                report.status = "PASS"
                                report.status_extended = (
                                    f"Custom Malware policy {policy.identity} is properly configured and includes {included_resources_str}, "
                                    f"with priority {defender_client.malware_rules[policy.identity].priority} (0 is the highest). "
                                    "However, the default policy is not properly configured, so entities not included by this custom policy could not be correctly protected."
                                )
                                findings.append(report)

        return findings

    def _is_filter_properly_configured(self, policy, recommended_extensions) -> bool:
        if not policy.enable_file_filter:
            return False

        if (
            not policy.is_default
            and policy.identity in defender_client.malware_rules
            and defender_client.malware_rules[policy.identity].state.lower()
            != "enabled"
        ):
            return False

        blocked_extensions = [ext.lower() for ext in policy.file_types]
        return all(ext.lower() in blocked_extensions for ext in recommended_extensions)

    def _get_missing_extensions(self, policy, recommended_extensions) -> List[str]:
        if not policy.enable_file_filter:
            return recommended_extensions

        blocked_extensions = [ext.lower() for ext in policy.file_types]
        return [
            ext
            for ext in recommended_extensions
            if ext.lower() not in blocked_extensions
        ]
