import ipaddress
import logging
from typing import Optional

from defence360agent.subsys.panels.base import PanelException

from defence360agent.subsys import web_server
from .panels.base import RemoteIPInterface
from .panels.hosting_panel import HostingPanel

logger = logging.getLogger(__name__)


class RemoteIPError(Exception):
    pass


class LiteSpeedRemoteIP(RemoteIPInterface):
    async def remoteip_activated(self) -> bool:
        content = open(web_server.LITESPEED_CONF_PATH, "rb").read()
        config = web_server.LiteSpeedConfig(content)
        proxyIP = config.client_ip_in_header()
        allowed = config.access_control_allowed_list()
        if proxyIP == config.CLIENT_IP_IN_HEADER_DISABLED:
            return False
        if proxyIP == config.CLIENT_IP_IN_HEADER_ENABLED:
            return True
        if proxyIP == config.CLIENT_IP_IN_HEADER_TRUSTED_IP_ONLY:
            localhost = ipaddress.IPv4Address("127.0.0.1")
            for item, trusted in allowed:
                if trusted:
                    if item == "ALL":
                        return True
                    try:
                        item_network = ipaddress.ip_network(item)
                    except ValueError:
                        continue
                    else:
                        if localhost in item_network:  # NOSONAR pylint:S134
                            return True
            return False
        raise PanelException("Unknown value for client ip in header option")

    async def remoteip_install(self) -> Optional[str]:
        content = open(web_server.LITESPEED_CONF_PATH, "rb").read()
        config = web_server.LiteSpeedConfig(content)
        allowed = config.access_control_allowed_list()
        config.set_client_ip_in_header(
            config.CLIENT_IP_IN_HEADER_TRUSTED_IP_ONLY
        )
        allowed.add(("127.0.0.1", True))
        config.set_access_control_allowed_list(allowed)
        with open(web_server.LITESPEED_CONF_PATH, "wb") as config_file:
            config_file.write(config.tostring())
        await web_server.graceful_restart()
        return None


class ModRemoteIp:
    """Manages mod_remoteip or similar functionality"""

    NAME = "mod_remoteip"

    def __init__(self):
        self.__interface = None
        self._panel = HostingPanel()
        if self._panel.remoteip_supported():
            if web_server.litespeed_running():
                self.__interface = LiteSpeedRemoteIP()
            else:
                self.__interface = self._panel

    def is_supported(self):
        return self.__interface is not None

    async def is_installed(self) -> bool:
        try:
            if not self.is_supported():
                return False
            return await self.__interface.remoteip_activated()
        except PanelException as exc:
            raise RemoteIPError from exc

    async def install(self):
        try:
            if self.is_supported():
                return await self.__interface.remoteip_install()
            else:
                logger.warning(
                    "skipping installation of remoteip, panel not"
                    " supported %s",
                    self._panel.NAME,
                )
        except PanelException as exc:
            raise RemoteIPError() from exc
