from __future__ import annotations

import functools

import lark_oapi.api.authen.v1 as av1
from lark_oapi.api.mail.v1 import (
    GetUserMailboxMessageRequest,
    ListUserMailboxMessageRequest,
    MailAddress,
    SendUserMailboxMessageRequest,
    SendUserMailboxMessageRequestBody,
)

from ._client import get_client, make_option
from ._scopes import InsufficientScopeError, MODULE_SCOPES


@functools.lru_cache(maxsize=32)
def _get_my_mailbox_id(token: str) -> str:
    client = get_client()
    req = av1.GetUserInfoRequest.builder().build()
    resp = client.authen.v1.user_info.get(req, make_option(token))
    if not resp.success():
        raise RuntimeError(
            f"获取当前用户信息失败: code={resp.code}, msg={resp.msg}"
        )
    email = getattr(resp.data, "enterprise_email", None) or getattr(resp.data, "email", None)
    if not email:
        raise RuntimeError("当前用户未配置企业邮箱，无法使用邮件接口")
    return email


def _to_mail_addresses(addrs: str | list[str]) -> list:
    if isinstance(addrs, str):
        addrs = [addrs]
    return [MailAddress.builder().mail_address(a).build() for a in addrs]


def list_messages(
    token: str,
    *,
    folder_id: str = "INBOX",
    only_unread: bool = False,
    page_size: int = 20,
    max_count: int = 100,
) -> list:
    client = get_client()
    mailbox_id = _get_my_mailbox_id(token)
    all_items: list = []
    page_token: str | None = None

    while len(all_items) < max_count:
        builder = (
            ListUserMailboxMessageRequest.builder()
            .user_mailbox_id(mailbox_id)
            .folder_id(folder_id)
            .only_unread(only_unread)
            .page_size(min(page_size, 50))
        )
        if page_token:
            builder = builder.page_token(page_token)
        response = client.mail.v1.user_mailbox_message.list(
            builder.build(), make_option(token)
        )
        if not response.success():
            if response.code == 99991679:
                raise InsufficientScopeError(MODULE_SCOPES.get("mail", []), module="mail")
            raise RuntimeError(
                f"获取邮件列表失败: code={response.code}, msg={response.msg}"
            )
        items = response.data.items or []
        all_items.extend(items)
        if not response.data.has_more:
            break
        page_token = response.data.page_token

    return all_items[:max_count]


def get_message(token: str, message_id: str) -> object:
    client = get_client()
    mailbox_id = _get_my_mailbox_id(token)
    request = (
        GetUserMailboxMessageRequest.builder()
        .user_mailbox_id(mailbox_id)
        .message_id(message_id)
        .build()
    )
    response = client.mail.v1.user_mailbox_message.get(request, make_option(token))
    if not response.success():
        if response.code == 99991679:
            raise InsufficientScopeError(MODULE_SCOPES.get("mail", []), module="mail")
        raise RuntimeError(
            f"获取邮件失败: code={response.code}, msg={response.msg}"
        )
    return response.data


def send_mail(
    token: str,
    *,
    to: str | list[str],
    subject: str,
    body: str,
    cc: str | list[str] | None = None,
    bcc: str | list[str] | None = None,
    html: bool = False,
) -> object:
    client = get_client()
    mailbox_id = _get_my_mailbox_id(token)

    body_builder = (
        SendUserMailboxMessageRequestBody.builder()
        .subject(subject)
        .to(_to_mail_addresses(to))
    )
    if html:
        body_builder = body_builder.body_html(body)
    else:
        body_builder = body_builder.body_plain_text(body)
    if cc:
        body_builder = body_builder.cc(_to_mail_addresses(cc))
    if bcc:
        body_builder = body_builder.bcc(_to_mail_addresses(bcc))

    request = (
        SendUserMailboxMessageRequest.builder()
        .user_mailbox_id(mailbox_id)
        .request_body(body_builder.build())
        .build()
    )
    response = client.mail.v1.user_mailbox_message.send(request, make_option(token))
    if not response.success():
        if response.code == 99991679:
            raise InsufficientScopeError(MODULE_SCOPES.get("mail", []), module="mail")
        raise RuntimeError(
            f"发送邮件失败: code={response.code}, msg={response.msg}"
        )
    return response.data
