from __future__ import annotations

from copy import deepcopy

from mcp.server.fastmcp import FastMCP

from ..config import DEFAULT_PROFILE
from ..errors import QingflowApiError, raise_tool_error
from ..json_types import JSONObject
from .base import ToolBase


class PackageTools(ToolBase):
    def register(self, mcp: FastMCP) -> None:
        @mcp.tool()
        def package_list(profile: str = DEFAULT_PROFILE, trial_status: str = "all") -> JSONObject:
            return self.package_list(profile=profile, trial_status=trial_status)

        @mcp.tool()
        def package_get(profile: str = DEFAULT_PROFILE, tag_id: int = 0) -> JSONObject:
            return self.package_get(profile=profile, tag_id=tag_id)

        @mcp.tool()
        def package_get_base(profile: str = DEFAULT_PROFILE, tag_id: int = 0) -> JSONObject:
            return self.package_get_base(profile=profile, tag_id=tag_id)

        @mcp.tool()
        def package_create(profile: str = DEFAULT_PROFILE, payload: JSONObject | None = None) -> JSONObject:
            return self.package_create(profile=profile, payload=payload or {})

        @mcp.tool(description=self._high_risk_tool_description(operation="update", target="app package settings"))
        def package_update(profile: str = DEFAULT_PROFILE, tag_id: int = 0, payload: JSONObject | None = None) -> JSONObject:
            return self.package_update(profile=profile, tag_id=tag_id, payload=payload or {})

        @mcp.tool(description=self._high_risk_tool_description(operation="delete", target="app package and linked data"))
        def package_delete(profile: str = DEFAULT_PROFILE, tag_id: int = 0, deleted_all_data: bool = False) -> JSONObject:
            return self.package_delete(profile=profile, tag_id=tag_id, deleted_all_data=deleted_all_data)

    def package_list(self, *, profile: str, trial_status: str = "all") -> JSONObject:
        def runner(session_profile, context):
            result = self.backend.request("GET", context, "/tag", params={"trialStatus": trial_status})
            return {"profile": profile, "ws_id": session_profile.selected_ws_id, "items": result}

        return self._run(profile, runner)

    def package_get(self, *, profile: str, tag_id: int) -> JSONObject:
        self._require_tag_id(tag_id)

        def runner(session_profile, context):
            result = self.backend.request("GET", context, f"/tag/{tag_id}")
            return {"profile": profile, "ws_id": session_profile.selected_ws_id, "tag_id": tag_id, "result": result}

        return self._run(profile, runner)

    def package_get_base(self, *, profile: str, tag_id: int) -> JSONObject:
        self._require_tag_id(tag_id)

        def runner(session_profile, context):
            result = self.backend.request("GET", context, f"/tag/{tag_id}/baseInfo")
            return {"profile": profile, "ws_id": session_profile.selected_ws_id, "tag_id": tag_id, "result": result}

        return self._run(profile, runner)

    def package_create(self, *, profile: str, payload: JSONObject) -> JSONObject:
        body = self._require_dict(payload)

        def runner(session_profile, context):
            result = self.backend.request("POST", context, "/tag", json_body=self._normalize_package_payload(body))
            return {"profile": profile, "ws_id": session_profile.selected_ws_id, "result": result}

        return self._run(profile, runner)

    def package_update(self, *, profile: str, tag_id: int, payload: JSONObject) -> JSONObject:
        self._require_tag_id(tag_id)
        body = self._require_dict(payload)

        def runner(session_profile, context):
            current = self.backend.request("GET", context, f"/tag/{tag_id}")
            result = self.backend.request(
                "PUT",
                context,
                f"/tag/{tag_id}",
                json_body=self._normalize_package_payload(body, existing=current),
            )
            return self._attach_human_review_notice(
                {"profile": profile, "ws_id": session_profile.selected_ws_id, "tag_id": tag_id, "result": result},
                operation="update",
                target="app package settings",
            )

        return self._run(profile, runner)

    def package_delete(self, *, profile: str, tag_id: int, deleted_all_data: bool = False) -> JSONObject:
        self._require_tag_id(tag_id)

        def runner(session_profile, context):
            result = self.backend.request(
                "DELETE",
                context,
                "/tag",
                json_body={"tagId": tag_id, "deletedAllData": deleted_all_data},
            )
            return self._attach_human_review_notice(
                {"profile": profile, "ws_id": session_profile.selected_ws_id, "tag_id": tag_id, "deleted_all_data": deleted_all_data, "result": result},
                operation="delete",
                target="app package and linked data",
            )

        return self._run(profile, runner)

    def _require_tag_id(self, tag_id: int) -> None:
        if tag_id <= 0:
            raise_tool_error(QingflowApiError.config_error("tag_id must be positive"))

    def _normalize_package_payload(self, payload: JSONObject, existing: JSONObject | None = None) -> JSONObject:
        data = deepcopy(existing) if isinstance(existing, dict) else {}
        data.update(deepcopy(payload))
        data.pop("tagId", None)
        data.pop("createTime", None)
        data.pop("creator", None)
        data.pop("publishStatus", None)
        data.pop("beingTrial", None)
        data.pop("trialExpireDate", None)
        data.setdefault("tagIcon", "")
        data.setdefault("tagItems", [])
        data.setdefault("auth", _default_package_auth())
        return data


def _default_package_auth() -> JSONObject:
    members = {
        "depart": [],
        "dynamic": [],
        "includeSubDeparts": None,
        "member": [],
        "role": [],
    }
    return {
        "type": "WORKSPACE",
        "contactAuth": {"type": "WORKSPACE_ALL", "authMembers": deepcopy(members)},
        "externalMemberAuth": {"type": "NOT", "authMembers": deepcopy(members)},
    }
