import re
from enum import Enum

from app.api.utils import AutoFixStatus, Service
from app.config import logger
from app.utils import CPULoadReason, ManagementType, ServiceStatus


class TicketTemplateSnippets(Enum):
    SPAMD_INCORRECTLY_DISABLED = (
        "It appears the SpamAssassin service (spamd) is not disabled correctly and will be restarted by cPanel.",
        """Disabling the Apache SpamAssassin service, requires turning off the following settings:
- WHM >Tweak Settings > then set "Enable Apache SpamAssassin™ spam filter" to off;
- WHM > Service Manager and uncheck the enabled column for "Apache SpamAssassin™".

If either of those options is enabled, the SpamAssassin service will be restarted.
Unfortunately, the exact restart conditions, when one of those setting is left enabled, are not specified in the cPanel documentation.
""",
        "",
    )

    SPAMD_DOWN = (
        "",
        "",
        """In order to troubleshoot the matter, you can start by checking the service status using the following commands via SSH as the root user:
systemctl status spamd
/scripts/restartsrv_spamd --status
The '/scripts/restartsrv_spamd' command can be used to restart SpamAssassin.
""",
    )

    FTP_DOWN = (
        "",
        "",
        """In order to troubleshoot the matter, you can start by checking the service status using the following commands via SSH as the root user:
/scripts/restartsrv_ftpd --status
The '/scripts/restartsrv_ftpd' command can be used to restart the FTP server. Alternatively, this can also be done using the following menu in WHM:
Home -> Restart Services -> FTP Server (ProFTPD/Pure-FTPd)
""",
    )

    CSF_DOWN = (
        "",
        "",
        """In order to troubleshoot the matter, you can start by checking the service status using the following commands via SSH as the root user:
    systemctl status csf
    systemctl status lfd
    The 'csf -ra' command can be used to restart the firewall.
    Alternatively, you can control CSF and check its status using the following menu in WHM:
    Home -> Plugins -> ConfigServer Security & Firewall
    """,
    )

    @property
    def description(self):
        return self.value[0]

    @property
    def details(self):
        return self.value[1]

    @property
    def recommendations(self):
        return self.value[2]


def check_ticket_necessity(
    management_type: ManagementType,
    service: Service,
    data: dict,
) -> bool:
    ticket_needed = True
    payload = data["payload"]
    if service in [
        Service.CP_LICENSE,
        Service.PUPPET,
        Service.BACKUP_AGE,
        Service.HOSTNAME_DNS,
    ]:
        ticket_needed = False

    if management_type == ManagementType.COMPLETE:
        if service not in [Service.DISK, Service.BACKUP_DISK, Service.MEMORY]:
            ticket_needed = False

    if payload.get("service_status") == ServiceStatus.DISABLED.codename:
        ticket_needed = False

    if payload.get("error"):
        ticket_needed = False

    return ticket_needed


def prepare_payload_for_ticket(service: Service, payload: dict):
    if service in [Service.DISK, Service.BACKUP_DISK]:
        process_disk_payload(payload)
    elif service in [Service.MEMORY, Service.SWAP]:
        process_memory_payload(payload, service)
    elif service == Service.SPAMD:
        process_spamd_payload(payload)
    elif service == Service.CPU_LOAD:
        process_cpu_load_payload(payload)
    elif service == Service.FTP:
        payload["recommendations"] = TicketTemplateSnippets.FTP_DOWN.recommendations
    elif service == Service.CSF:
        payload["recommendations"] = TicketTemplateSnippets.CSF_DOWN.recommendations


def process_cpu_load_payload(payload: dict):
    payload["service_data"] = payload["top_data"]
    payload["details"] = payload["ps_data"]
    if payload["cpu_load_reason"] == CPULoadReason.MYSQL.value:
        payload[
            "recommendations"
        ] = f"Here are a few recommended optimization steps for MySQL:\n{payload['recommendations']}"


def process_memory_payload(payload: dict, service: Service):
    service_name = "RAM" if service == Service.MEMORY else "Swap"

    free_memory = f"{payload[f'{service_name.lower()}_free']} ({payload['free_percent']}%)"
    payload[
        "service_data"
    ] = f"Total {service_name}: {payload[f'{service_name.lower()}_total']}\nFree {service_name}: {free_memory}"


def process_disk_payload(payload: dict):
    try:
        partitions = list(
            {k.split("_")[-1] for k in payload.keys() if re.findall("df_(?:data|inodes)_.*", k)},
        )
        service_data = ""
        details = ""

        for part in partitions:
            service_data += f"'{part}' partition:\n"
            if payload.get(f"df_data_{part}"):
                service_data += f"{payload[f'df_data_{part}']}\n"

            if payload.get(f"df_inodes_{part}"):
                service_data += f"{payload[f'df_inodes_{part}']}\n"

            details += f"'{part}' partition:\n"
            if payload.get(f"big_dirs_{part}"):
                details += f"Large directories:\n{payload[f'big_dirs_{part}']}\n"
            if payload.get(f"big_files_{part}"):
                details += f"Large files:\n{payload[f'big_files_{part}']}\n"
            if payload.get(f"inodes_{part}"):
                details += f"Inode usage statistics:\n{payload[f'inodes_{part}']}\n"

            if part == "/tmp":
                file_details = ""
                if payload.get("file_type"):
                    file_details += (
                        f"The file types of some of the files in question are as follows:\n{payload['file_type']}\n"
                    )
                if payload.get("file_data"):
                    file_details += f"Here are some of the file contents:\n{payload['file_data']}"
                if file_details:
                    details += f"\n{file_details}"
                    payload.pop("file_type", None)
                    payload.pop("file_data", None)

            for var in [
                f"df_data_{part}",
                f"df_inodes_{part}",
                f"big_dirs_{part}",
                f"big_files_{part}",
                f"inodes_{part}",
            ]:
                payload.pop(var, None)

        payload["service_data"] = service_data
        payload["details"] = details
    except Exception as e:
        logger.error(
            f"Failed to parse partition data while checking disk status:\n{repr(e)}",
        )


def process_spamd_payload(payload: dict):
    spamd_service_data = payload.get("chkservd_conf_spamd")
    spamd_tweak_settings_data = payload.get("tweak_settings_skipspamassassin")
    if payload.get("auto_fix_status") == AutoFixStatus.FAILURE.codename:
        payload["recommendations"] = TicketTemplateSnippets.SPAMD_DOWN.recommendations
    elif spamd_tweak_settings_data is not None and spamd_service_data is not None:
        spamd_service_enabled = bool(spamd_service_data.split(":")[1])
        spamd_active_tweak_settings = not bool(spamd_tweak_settings_data.split("=")[1])
        spamd_deactivated_incorrectly = spamd_service_enabled ^ spamd_active_tweak_settings
        if spamd_deactivated_incorrectly:
            payload["service_data"] = TicketTemplateSnippets.SPAMD_INCORRECTLY_DISABLED.description
            payload["details"] = TicketTemplateSnippets.SPAMD_INCORRECTLY_DISABLED.details
