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

from temporalio import activity, workflow

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.rt import structs
from csirtmu.beta_temporal.external_services.rt.client import RTClient
from csirtmu.beta_temporal.external_services.rt.utils import parse_headers
from csirtmu.beta_temporal.workflows.logging import LoggedActivities, LoggedWorkflow


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

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

    @activity.defn
    async def is_spam(self, transaction: structs.TransactionStruct) -> bool:
        self.log_activity()
        if (transaction_from_api := self.rt_client.get_transaction(transaction.id)) is None:
            return False
        if attachments := self.rt_client.get_attachments(transaction_from_api):
            headers = parse_headers(attachments[0].headers)
            if "X-Spam" in headers:
                data = headers["X-Spam"]
                if isinstance(data, str):
                    return str(data).lower() == "yes"
                if isinstance(data, list):
                    return any(item.lower() == "yes" for item in headers["X-Spam"] if isinstance(item, str))
        return False

    @activity.defn
    async def actions_on_spam(self, transaction: structs.TransactionStruct) -> None:
        self.log_activity()
        if transaction.ticket_obj is None:
            raise ValueError("Ticket object is None.")
        if not list(filter(lambda cf: cf.name == "Category" and cf.values, transaction.ticket_obj.custom_fields)):
            self.rt_client.edit_ticket(transaction.ticket_obj.id, CustomFields={"Category": "Spam"})


class SetSpamCategoryOnSpamHeader(LoggedWorkflow, workflow_name=WorkflowReference.SET_SPAM_CATEGORY_ON_SPAM_HEADER):
    @classmethod
    def get_activities(cls) -> Sequence[Callable[..., Awaitable[Any]]]:
        config = AppConfig.get()
        spam_activities = SpamCategoryOnHeaderActivities(RTClient(config.rt))
        temporal_actions = TemporalCommonActions(config.temporal)
        return [*spam_activities.get_activities(), *temporal_actions.get_activities()]

    @workflow.run
    async def run(self, transaction: structs.TransactionStruct) -> None:
        self.log_workflow()
        config = AppConfig.get()
        if await workflow.execute_activity(
            SpamCategoryOnHeaderActivities.is_spam,
            args=(transaction,),
            retry_policy=config.temporal.retry_policy,
            start_to_close_timeout=config.temporal.activity_timeout,
        ):
            await workflow.execute_activity(
                SpamCategoryOnHeaderActivities.actions_on_spam,
                args=(transaction,),
                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,
            )
