from __future__ import annotations

from lark_oapi.api.calendar.v4 import (
    BatchDeleteCalendarEventAttendeeRequest,
    BatchDeleteCalendarEventAttendeeRequestBody,
    CalendarEvent,
    CalendarEventAttendee,
    CreateCalendarEventAttendeeRequest,
    CreateCalendarEventAttendeeRequestBody,
    CreateCalendarEventRequest,
    DeleteCalendarEventRequest,
    EventLocation,
    GetCalendarEventRequest,
    ListCalendarEventAttendeeRequest,
    ListCalendarEventRequest,
    ListFreebusyRequest,
    ListFreebusyRequestBody,
    PatchCalendarEventRequest,
    PrimaryCalendarRequest,
    TimeInfo,
)

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


def get_primary_calendar(token: str) -> object:
    client = get_client()
    request = PrimaryCalendarRequest.builder().user_id_type("open_id").build()
    response = client.calendar.v4.calendar.primary(request, make_option(token))
    if not response.success():
        if response.code == 99991679:
            raise InsufficientScopeError(MODULE_SCOPES.get("calendar", []), module="calendar")
        raise RuntimeError(
            f"获取主日历失败: code={response.code}, msg={response.msg}"
        )
    calendars = response.data.calendars or []
    return calendars[0].calendar if calendars else None


def list_events(
    token: str,
    calendar_id: str,
    *,
    start_time: str | None = None,
    end_time: str | None = None,
    page_size: int = 50,
    max_count: int = 200,
) -> list:
    client = get_client()
    all_items: list = []
    page_token: str | None = None

    while len(all_items) < max_count:
        builder = (
            ListCalendarEventRequest.builder()
            .calendar_id(calendar_id)
            .page_size(min(page_size, 500))
        )
        if start_time:
            builder = builder.start_time(start_time)
        if end_time:
            builder = builder.end_time(end_time)
        if page_token:
            builder = builder.page_token(page_token)
        response = client.calendar.v4.calendar_event.list(
            builder.build(), make_option(token)
        )
        if not response.success():
            if response.code == 99991679:
                raise InsufficientScopeError(MODULE_SCOPES.get("calendar", []), module="calendar")
            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_event(token: str, calendar_id: str, event_id: str) -> object:
    client = get_client()
    request = (
        GetCalendarEventRequest.builder()
        .calendar_id(calendar_id)
        .event_id(event_id)
        .user_id_type("open_id")
        .build()
    )
    response = client.calendar.v4.calendar_event.get(request, make_option(token))
    if not response.success():
        if response.code == 99991679:
            raise InsufficientScopeError(MODULE_SCOPES.get("calendar", []), module="calendar")
        raise RuntimeError(
            f"获取日程失败: code={response.code}, msg={response.msg}"
        )
    return response.data.event


def create_event(
    token: str,
    calendar_id: str,
    summary: str,
    *,
    start_time: str,
    end_time: str,
    description: str = "",
    location: str = "",
    attendees: list[str] | None = None,
    timezone: str = "Asia/Shanghai",
) -> object:
    client = get_client()

    event_builder = (
        CalendarEvent.builder()
        .summary(summary)
        .start_time(
            TimeInfo.builder().timestamp(start_time).timezone(timezone).build()
        )
        .end_time(
            TimeInfo.builder().timestamp(end_time).timezone(timezone).build()
        )
    )
    if description:
        event_builder = event_builder.description(description)
    if location:
        event_builder = event_builder.location(
            EventLocation.builder().name(location).build()
        )
    if attendees:
        attendee_list = [
            CalendarEventAttendee.builder()
            .type("user")
            .user_id(uid)
            .build()
            for uid in attendees
        ]
        event_builder = event_builder.attendees(attendee_list)

    request = (
        CreateCalendarEventRequest.builder()
        .calendar_id(calendar_id)
        .request_body(event_builder.build())
        .user_id_type("open_id")
        .build()
    )
    response = client.calendar.v4.calendar_event.create(request, make_option(token))
    if not response.success():
        if response.code == 99991679:
            raise InsufficientScopeError(MODULE_SCOPES.get("calendar", []), module="calendar")
        raise RuntimeError(
            f"创建日程失败: code={response.code}, msg={response.msg}"
        )
    return response.data.event


