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

from temporalio import activity, workflow

from csirtmu.beta_temporal.commons.actions import RTCommonActions
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.netbox.client import NetboxClient
from csirtmu.beta_temporal.external_services.rt import structs
from csirtmu.beta_temporal.external_services.rt.client import RTClient
from csirtmu.beta_temporal.external_services.rt.utils import (
    get_custom_field_value_from_transaction,
    get_header,
    get_return_mail_map,
)
from csirtmu.beta_temporal.workflows.logging import LoggedActivities, LoggedWorkflow


class CloseAutomaticTicketActivities(LoggedActivities):
    def __init__(self, rt_client: RTClient, netbox_client: NetboxClient) -> None:
        self.rt_client = rt_client
        self.netbox_client = netbox_client

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

    @activity.defn
    async def is_automatic_ticket_for_closing(self, transaction: structs.TransactionStruct) -> bool:
        self.log_activity()
        return (
            transaction.ticket_obj is not None
            and r"Automatic ticket placeholder" not in transaction.ticket_obj.subject
            and (ticket_data := self.rt_client.get_ticket_data(transaction)) is not None
            and not any(bool(re.search(r".*muni\.cz", sender)) for sender in get_header(ticket_data.headers, "From"))
            and (
                (gateway := get_custom_field_value_from_transaction(transaction, "Gateway")) is None
                or "0" in gateway.values
            )
        )

    @activity.defn
    async def is_rejected_mail(self, transaction: structs.TransactionStruct) -> bool:
        self.log_activity()
        if transaction.ticket_obj is None or (ticket_data := self.rt_client.get_ticket_data(transaction)) is None:
            return False
        senders = get_header(ticket_data.headers, "From")
        return_mail_map = get_return_mail_map()
        for condition in return_mail_map:
            if (
                (
                    condition["Subject"] is None
                    or re.search(re.escape(condition["Subject"]), transaction.ticket_obj.subject) is not None
                )
                and (
                    condition["Sender"] is None
                    or any(
                        re.search(re.escape(condition["Sender"]), sender, re.IGNORECASE) is not None
                        for sender in senders
                    )
                )
                and (
                    condition["Content"] is None
                    or re.search(r"^\s*" + re.escape(condition["Content"]), ticket_data.body) is not None
                )
            ):
                return True
        return False


class CloseAutomaticTickets(LoggedWorkflow, workflow_name=WorkflowReference.CLOSE_AUTOMATIC_TICKETS):
    @classmethod
    def get_activities(cls) -> Sequence[Callable[..., Awaitable[Any]]]:
        config = AppConfig.get()
        rt_client = RTClient(config.rt)
        temporal_activities = TemporalCommonActions(config.temporal)
        rt_activities = RTCommonActions(rt_client)
        activities = CloseAutomaticTicketActivities(rt_client, NetboxClient(config.netbox))
        return [*temporal_activities.get_activities(), *rt_activities.get_activities(), *activities.get_activities()]

    @workflow.run
    async def run(self, transaction: structs.TransactionStruct) -> None:
        self.log_workflow()
        config = AppConfig.get()
        if await workflow.execute_activity(
            CloseAutomaticTicketActivities.is_automatic_ticket_for_closing,
            args=(transaction,),
            retry_policy=config.temporal.retry_policy,
            start_to_close_timeout=config.temporal.activity_timeout,
        ):
            if await workflow.execute_activity(
                CloseAutomaticTicketActivities.is_rejected_mail,
                args=(transaction,),
                retry_policy=config.temporal.retry_policy,
                start_to_close_timeout=config.temporal.activity_timeout,
            ):
                await workflow.execute_activity(
                    RTCommonActions.set_custom_field,
                    args=("Category", "Unable to contact", transaction),
                    retry_policy=config.temporal.retry_policy,
                    start_to_close_timeout=config.temporal.activity_timeout,
                )
            else:
                await workflow.execute_activity(
                    RTCommonActions.set_custom_field,
                    args=("Category", "Generic autoreply", transaction),
                    retry_policy=config.temporal.retry_policy,
                    start_to_close_timeout=config.temporal.activity_timeout,
                )
            if transaction.ticket_obj is None:
                return
            await workflow.execute_activity(
                RTCommonActions.close_ticket,
                args=(transaction.ticket_obj.id,),
                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,
            )
