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

from temporalio import activity, workflow

from csirtmu.beta_temporal.commons.actions import MattermostActions
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.mattermost.client import MattermostClient
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,
    search_for_keyword_non_quoted,
)
from csirtmu.beta_temporal.workflows.logging import LoggedActivities, LoggedWorkflow


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

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

    @staticmethod
    def try_decode_from_base64(text: str) -> str:
        try:
            return base64.b64decode(text).decode("utf-8")
        except binascii.Error:
            return ""

    @activity.defn
    async def is_analytics_comment(self, transaction: structs.TransactionStruct) -> bool:
        self.log_activity()
        cf = get_custom_field_value_from_transaction(transaction, "Category")
        if cf and "Analytics" in cf.values:
            if (data := self.rt_client.get_ticket_data(transaction)) is None:
                return False
            if search_for_keyword_non_quoted(data.body.lower(), "[@analytics]"):
                return True
            for att in data.attachments:
                if att.content and "text" in att.content_type:
                    if search_for_keyword_non_quoted(att.content.lower(), "[@analytics]"):
                        return True
                    if search_for_keyword_non_quoted(
                        self.try_decode_from_base64(att.content.strip()).lower(), "[@analytics]"
                    ):
                        return True
        return False


class MattermostNotificationOnAnalyticsComment(
    LoggedWorkflow, workflow_name=WorkflowReference.MATTERMOST_NOTIFICATION_ON_ANALYTICS_COMMENT
):
    @classmethod
    def get_activities(cls) -> Sequence[Callable[..., Awaitable[Any]]]:
        config = AppConfig.get()
        mm_actions = MattermostActions(config.rt.base_url, MattermostClient(config.mattermost))
        mm_conditions = MattermostNotificationOnAnalyticsCommentActivities(RTClient(config.rt))
        temporal_actions = TemporalCommonActions(config.temporal)
        return [*mm_conditions.get_activities(), *mm_actions.get_activities(), *temporal_actions.get_activities()]

    @workflow.run
    async def run(self, transaction: structs.TransactionStruct, params: dict[str, str]) -> None:
        self.log_workflow()
        config = AppConfig.get()
        if not (channel := params.get("mm_channel")):
            raise ValueError("No channel given!")
        if await workflow.execute_activity(
            MattermostNotificationOnAnalyticsCommentActivities.is_analytics_comment,
            args=(transaction,),
            retry_policy=config.temporal.retry_policy,
            start_to_close_timeout=config.temporal.activity_timeout,
        ):
            await workflow.execute_activity(
                MattermostActions.notify_mattermost_on_analytics_category,
                args=(
                    transaction,
                    channel,
                ),
                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,
            )
