"""API Tools: Datasets (v2)"""
import json
from urllib.parse import quote as urlquote
from mcp.server.fastmcp import FastMCP
from http_client import fluig_get, fluig_post, fluig_patch, fluig_delete


def register(mcp: FastMCP):

    # ── CRUD DE DATASETS ───────────────────────────────────────

    @mcp.tool()
    async def fluig_dataset_listar(
        dataset_id: str = "",
        busca: str = "",
        ativo: str = "",
        tipo: str = "",
        pagina: int = 0,
        tamanho: int = 20,
        ordem: str = "",
    ) -> str:
        """
        Pesquisa datasets disponíveis no servidor Fluig.

        Args:
            dataset_id: Filtrar por ID exato do dataset.
            busca: Termo de busca textual.
            ativo: Filtrar por status: 'true' ou 'false'.
            tipo: Filtrar por tipo de dataset.
            pagina: Página de resultados (começa em 0).
            tamanho: Itens por página.
            ordem: Campo de ordenação.
        """
        params: dict = {"page": pagina, "pageSize": tamanho}
        if dataset_id:
            params["datasetId"] = dataset_id
        if busca:
            params["search"] = busca
        if ativo:
            params["active"] = ativo
        if tipo:
            params["type"] = tipo
        if ordem:
            params["order"] = ordem
        return await fluig_get("/api/v2/datasets", params)

    @mcp.tool()
    async def fluig_dataset_criar(
        dataset_obj: str,
        ignorar_conflitos: bool = False,
    ) -> str:
        """
        Registra um novo dataset no Fluig.

        Args:
            dataset_obj: JSON object representando o dataset. Ex: '{"datasetId":"ds_teste","datasetDescription":"Meu dataset","datasetImpl":"function createDataset..."}'.
            ignorar_conflitos: Se True, ignora conflitos ao registrar.
        """
        try:
            body = json.loads(dataset_obj)
        except json.JSONDecodeError as e:
            return f"Erro: dataset_obj JSON invalido - {e}"
        params = {}
        if ignorar_conflitos:
            params["ignoreConflicts"] = "true"
        return await fluig_post("/api/v2/datasets", body, params if params else None)

    @mcp.tool()
    async def fluig_dataset_desativar(dataset_id: str) -> str:
        """
        Desativa um dataset.

        Args:
            dataset_id: ID do dataset a desativar.
        """
        safe_id = urlquote(str(dataset_id), safe="")
        return await fluig_post(f"/api/v2/datasets/disable/{safe_id}")

    @mcp.tool()
    async def fluig_dataset_ativar(dataset_id: str) -> str:
        """
        Ativa um dataset desativado.

        Args:
            dataset_id: ID do dataset a ativar.
        """
        safe_id = urlquote(str(dataset_id), safe="")
        return await fluig_post(f"/api/v2/datasets/enable/{safe_id}")

    @mcp.tool()
    async def fluig_dataset_converter(dataset_id: str) -> str:
        """
        Converte o tipo de um dataset.

        Args:
            dataset_id: ID do dataset a converter.
        """
        safe_id = urlquote(str(dataset_id), safe="")
        return await fluig_post(f"/api/v2/datasets/convert/{safe_id}")

    @mcp.tool()
    async def fluig_dataset_exportar(body_json: str) -> str:
        """
        Exporta datasets para um servidor remoto.

        Args:
            body_json: JSON object com configuracoes de exportacao (servidor destino, datasets, etc).
        """
        try:
            body = json.loads(body_json)
        except json.JSONDecodeError as e:
            return f"Erro: body_json invalido - {e}"
        return await fluig_post("/api/v2/datasets/export", body)

    @mcp.tool()
    async def fluig_dataset_importar(body_json: str) -> str:
        """
        Importa datasets de um servidor remoto.

        Args:
            body_json: JSON object com configuracoes de importacao.
        """
        try:
            body = json.loads(body_json)
        except json.JSONDecodeError as e:
            return f"Erro: body_json invalido - {e}"
        return await fluig_post("/api/v2/datasets/import", body)

    @mcp.tool()
    async def fluig_dataset_sincronizar(
        dataset_id: str,
        habilitar: bool = True,
    ) -> str:
        """
        Habilita ou desabilita a sincronizacao de um dataset.

        Args:
            dataset_id: ID do dataset.
            habilitar: True para habilitar, False para desabilitar.
        """
        safe_id = urlquote(str(dataset_id), safe="")
        body = {"enabled": habilitar}
        return await fluig_patch(f"/api/v2/datasets/synchronize/{safe_id}", body)

    # ── CONSULTA DE DADOS ──────────────────────────────────────

    @mcp.tool()
    async def fluig_dataset_consultar(
        dataset_id: str,
        campos: str = "[]",
        offset: int = 0,
        limit: int = 100,
        orderby: str = "",
        constraints: str = "[]",
    ) -> str:
        """
        Consulta valores/dados de um dataset com filtros (constraints).

        Args:
            dataset_id: Nome/ID do dataset (obrigatorio). Ex: 'ColleagueDS'.
            campos: JSON array de campos a retornar. Ex: '["colleagueId","colleagueName"]'. Vazio = todos.
            offset: Offset para paginacao.
            limit: Limite de registros retornados.
            orderby: Campo de ordenacao.
            constraints: JSON array de constraints. Cada constraint e um objeto com: constraintField, initialValue, finalValue, type (MUST/SHOULD/MUST_NOT), likeSearch (true/false). Ex: '[{"constraintField":"colleagueName","initialValue":"Joao","finalValue":"Joao","type":"MUST","likeSearch":false}]'.
        """
        try:
            campos_list = json.loads(campos)
            constraints_list = json.loads(constraints)
        except json.JSONDecodeError as e:
            return f"Erro: parametro JSON invalido - {e}"

        params: dict = {
            "datasetId": dataset_id,
            "offset": offset,
            "limit": limit,
        }
        if campos_list:
            params["field[]"] = campos_list
        if orderby:
            params["orderby"] = orderby

        # Montar arrays de constraints
        if constraints_list:
            cf, ci, cfin, ct, cl = [], [], [], [], []
            for c in constraints_list:
                cf.append(c.get("constraintField", ""))
                ci.append(c.get("initialValue", ""))
                cfin.append(c.get("finalValue", ""))
                ct.append(str(c.get("type", "MUST")))
                cl.append(str(c.get("likeSearch", "false")).lower())
            params["constraintsField[]"] = cf
            params["constraintsInitialValue[]"] = ci
            params["constraintsFinalValue[]"] = cfin
            params["constraintsType[]"] = ct
            params["constraintsLikeSearch[]"] = cl

        return await fluig_get("/api/v2/dataset-handle/search", params)

    # ── HISTORICO ──────────────────────────────────────────────

    @mcp.tool()
    async def fluig_dataset_historico(
        dataset_id: str = "",
        status: str = "",
        versao: str = "",
        pagina: int = 0,
        tamanho: int = 20,
    ) -> str:
        """
        Retorna o historico de versoes de datasets.

        Args:
            dataset_id: Filtrar por ID do dataset.
            status: Filtrar por status.
            versao: Filtrar por versao.
            pagina: Pagina de resultados.
            tamanho: Itens por pagina.
        """
        params: dict = {"page": pagina, "pageSize": tamanho}
        if dataset_id:
            params["datasetId"] = dataset_id
        if status:
            params["status"] = status
        if versao:
            params["version"] = versao
        return await fluig_get("/api/v2/dataset-history", params)

    @mcp.tool()
    async def fluig_dataset_draft_criar(body_json: str) -> str:
        """
        Cria um rascunho (draft) de dataset.

        Args:
            body_json: JSON object com dados do draft.
        """
        try:
            body = json.loads(body_json)
        except json.JSONDecodeError as e:
            return f"Erro: body_json invalido - {e}"
        return await fluig_post("/api/v2/dataset-history/drafts", body)

    @mcp.tool()
    async def fluig_dataset_draft_excluir(dataset_id: str) -> str:
        """
        Remove o rascunho (draft) de um dataset.

        Args:
            dataset_id: ID do dataset cujo draft sera removido.
        """
        return await fluig_delete("/api/v2/dataset-history/drafts", {"datasetId": dataset_id})

    @mcp.tool()
    async def fluig_dataset_restaurar_versao(
        dataset_id: str,
        versao: int,
    ) -> str:
        """
        Restaura uma versao anterior de um dataset.

        Args:
            dataset_id: ID do dataset.
            versao: Numero da versao a restaurar.
        """
        return await fluig_post(
            "/api/v2/dataset-history/restore",
            params={"datasetId": dataset_id, "version": versao},
        )
