import datetime

import agilicus
import shortuuid

from dataclasses import dataclass
from enum import Enum
from typing import Optional

from .. import context


def send_broadcast_from_cli(
    ctx,
    user_org_id,
    expiry,
    title,
    text,
    icon_url,
    link,
    target,
    message_type,
    campaign_id,
):
    if not is_tz_aware(expiry):
        expiry = expiry.astimezone(datetime.timezone.utc)
    token = context.get_token(ctx)
    apiclient = context.get_apiclient(ctx, token)
    if not campaign_id:
        campaign_id = shortuuid.uuid()
    msg = Broadcast(
        title=title,
        text=text,
        message_type=message_type,
        icon_url=icon_url,
        link=link,
    )

    return send_broadcast(
        apiclient.messages_api,
        user_org_id_list=user_org_id,
        msg=msg,
        expiry=expiry,
        target=target,
        campaign_id=campaign_id,
    )


class BroadcastType(Enum):
    message_of_the_day = "motd"
    survey = "survey"


class MessageTarget(Enum):
    admin_portal = "agilicus-admin-portal"
    profile = "agilicus-profile"


@dataclass
class Broadcast:
    title: str
    text: str
    message_type: BroadcastType
    icon_url: Optional[str] = None
    link: Optional[str] = None


def send_broadcast(
    api: agilicus.MessagesApi,
    user_org_id_list: list[tuple[str, str] | tuple[str, str, bool]],
    msg: Broadcast,
    expiry: datetime.datetime,
    target: MessageTarget,
    campaign_id: str,
):
    """
    `send_broadcast` sends a message to a list of users (in a given org), which will
    expire (be removed from their inbox automatically). This can be used to
    broadcast important announcements, solicit feedback, notify of new features,
    etc.

    Each user is identified in the `user_org_id_list`, the first item being the user
    id, and the second their org id. If you want to send to a group of users, use the
    group's user id as the first parameter in the list, and set the third, optional,
    parameter to `True`.
    """
    if not is_tz_aware(expiry):
        raise ValueError(f"expiry ({expiry}) must be timezone aware")

    message = agilicus.Message(
        text=msg.text,
        title=msg.title,
        message_type=agilicus.MessageType(msg.message_type.value),
        message_class=agilicus.MessageClass(target.value),
    )

    if msg.icon_url is not None:
        message.icon_url = msg.icon_url
    if msg.link is not None:
        message.uri = msg.link

    message.expiry_date = expiry
    message.tag = agilicus.MessageTag(tag_name=agilicus.MessageTagName(campaign_id))

    send_item = agilicus.MessageSendItem(
        message=message,
        ephemeral=False,
        addresses=[
            _user_org_tuple_to_address(user_org) for user_org in user_org_id_list
        ],
        endpoint_types=[agilicus.MessageEndpointType("inbox")],
    )
    req = agilicus.MessageSendRequest(
        messages=[send_item],
    )
    return api.create_routed_message(req)


def _user_org_tuple_to_address(user_org: tuple[str, str] | tuple[str, str, bool]):
    addr = agilicus.MessageAddress(
        user_id=user_org[0],
        org_id=user_org[1],
        direct=True,
    )

    if len(user_org) > 2:
        # The third parameter here stands for "send to group", which is the inverse of
        # the direct field of the MessageAddress.
        addr.direct = not user_org[2]

    return addr


def is_tz_aware(dt: datetime.datetime):
    return dt.tzinfo is not None and dt.tzinfo.utcoffset(dt) is not None
