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

from temporalio import activity, workflow

from csirtmu.beta_temporal.commons.actions.temporal_common_actions import TemporalCommonActions
from csirtmu.beta_temporal.commons.conditions import CommonConditions
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.workflows.logging import LoggedActivities, LoggedWorkflow


class SetDueOnTicketStatusChangeParams(TypedDict):
    days: int
    status: str


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

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

    @activity.defn
    async def set_due(self, days: int, transaction: structs.TransactionStruct) -> None:
        self.log_activity()
        if transaction.ticket_obj is None:
            return
        today = datetime.datetime.now(tz=datetime.UTC)
        weekday = today.weekday()
        if weekday + days > 4:
            days += 2 if (weekday != 6) else 1
        if weekday == 6 or weekday == 5:
            today = today.replace(hour=0, minute=0, second=0)
        due = today + datetime.timedelta(days=days)
        self.rt_client.edit_ticket(transaction.ticket_obj.id, Due=due.strftime("%Y-%m-%d %H:%M:%S"))


class SetDueOnTicketStatusChange(LoggedWorkflow, workflow_name=WorkflowReference.SET_DUE_ON_TICKET_STATUS_CHANGE):
    @classmethod
    def get_activities(cls) -> Sequence[Callable[..., Awaitable[Any]]]:
        config = AppConfig.get()
        rt_client = RTClient(config.rt)
        common = CommonConditions(rt_client)
        local = SetDueOnTicketStatusChangeActivities(rt_client)
        temporal = TemporalCommonActions(config.temporal)
        return [*common.get_activities(), *local.get_activities(), *temporal.get_activities()]

    @workflow.run
    async def run(self, transaction: structs.TransactionStruct, params: SetDueOnTicketStatusChangeParams) -> None:
        self.log_workflow()
        config = AppConfig.get()
        if await workflow.execute_activity(
            CommonConditions.is_status_change,
            args=(params.get("status"), transaction),
            retry_policy=config.temporal.retry_policy,
            start_to_close_timeout=config.temporal.activity_timeout,
        ):
            await workflow.execute_activity(
                SetDueOnTicketStatusChangeActivities.set_due,
                args=(params.get("days"), 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,
            )