def update_event(
    token: str,
    calendar_id: str,
    event_id: str,
    *,
    summary: str | None = None,
    start_time: str | None = None,
    end_time: str | None = None,
    description: str | None = None,
    location: str | None = None,
    timezone: str = "Asia/Shanghai",
) -> object:
    client = get_client()

    event_builder = CalendarEvent.builder()
    if summary is not None:
        event_builder = event_builder.summary(summary)
    if start_time is not None:
        event_builder = event_builder.start_time(
            TimeInfo.builder().timestamp(start_time).timezone(timezone).build()
        )
    if end_time is not None:
        event_builder = event_builder.end_time(
            TimeInfo.builder().timestamp(end_time).timezone(timezone).build()
        )
    if description is not None:
        event_builder = event_builder.description(description)
    if location is not None:
        event_builder = event_builder.location(
            EventLocation.builder().name(location).build()
        )

    request = (
        PatchCalendarEventRequest.builder()
        .calendar_id(calendar_id)
        .event_id(event_id)
        .request_body(event_builder.build())
        .user_id_type("open_id")
        .build()
    )
    response = client.calendar.v4.calendar_event.patch(request, make_option(token))
    if not response.success():
        if response.code == 99991679:
            raise InsufficientScopeError(MODULE_SCOPES.get("calendar", []), module="calendar")
        raise RuntimeError(
            f"更新日程失败: code={response.code}, msg={response.msg}"
        )
    return response.data.event


def delete_event(token: str, calendar_id: str, event_id: str) -> None:
    client = get_client()
    request = (
        DeleteCalendarEventRequest.builder()
        .calendar_id(calendar_id)
        .event_id(event_id)
        .build()
    )
    response = client.calendar.v4.calendar_event.delete(request, make_option(token))
    if not response.success():
        if response.code == 99991679:
            raise InsufficientScopeError(MODULE_SCOPES.get("calendar", []), module="calendar")
        raise RuntimeError(
            f"删除日程失败: code={response.code}, msg={response.msg}"
        )


def add_attendees(
    token: str,
    calendar_id: str,
    event_id: str,
    user_ids: list[str],
    *,
    need_notification: bool = True,
) -> list[dict]:
    client = get_client()
    attendee_list = [
        CalendarEventAttendee.builder().type("user").user_id(uid).build()
        for uid in user_ids
    ]
    request = (
        CreateCalendarEventAttendeeRequest.builder()
        .calendar_id(calendar_id)
        .event_id(event_id)
        .user_id_type("open_id")
        .request_body(
            CreateCalendarEventAttendeeRequestBody.builder()
            .attendees(attendee_list)
            .need_notification(need_notification)
            .build()
        )
        .build()
    )
    response = client.calendar.v4.calendar_event_attendee.create(request, make_option(token))
    if not response.success():
        if response.code == 99991679:
            raise InsufficientScopeError(MODULE_SCOPES.get("calendar", []), module="calendar")
        raise RuntimeError(f"添加日程参与者失败: code={response.code}, msg={response.msg}")
    result = []
    for a in response.data.attendees or []:
        result.append({
            "attendee_id": getattr(a, "attendee_id", ""),
            "type": getattr(a, "type", ""),
            "user_id": getattr(a, "user_id", ""),
            "display_name": getattr(a, "display_name", ""),
            "rsvp_status": getattr(a, "rsvp_status", ""),
        })
    return result


def remove_attendees(
    token: str,
    calendar_id: str,
    event_id: str,
    attendee_ids: list[str],
    *,
    need_notification: bool = True,
) -> dict:
    client = get_client()
    request = (
        BatchDeleteCalendarEventAttendeeRequest.builder()
        .calendar_id(calendar_id)
        .event_id(event_id)
        .user_id_type("open_id")
        .request_body(
            BatchDeleteCalendarEventAttendeeRequestBody.builder()
            .attendee_ids(attendee_ids)
            .need_notification(need_notification)
            .build()
        )
        .build()
    )
    response = client.calendar.v4.calendar_event_attendee.batch_delete(request, make_option(token))
    if not response.success():
        if response.code == 99991679:
            raise InsufficientScopeError(MODULE_SCOPES.get("calendar", []), module="calendar")
        raise RuntimeError(f"删除日程参与者失败: code={response.code}, msg={response.msg}")
    return {"removed_count": len(attendee_ids), "attendee_ids": attendee_ids}


def query_freebusy(
    token: str,
    user_id: str,
    time_min: str,
    time_max: str,
) -> list[dict]:
    client = get_client()
    request = (
        ListFreebusyRequest.builder()
        .user_id_type("open_id")
        .request_body(
            ListFreebusyRequestBody.builder()
            .user_id(user_id)
            .time_min(time_min)
            .time_max(time_max)
            .build()
        )
        .build()
    )
    response = client.calendar.v4.freebusy.list(request, make_option(token))
    if not response.success():
        if response.code == 99991679:
            raise InsufficientScopeError(MODULE_SCOPES.get("calendar", []), module="calendar")
        raise RuntimeError(f"查询空闲忙碌失败: code={response.code}, msg={response.msg}")
    result = []
    for fb in response.data.freebusy_list or []:
        result.append({
            "user_id": getattr(fb, "uid", user_id),
            "start_time": getattr(fb, "start_time", ""),
            "end_time": getattr(fb, "end_time", ""),
        })
    return result
