from __future__ import annotations

import time

from lark_oapi.api.task.v2 import (
    CreateTaskRequest,
    DeleteTaskRequest,
    Due,
    GetTaskRequest,
    InputTask,
    ListTaskRequest,
    ListTasklistRequest,
    Member,
    PatchTaskRequest,
    PatchTaskRequestBody,
)

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


def list_tasks(
    token: str,
    *,
    page_size: int = 50,
    max_count: int = 200,
    completed: bool | None = None,
) -> list:
    client = get_client()
    all_items: list = []
    page_token: str | None = None

    while len(all_items) < max_count:
        builder = (
            ListTaskRequest.builder()
            .page_size(min(page_size, 100))
            .user_id_type("open_id")
        )
        if completed is not None:
            builder = builder.completed(completed)
        if page_token:
            builder = builder.page_token(page_token)
        response = client.task.v2.task.list(builder.build(), make_option(token))
        if not response.success():
            if response.code == 99991679:
                raise InsufficientScopeError(MODULE_SCOPES.get("task", []), module="task")
            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_task(token: str, task_guid: str) -> object:
    client = get_client()
    request = (
        GetTaskRequest.builder()
        .task_guid(task_guid)
        .user_id_type("open_id")
        .build()
    )
    response = client.task.v2.task.get(request, make_option(token))
    if not response.success():
        if response.code == 99991679:
            raise InsufficientScopeError(MODULE_SCOPES.get("task", []), module="task")
        raise RuntimeError(
            f"获取任务失败: code={response.code}, msg={response.msg}"
        )
    return response.data.task


def create_task(
    token: str,
    summary: str,
    *,
    due: str | None = None,
    description: str = "",
    members: list[str] | None = None,
) -> object:
    client = get_client()

    task_builder = InputTask.builder().summary(summary)
    if description:
        task_builder = task_builder.description(description)
    if due:
        task_builder = task_builder.due(
            Due.builder().timestamp(due).is_all_day(False).build()
        )
    if members:
        member_list = [
            Member.builder().id(uid).type("user").role("assignee").build()
            for uid in members
        ]
        task_builder = task_builder.members(member_list)

    request = (
        CreateTaskRequest.builder()
        .request_body(task_builder.build())
        .user_id_type("open_id")
        .build()
    )
    response = client.task.v2.task.create(request, make_option(token))
    if not response.success():
        if response.code == 99991679:
            raise InsufficientScopeError(MODULE_SCOPES.get("task", []), module="task")
        raise RuntimeError(
            f"创建任务失败: code={response.code}, msg={response.msg}"
        )
    return response.data.task


def update_task(
    token: str,
    task_guid: str,
    *,
    summary: str | None = None,
    due: str | None = None,
    description: str | None = None,
    completed: bool | None = None,
) -> object:
    client = get_client()

    update_fields: list[str] = []
    task_builder = InputTask.builder()

    if summary is not None:
        task_builder = task_builder.summary(summary)
        update_fields.append("summary")
    if description is not None:
        task_builder = task_builder.description(description)
        update_fields.append("description")
    if due is not None:
        task_builder = task_builder.due(
            Due.builder().timestamp(due).is_all_day(False).build()
        )
        update_fields.append("due")
    if completed is not None:
        completed_at = str(int(time.time() * 1000)) if completed else ""
        task_builder = task_builder.completed_at(completed_at)
        update_fields.append("completed_at")

    request = (
        PatchTaskRequest.builder()
        .task_guid(task_guid)
        .request_body(
            PatchTaskRequestBody.builder()
            .task(task_builder.build())
            .update_fields(update_fields)
            .build()
        )
        .user_id_type("open_id")
        .build()
    )
    response = client.task.v2.task.patch(request, make_option(token))
    if not response.success():
        if response.code == 99991679:
            raise InsufficientScopeError(MODULE_SCOPES.get("task", []), module="task")
        raise RuntimeError(
            f"更新任务失败: code={response.code}, msg={response.msg}"
        )
    return response.data.task


def delete_task(token: str, task_guid: str) -> None:
    client = get_client()
    request = DeleteTaskRequest.builder().task_guid(task_guid).build()
    response = client.task.v2.task.delete(request, make_option(token))
    if not response.success():
        if response.code == 99991679:
            raise InsufficientScopeError(MODULE_SCOPES.get("task", []), module="task")
        raise RuntimeError(
            f"删除任务失败: code={response.code}, msg={response.msg}"
        )


def complete_task(token: str, task_guid: str) -> object:
    return update_task(token, task_guid, completed=True)


def list_task_lists(token: str, *, page_size: int = 50) -> list:
    client = get_client()
    all_items: list = []
    page_token: str | None = None

    while True:
        builder = (
            ListTasklistRequest.builder()
            .page_size(min(page_size, 100))
            .user_id_type("open_id")
        )
        if page_token:
            builder = builder.page_token(page_token)
        response = client.task.v2.tasklist.list(builder.build(), make_option(token))
        if not response.success():
            if response.code == 99991679:
                raise InsufficientScopeError(MODULE_SCOPES.get("task", []), module="task")
            raise RuntimeError(
                f"获取清单列表失败: code={response.code}, msg={response.msg}"
            )
        all_items.extend(response.data.items or [])
        if not response.data.has_more:
            break
        page_token = response.data.page_token

    return all_items
