"""
Invitation Workflow.

Creates invitation, generates token, and sends Novu notification.
"""
from datetime import timedelta

from temporalio import workflow
from temporalio.common import RetryPolicy

with workflow.unsafe.imports_passed_through():
    from ..types import (
        InvitationData,
        InvitationWorkflowResult,
        CreateInvitationInput,
        CreateInvitationResult,
        CreateInvitationTokenInput,
        CreateInvitationTokenResult,
        UpdateInvitationTokenStatusInput,
        SendInviteNotificationInput,
        SendInviteNotificationResult,
    )


EXTERNAL_API_RETRY = RetryPolicy(
    maximum_attempts=5,
    initial_interval=timedelta(seconds=2),
    backoff_coefficient=2.0,
    maximum_interval=timedelta(seconds=30),
)

INTERNAL_API_RETRY = RetryPolicy(
    maximum_attempts=3,
    initial_interval=timedelta(seconds=1),
    backoff_coefficient=2.0,
    maximum_interval=timedelta(seconds=10),
)


@workflow.defn(name="invite_user")
class InviteUserWorkflow:
    @workflow.run
    async def run(self, data: InvitationData) -> InvitationWorkflowResult:
        workflow.logger.info("Starting invite workflow for %s", data.email)

        create_invitation: CreateInvitationResult = await workflow.execute_activity(
            "create_invitation",
            CreateInvitationInput(
                team_uuid=data.team_uuid,
                email=data.email,
                role=data.role,
                invited_by=data.invited_by,
                expires_at=data.expires_at,
            ),
            schedule_to_close_timeout=timedelta(seconds=30),
            start_to_close_timeout=timedelta(seconds=15),
            retry_policy=INTERNAL_API_RETRY,
            result_type=CreateInvitationResult,
        )

        if not create_invitation.success:
            return InvitationWorkflowResult(
                status="failed",
                message=create_invitation.message,
            )

        invitation_uuid = create_invitation.invitation_uuid

        token_result: CreateInvitationTokenResult = await workflow.execute_activity(
            "create_invitation_token",
            CreateInvitationTokenInput(
                invitation_uuid=invitation_uuid,
                expires_at=data.expires_at,
            ),
            schedule_to_close_timeout=timedelta(seconds=30),
            start_to_close_timeout=timedelta(seconds=15),
            retry_policy=INTERNAL_API_RETRY,
            result_type=CreateInvitationTokenResult,
        )

        if not token_result.success:
            return InvitationWorkflowResult(
                status="failed",
                invitation_uuid=invitation_uuid,
                message=token_result.message,
            )

        send_result: SendInviteNotificationResult = await workflow.execute_activity(
            "send_invite_notification",
            SendInviteNotificationInput(
                email=data.email,
                team_uuid=data.team_uuid,
                role=data.role,
                token=token_result.token,
            ),
            schedule_to_close_timeout=timedelta(seconds=30),
            start_to_close_timeout=timedelta(seconds=15),
            retry_policy=EXTERNAL_API_RETRY,
            result_type=SendInviteNotificationResult,
        )

        if not send_result.success:
            await workflow.execute_activity(
                "update_invitation_token_status",
                UpdateInvitationTokenStatusInput(
                    token_uuid=token_result.token_uuid,
                    status="error",
                ),
                schedule_to_close_timeout=timedelta(seconds=30),
                start_to_close_timeout=timedelta(seconds=15),
                retry_policy=INTERNAL_API_RETRY,
            )
            return InvitationWorkflowResult(
                status="failed",
                invitation_uuid=invitation_uuid,
                message=send_result.message,
            )

        await workflow.execute_activity(
            "update_invitation_token_status",
            UpdateInvitationTokenStatusInput(
                token_uuid=token_result.token_uuid,
                status="active",
            ),
            schedule_to_close_timeout=timedelta(seconds=30),
            start_to_close_timeout=timedelta(seconds=15),
            retry_policy=INTERNAL_API_RETRY,
        )

        return InvitationWorkflowResult(
            status="completed",
            invitation_uuid=invitation_uuid,
            token=token_result.token,
        )
