import ipaddress
import re
from collections.abc import Awaitable, Callable, Sequence
from itertools import chain
from typing import Any

from temporalio import activity, workflow

from csirtmu.beta_temporal.commons.actions import RTCommonActions
from csirtmu.beta_temporal.commons.actions.alpha_common_actions import AlphaCommonActions
from csirtmu.beta_temporal.commons.actions.temporal_common_actions import TemporalCommonActions
from csirtmu.beta_temporal.config import AppConfig
from csirtmu.beta_temporal.constants import WorkflowReference
from csirtmu.beta_temporal.external_services.alpha.client import AlphaClient
from csirtmu.beta_temporal.external_services.rt import structs
from csirtmu.beta_temporal.external_services.rt.client import RTClient
from csirtmu.beta_temporal.workflows.logging import LoggedActivities, LoggedWorkflow


class SetIPCustomFieldOnCreateActivities(LoggedActivities):
    def __init__(self, rt_client: RTClient) -> None:
        self.rt_client = rt_client
        self.REGEX_IP = r"(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)"
        self.REGEX_IPV6 = r"(?:(?:(?:[0-9A-Fa-f]{1,4}:){7}(?:[0-9A-Fa-f]{1,4}|:))|(?:(?:[0-9A-Fa-f]{1,4}:){6}(?::[0-9A-Fa-f]{1,4}|(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])(?:\.(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])){3})|:))|(?:(?:[0-9A-Fa-f]{1,4}:){5}(?:(?:(?::[0-9A-Fa-f]{1,4}){1,2})|:(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])(?:\.(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])){3})|:))|(?:(?:[0-9A-Fa-f]{1,4}:){4}(?:(?:(?::[0-9A-Fa-f]{1,4}){1,3})|(?:(?::[0-9A-Fa-f]{1,4})?:(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])(?:\.(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])){3}))|:))|(?:(?:[0-9A-Fa-f]{1,4}:){3}(?:(?:(?::[0-9A-Fa-f]{1,4}){1,4})|(?:(?::[0-9A-Fa-f]{1,4}){0,2}:(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])(?:\.(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])){3}))|:))|(?:(?:[0-9A-Fa-f]{1,4}:){2}(?:(?:(?::[0-9A-Fa-f]{1,4}){1,5})|(?:(?::[0-9A-Fa-f]{1,4}){0,3}:(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])(?:\.(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])){3}))|:))|(?:(?:[0-9A-Fa-f]{1,4}:){1}(?:(?:(?::[0-9A-Fa-f]{1,4}){1,6})|(?:(?::[0-9A-Fa-f]{1,4}){0,4}:(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])(?:\.(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])){3}))|:))|(?::(?:(?:(?::[0-9A-Fa-f]{1,4}){1,7})|(?:(?::[0-9A-Fa-f]{1,4}){0,5}:(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])(?:\.(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])){3}))|:)))(?:%.+)?"  # noqa: E501

    def get_activities(self) -> Sequence[Callable[..., Any]]:
        return [self.extract_ip_addresses_from_ticket]

    def check_ip(self, ip: str) -> bool:
        try:
            ipaddress.ip_address(ip)
            return True
        except ValueError:
            return False

    @activity.defn
    async def extract_ip_addresses_from_ticket(self, transaction: structs.TransactionStruct) -> list[str]:
        self.log_activity()
        addresses: set[str] = set()
        if (ticket_data := self.rt_client.get_ticket_data(transaction)) is not None:
            for match in chain(
                re.findall(self.REGEX_IP, ticket_data.body), re.findall(self.REGEX_IPV6, ticket_data.body)
            ):
                if self.check_ip(match):
                    addresses.add(match)
        return list(addresses)


class SetIPCustomFieldOnCreate(LoggedWorkflow, workflow_name=WorkflowReference.SET_IP_CUSTOM_FIELD_ON_CREATE):
    @classmethod
    def get_activities(cls) -> Sequence[Callable[..., Awaitable[Any]]]:
        config = AppConfig.get()
        return [
            *SetIPCustomFieldOnCreateActivities(RTClient(config.rt)).get_activities(),
            *AlphaCommonActions(AlphaClient(config.alpha)).get_activities(),
            *RTCommonActions(RTClient(config.rt)).get_activities(),
            *TemporalCommonActions(config.temporal).get_activities(),
        ]

    @workflow.run
    async def run(self, transaction: structs.TransactionStruct) -> None:
        self.log_workflow()
        config = AppConfig.get()
        ips: list[str] = await workflow.execute_activity(
            SetIPCustomFieldOnCreateActivities.extract_ip_addresses_from_ticket,
            args=(transaction,),
            retry_policy=config.temporal.retry_policy,
            start_to_close_timeout=config.temporal.activity_timeout,
        )
        if len(ips) > 0:
            custom_fields: dict[str, list[str]] = await workflow.execute_activity(
                AlphaCommonActions.get_netbox_network_info,
                args=(ips,),
                retry_policy=config.temporal.retry_policy,
                start_to_close_timeout=config.temporal.activity_timeout,
            )
            if custom_fields != {}:
                await workflow.execute_activity(
                    RTCommonActions.set_ip_related_custom_fields,
                    args=(transaction, custom_fields | {"IP": ips}),
                    retry_policy=config.temporal.retry_policy,
                    start_to_close_timeout=config.temporal.activity_timeout,
                )
        elif config.temporal.allow_internal_cancels:
            await workflow.execute_activity(
                TemporalCommonActions.cancel_workflow,
                args=(workflow.info().workflow_id, workflow.info().task_queue),
                retry_policy=config.temporal.retry_policy,
                start_to_close_timeout=config.temporal.activity_timeout,
            )
