from __future__ import annotations

from typing import Any

from mcp.server.fastmcp import FastMCP

from ..config import DEFAULT_PROFILE
from ..errors import QingflowApiError, raise_tool_error
from ..list_type_labels import get_record_list_type_label, get_task_type_label
from .base import ToolBase


class TaskTools(ToolBase):
    """任务中心（待办/已办）相关工具

    提供对工作流任务的管理功能，包括：
    - 查询待办/已办列表
    - 查看任务统计
    - 标记已读/催办
    - 查询节点和表单分组信息

    消息类型 (type):
    - 1: 待办 (TODO) - 需要当前用户处理的任务
    - 2: 我发起的 (INITIATED) - 当前用户发起的流程
    - 3: 抄送 (CC) - 抄送给当前用户的任务
    - 5: 已办 (DONE) - 当前用户已处理的任务

    流程状态 (process_status):
    - 1: 全部
    - 2: 流程中
    - 3: 已通过
    - 4: 已拒绝
    - 5: 待完善
    - 6: 催办
    - 7: 超时
    - 8: 即将超时
    - 9: 未读
    - 10: 流程结束
    """

    def register(self, mcp: FastMCP) -> None:
        @mcp.tool()
        def task_list(
            profile: str = DEFAULT_PROFILE,
            type: int = 1,
            process_status: int = 1,
            app_key: str | None = None,
            node_id: int | None = None,
            search_key: str | None = None,
            page_num: int = 1,
            page_size: int = 20,
            create_time_asc: bool | None = None,
        ) -> dict[str, Any]:
            """查询任务列表（待办/已办/我发起的/抄送）

            Args:
                profile: 配置文件名
                type: 消息类型 (1=待办, 2=我发起的, 3=抄送, 5=已办)
                process_status: 流程状态 (1=全部, 2=流程中, 3=已通过, 4=已拒绝, 5=待完善, 6=催办, 7=超时, 8=即将超时, 9=未读)
                app_key: 应用key（可选，用于筛选特定应用）
                node_id: 节点ID（可选，用于筛选特定节点）
                search_key: 搜索关键词
                page_num: 页码，从1开始
                page_size: 每页数量
                create_time_asc: 是否按创建时间升序（None表示默认排序）
            """
            return self.task_list(
                profile=profile,
                type=type,
                process_status=process_status,
                app_key=app_key,
                node_id=node_id,
                search_key=search_key,
                page_num=page_num,
                page_size=page_size,
                create_time_asc=create_time_asc,
            )

        @mcp.tool()
        def task_list_grouped(
            profile: str = DEFAULT_PROFILE,
            type: int = 1,
            process_status: int = 1,
            app_key: str | None = None,
            node_id: int | None = None,
            search_key: str | None = None,
            page_num: int = 1,
            page_size: int = 20,
        ) -> dict[str, Any]:
            """查询任务列表（带分组信息）

            返回按表单分组的任务列表，适用于需要分组展示的场景。

            Args:
                profile: 配置文件名
                type: 消息类型 (1=待办, 2=我发起的, 3=抄送, 5=已办)
                process_status: 流程状态 (1=全部, 2=流程中, 3=已通过, 4=已拒绝, 5=待完善, 6=催办, 7=超时, 8=即将超时, 9=未读)
                app_key: 应用key（可选，用于筛选特定应用）
                node_id: 节点ID（可选，用于筛选特定节点）
                search_key: 搜索关键词
                page_num: 页码，从1开始
                page_size: 每页数量
            """
            return self.task_list_grouped(
                profile=profile,
                type=type,
                process_status=process_status,
                app_key=app_key,
                node_id=node_id,
                search_key=search_key,
                page_num=page_num,
                page_size=page_size,
            )

        @mcp.tool()
        def task_statistics(
            profile: str = DEFAULT_PROFILE,
            app_key: str | None = None,
        ) -> dict[str, Any]:
            """查询任务中心统计信息

            获取当前用户的任务统计数量，包括：
            - 待办数量
            - 超时数量
            - 即将超时数量
            - 催办数量
            - 抄送未读数量
            - 我发起的流程中数量

            Args:
                profile: 配置文件名
                app_key: 应用key（可选，用于统计特定应用）
            """
            return self.task_statistics(profile=profile, app_key=app_key)

        @mcp.tool()
        def task_workflow_nodes(
            profile: str = DEFAULT_PROFILE,
            type: int = 1,
            status: str | None = None,
            app_key_list: list[str] | None = None,
            search_key: str | None = None,
            page_num: int = 1,
            page_size: int = 20,
        ) -> dict[str, Any]:
            """查询流程节点列表

            获取工作流节点信息，可用于了解当前有哪些流程节点。

            Args:
                profile: 配置文件名
                type: 消息类型 (1=待办, 2=我发起的, 3=抄送, 5=已办)
                status: 流程状态
                app_key_list: 应用key列表（用于筛选特定应用）
                search_key: 节点名称搜索关键词
                page_num: 页码
                page_size: 每页数量
            """
            return self.task_workflow_nodes(
                profile=profile,
                type=type,
                status=status,
                app_key_list=app_key_list,
                search_key=search_key,
                page_num=page_num,
                page_size=page_size,
            )

        @mcp.tool()
        def task_node_statistics(
            profile: str = DEFAULT_PROFILE,
            app_key: str = "",
            type: int = 1,
            search_key: str | None = None,
        ) -> dict[str, Any]:
            """查询表单下节点的分组统计信息

            获取指定应用下各节点的任务数量统计。

            Args:
                profile: 配置文件名
                app_key: 应用key
                type: 消息类型 (1=待办, 2=我发起的, 3=抄送, 5=已办)
                search_key: 节点名称搜索关键词
            """
            return self.task_node_statistics(
                profile=profile,
                app_key=app_key,
                type=type,
                search_key=search_key,
            )

        @mcp.tool()
        def task_worksheet_statistics(
            profile: str = DEFAULT_PROFILE,
            type: int = 1,
            worksheet_name: str | None = None,
            page_num: int = 1,
            page_size: int = 20,
        ) -> dict[str, Any]:
            """查询表单分组统计信息

            获取各表单的任务数量统计。

            Args:
                profile: 配置文件名
                type: 消息类型 (1=待办, 2=我发起的, 3=抄送, 5=已办)
                worksheet_name: 表单名称搜索关键词
                page_num: 页码
                page_size: 每页数量
            """
            return self.task_worksheet_statistics(
                profile=profile,
                type=type,
                worksheet_name=worksheet_name,
                page_num=page_num,
                page_size=page_size,
            )

        @mcp.tool()
        def task_mark_read(
            profile: str = DEFAULT_PROFILE,
            app_key: str = "",
            id: int = 0,
            type: int = 1,
        ) -> dict[str, Any]:
            """标记任务为已读

            Args:
                profile: 配置文件名
                app_key: 应用key
                id: 任务ID
                type: 消息类型
            """
            return self.task_mark_read(profile=profile, app_key=app_key, id=id, type=type)

        @mcp.tool()
        def task_mark_all_cc_read(
            profile: str = DEFAULT_PROFILE,
            type: int = 3,
            process_status: int = 1,
        ) -> dict[str, Any]:
            """标记所有抄送为已读

            Args:
                profile: 配置文件名
                type: 消息类型（默认为3=抄送）
                process_status: 流程状态
            """
            return self.task_mark_all_cc_read(
                profile=profile,
                type=type,
                process_status=process_status,
            )

        @mcp.tool()
        def task_urge(
            profile: str = DEFAULT_PROFILE,
            app_key: str = "",
            row_record_id: int = 0,
        ) -> dict[str, Any]:
            """催办任务

            对指定记录发起催办，提醒处理人尽快处理。

            Args:
                profile: 配置文件名
                app_key: 应用key
                row_record_id: 记录ID（原applyId）
            """
            return self.task_urge(profile=profile, app_key=app_key, row_record_id=row_record_id)

        @mcp.tool()
        def task_group_detail(
            profile: str = DEFAULT_PROFILE,
            app_key: str = "",
            group_id: int = 0,
        ) -> dict[str, Any]:
            """查询分组详情

            获取指定分组的详细信息。

            Args:
                profile: 配置文件名
                app_key: 应用key
                group_id: 分组ID
            """
            return self.task_group_detail(profile=profile, app_key=app_key, group_id=group_id)

        @mcp.tool()
        def task_batch_processing_amount(
            profile: str = DEFAULT_PROFILE,
            app_key: str = "",
            list_type: int = 0,
            task_center_filter: dict[str, Any] | None = None,
        ) -> dict[str, Any]:
            """查询批量处理数量

            获取符合筛选条件的任务数量，用于批量操作前的数量确认。

            Args:
                profile: 配置文件名
                app_key: 应用key
                list_type: 操作类型
                task_center_filter: 筛选条件
            """
            return self.task_batch_processing_amount(
                profile=profile,
                app_key=app_key,
                list_type=list_type,
                task_center_filter=task_center_filter,
            )

    def task_list(
        self,
        *,
        profile: str,
        type: int,
        process_status: int,
        app_key: str | None,
        node_id: int | None,
        search_key: str | None,
        page_num: int,
        page_size: int,
        create_time_asc: bool | None,
    ) -> dict[str, Any]:
        self._validate_type(type)
        self._validate_process_status(process_status)

        def runner(session_profile, context):
            payload: dict[str, Any] = {
                "type": type,
                "processStatus": process_status,
                "pageNum": page_num,
                "pageSize": page_size,
            }
            if app_key is not None:
                payload["appKey"] = app_key
            if node_id is not None:
                payload["nodeId"] = node_id
            if search_key:
                payload["searchKey"] = search_key
            if create_time_asc is not None:
                payload["createTimeAsc"] = create_time_asc

            result = self.backend.request("POST", context, "/task/dynamic/page", json_body=payload)
            return {
                "profile": profile,
                "ws_id": session_profile.selected_ws_id,
                "type": type,
                "type_label": get_task_type_label(type),
                "list_type_label": get_task_type_label(type),
                "process_status": process_status,
                "page": result,
            }

        return self._run(profile, runner)

    def task_list_grouped(
        self,
        *,
        profile: str,
        type: int,
        process_status: int,
        app_key: str | None,
        node_id: int | None,
        search_key: str | None,
        page_num: int,
        page_size: int,
    ) -> dict[str, Any]:
        self._validate_type(type)
        self._validate_process_status(process_status)

        def runner(session_profile, context):
            payload: dict[str, Any] = {
                "type": type,
                "processStatus": process_status,
                "pageNum": page_num,
                "pageSize": page_size,
            }
            if app_key is not None:
                payload["appKey"] = app_key
            if node_id is not None:
                payload["nodeId"] = node_id
            if search_key:
                payload["searchKey"] = search_key

            result = self.backend.request("POST", context, "/task/dynamic/page/group", json_body=payload)
            return {
                "profile": profile,
                "ws_id": session_profile.selected_ws_id,
                "type": type,
                "type_label": get_task_type_label(type),
                "list_type_label": get_task_type_label(type),
                "process_status": process_status,
                "page": result,
            }

        return self._run(profile, runner)

    def task_statistics(
        self,
        *,
        profile: str,
        app_key: str | None,
    ) -> dict[str, Any]:
        def runner(session_profile, context):
            params: dict[str, Any] = {}
            if app_key:
                params["appKey"] = app_key

            result = self.backend.request("GET", context, "/task/dynamic/statics", params=params)
            return {
                "profile": profile,
                "ws_id": session_profile.selected_ws_id,
                "statistics": result,
            }

        return self._run(profile, runner)

    def task_workflow_nodes(
        self,
        *,
        profile: str,
        type: int,
        status: str | None,
        app_key_list: list[str] | None,
        search_key: str | None,
        page_num: int,
        page_size: int,
    ) -> dict[str, Any]:
        self._validate_type(type)

        def runner(session_profile, context):
            params: dict[str, Any] = {
                "type": type,
                "pageNum": page_num,
                "pageSize": page_size,
            }
            if status is not None:
                params["status"] = status
            if app_key_list:
                params["appKeyList"] = app_key_list
            if search_key:
                params["searchKey"] = search_key

            result = self.backend.request("GET", context, "/task/dynamic/workflow/nodes", params=params)
            return {
                "profile": profile,
                "ws_id": session_profile.selected_ws_id,
                "type": type,
                "type_label": get_task_type_label(type),
                "list_type_label": get_task_type_label(type),
                "page": result,
            }

        return self._run(profile, runner)

    def task_node_statistics(
        self,
        *,
        profile: str,
        app_key: str,
        type: int,
        search_key: str | None,
    ) -> dict[str, Any]:
        self._validate_type(type)
        if not app_key:
            raise_tool_error(QingflowApiError.config_error("app_key is required"))

        def runner(session_profile, context):
            params: dict[str, Any] = {
                "appKey": app_key,
                "type": type,
            }
            if search_key:
                params["searchKey"] = search_key

            result = self.backend.request("GET", context, "/task/dynamic/statics/node", params=params)
            return {
                "profile": profile,
                "ws_id": session_profile.selected_ws_id,
                "app_key": app_key,
                "type": type,
                "type_label": get_task_type_label(type),
                "list_type_label": get_task_type_label(type),
                "nodes": result,
            }

        return self._run(profile, runner)

    def task_worksheet_statistics(
        self,
        *,
        profile: str,
        type: int,
        worksheet_name: str | None,
        page_num: int,
        page_size: int,
    ) -> dict[str, Any]:
        self._validate_type(type)

        def runner(session_profile, context):
            params: dict[str, Any] = {
                "type": type,
                "pageNum": page_num,
                "pageSize": page_size,
            }
            if worksheet_name:
                params["worksheetName"] = worksheet_name

            result = self.backend.request("GET", context, "/task/dynamic/statics/worksheet", params=params)
            return {
                "profile": profile,
                "ws_id": session_profile.selected_ws_id,
                "type": type,
                "type_label": get_task_type_label(type),
                "list_type_label": get_task_type_label(type),
                "page": result,
            }

        return self._run(profile, runner)

    def task_mark_read(
        self,
        *,
        profile: str,
        app_key: str,
        id: int,
        type: int,
    ) -> dict[str, Any]:
        if not app_key:
            raise_tool_error(QingflowApiError.config_error("app_key is required"))
        if id <= 0:
            raise_tool_error(QingflowApiError.config_error("id must be positive"))
        self._validate_type(type)

        def runner(session_profile, context):
            result = self.backend.request(
                "POST",
                context,
                f"/task/dynamic/{app_key}/{id}/read/{type}",
            )
            return {
                "profile": profile,
                "ws_id": session_profile.selected_ws_id,
                "app_key": app_key,
                "id": id,
                "type": type,
                "type_label": get_task_type_label(type),
                "list_type_label": get_task_type_label(type),
                "result": result,
            }

        return self._run(profile, runner)

    def task_mark_all_cc_read(
        self,
        *,
        profile: str,
        type: int,
        process_status: int,
    ) -> dict[str, Any]:
        self._validate_type(type)
        self._validate_process_status(process_status)

        def runner(session_profile, context):
            payload: dict[str, Any] = {
                "type": type,
                "processStatus": process_status,
            }
            result = self.backend.request("POST", context, "/task/dynamic/cc/readAll", json_body=payload)
            return {
                "profile": profile,
                "ws_id": session_profile.selected_ws_id,
                "type": type,
                "type_label": get_task_type_label(type),
                "list_type_label": get_task_type_label(type),
                "process_status": process_status,
                "result": result,
            }

        return self._run(profile, runner)

    def task_urge(
        self,
        *,
        profile: str,
        app_key: str,
        row_record_id: int,
    ) -> dict[str, Any]:
        if not app_key:
            raise_tool_error(QingflowApiError.config_error("app_key is required"))
        if row_record_id <= 0:
            raise_tool_error(QingflowApiError.config_error("row_record_id must be positive"))

        def runner(session_profile, context):
            result = self.backend.request(
                "POST",
                context,
                f"/task/dynamic/{app_key}/{row_record_id}/urge",
            )
            return {
                "profile": profile,
                "ws_id": session_profile.selected_ws_id,
                "app_key": app_key,
                "row_record_id": row_record_id,
                "result": result,
            }

        return self._run(profile, runner)

    def task_group_detail(
        self,
        *,
        profile: str,
        app_key: str,
        group_id: int,
    ) -> dict[str, Any]:
        if not app_key:
            raise_tool_error(QingflowApiError.config_error("app_key is required"))
        if group_id <= 0:
            raise_tool_error(QingflowApiError.config_error("group_id must be positive"))

        def runner(session_profile, context):
            result = self.backend.request(
                "GET",
                context,
                f"/task/dynamic/app/{app_key}/group/{group_id}/detail",
            )
            return {
                "profile": profile,
                "ws_id": session_profile.selected_ws_id,
                "app_key": app_key,
                "group_id": group_id,
                "detail": result,
            }

        return self._run(profile, runner)

    def task_batch_processing_amount(
        self,
        *,
        profile: str,
        app_key: str,
        list_type: int,
        task_center_filter: dict[str, Any] | None,
    ) -> dict[str, Any]:
        if not app_key:
            raise_tool_error(QingflowApiError.config_error("app_key is required"))

        def runner(session_profile, context):
            payload: dict[str, Any] = {
                "listType": list_type,
            }
            if task_center_filter is not None:
                payload["taskCenterFilter"] = task_center_filter

            result = self.backend.request(
                "POST",
                context,
                f"/task/app/{app_key}/batchProcessingAmount",
                json_body=payload,
            )
            return {
                "profile": profile,
                "ws_id": session_profile.selected_ws_id,
                "app_key": app_key,
                "list_type": list_type,
                "list_type_label": get_record_list_type_label(list_type),
                "amount": result,
            }

        return self._run(profile, runner)

    def _validate_type(self, type: int) -> None:
        valid_types = [1, 2, 3, 5]  # TODO, INITIATED, CC, DONE
        if type not in valid_types:
            raise_tool_error(
                QingflowApiError.config_error(
                    f"Invalid type: {type}. Must be one of {valid_types} (1=待办, 2=我发起的, 3=抄送, 5=已办)"
                )
            )

    def _validate_process_status(self, process_status: int) -> None:
        valid_statuses = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
        if process_status not in valid_statuses:
            raise_tool_error(
                QingflowApiError.config_error(
                    f"Invalid process_status: {process_status}. Must be one of {valid_statuses}"
                )
            )
