"""Este módulo contém funções que geram constantes dinâmicas a partir da API"""

from typing import Any, Literal
import httpx
from os import getenv

from siga_mcp._types import EquipeGeralType, SituacaoUsuarioType
from siga_mcp.clients import langfuse
from siga_mcp.constants import (
    MATRICULA_USUARIO_ATUAL,
    MCP_TRANSPORT,
    NOME_USUARIO_ATUAL,
)
from siga_mcp.prompt import Prompt
from siga_mcp.utils import converter_data_siga, dict_to_markdown, buscar_constante_siga
from siga_mcp.xml_builder import XMLBuilder


# Esta função é chamada pela MCP tool e gera os dados reais para a CONSTANTE
# Busca usuários de uma equipe filtrados por gerente responsável, descrição da equipe e situação do usuário
# Contém toda a lógica de negócio: validações, normalização, requisições HTTP e processamento
# Função SÍNCRONA que faz o trabalho pesado e retorna XML com os resultados
def listar_usuarios_equipe_por_gerente(
    matricula_gerente: str | int | Literal["CURRENT_USER"] | None = None,
    descricao_equipe: EquipeGeralType | None = None,
    situacao_usuario: SituacaoUsuarioType | None = None,
) -> str:
    import requests

    # VALIDAÇÃO E NORMALIZAÇÃO DA EQUIPE (se fornecida)
    equipe_final = ""
    if descricao_equipe is not None:
        # Busca a equipe correta na constante EQUIPE_GERAL_TO_NUMBER ignorando maiúsculas/minúsculas
        equipe_normalizada = next(
            (
                key
                for key in EQUIPE_GERAL_TO_NUMBER.keys()
                if str(key).lower() == str(descricao_equipe).lower()
            ),
            None,
        )

        if equipe_normalizada is None:
            return XMLBuilder().build_xml(
                data=[
                    {
                        "status": "erro",
                        "tipo_erro": "equipe_invalida",
                        "equipe_informada": descricao_equipe,
                        "mensagem": f"Equipe '{descricao_equipe}' não encontrada na constante EQUIPE_GERAL_TO_NUMBER",
                        "equipes_validas": list(EQUIPE_GERAL_TO_NUMBER.keys()),
                    }
                ],
                root_element_name="erro_validacao",
                item_element_name="erro",
                root_attributes={
                    "sistema": "SIGA",
                    "funcao": "listar_usuarios_equipe_por_gerente",
                },
                custom_attributes={"sistema": "SIGA"},
            )

        # NORMALIZA: converte nome → código
        equipe_final = EQUIPE_GERAL_TO_NUMBER[equipe_normalizada]

    # VALIDAÇÃO E NORMALIZAÇÃO DA SITUAÇÃO (se fornecida)
    situacao_final = ""
    if situacao_usuario is not None:
        # Busca a situação correta na constante SITUACAO_USUARIO_TO_NUMBER ignorando maiúsculas/minúsculas
        situacao_normalizada = next(
            (
                key
                for key in SITUACAO_USUARIO_TO_NUMBER.keys()
                if str(key).lower() == str(situacao_usuario).lower()
            ),
            None,
        )

        if situacao_normalizada is None:
            return XMLBuilder().build_xml(
                data=[
                    {
                        "status": "erro",
                        "tipo_erro": "situacao_invalida",
                        "situacao_informada": situacao_usuario,
                        "mensagem": f"Situação '{situacao_usuario}' não encontrada na constante SITUACAO_USUARIO_TO_NUMBER",
                        "situacoes_validas": list(SITUACAO_USUARIO_TO_NUMBER.keys()),
                    }
                ],
                root_element_name="erro_validacao",
                item_element_name="erro",
                root_attributes={
                    "sistema": "SIGA",
                    "funcao": "listar_usuarios_equipe_por_gerente",
                },
                custom_attributes={"sistema": "SIGA"},
            )

        # NORMALIZA: converte nome → número
        situacao_final = SITUACAO_USUARIO_TO_NUMBER[situacao_normalizada]

    try:
        response = requests.post(
            "https://ava3.uniube.br/ava/api/usuarios/listarUsuariosEquipePorGerente/",
            json={
                "apiKey": getenv("AVA_API_KEY"),
                "matriculaGerente": str(matricula_gerente) if matricula_gerente else "",
                "equipe": str(equipe_final) if equipe_final else "",
                "situacaoUsuario": str(situacao_final) if situacao_final else "",
            },
        )

        json_response = response.json()

        # VERIFICAR SE JSON_RESPONSE É None
        if json_response is None:
            return XMLBuilder().build_xml(
                data=[
                    {
                        "status": "erro",
                        "mensagem": "API retornou resposta vazia. Verifique a configuração da API key.",
                    }
                ],
                root_element_name="resultado",
                item_element_name="item",
                custom_attributes={"sistema": "SIGA"},
            )

        result_data = json_response.get("result")

        # Trata a resposta
        if result_data is None or len(result_data) == 0:
            data_final = [
                {
                    "status": "aviso",
                    "mensagem": "Nenhum usuário encontrado para os filtros informados. Verifique se você é gerente de uma equipe ou ajuste os filtros de busca.",
                }
            ]

            # Retorna XML de aviso em vez dos dados
            return XMLBuilder().build_xml(
                data=data_final,
                root_element_name="usuarios_equipe_gerente",
                item_element_name="resultado",
                root_attributes={
                    "matriculaGerente": str(matricula_gerente)
                    if matricula_gerente
                    else "",
                    "equipe": str(equipe_final) if equipe_final else "",
                    "situacaoUsuario": str(situacao_final) if situacao_final else "",
                },
                custom_attributes={"sistema": "SIGA"},
            )
        else:
            # Se há resultados, processar normalmente
            return XMLBuilder().build_xml(
                data=result_data,
                root_element_name="usuarios_equipe_gerente",
                item_element_name="usuario_equipe_gerente",
                root_attributes={
                    "matriculaGerente": str(matricula_gerente)
                    if matricula_gerente
                    else "",
                    "equipe": str(equipe_final) if equipe_final else "",
                    "situacaoUsuario": str(situacao_final) if situacao_final else "",
                },
                custom_attributes={"sistema": "SIGA"},
            )

    except Exception as e:
        return XMLBuilder().build_xml(
            data=[
                {
                    "status": "erro",
                    "mensagem": f"Erro interno: {str(e)}. Tente novamente mais tarde.",
                }
            ],
            root_element_name="resultado",
            item_element_name="item",
            custom_attributes={"sistema": "SIGA"},
        )


# Constante com a lista de colaboradores de todas as equipes da empresa, para ser usado no prompt do sistema, durante o uso do chat do SIGA.
COLABORADORES_PROMPT: str = listar_usuarios_equipe_por_gerente()


# Obter usuário responsável para criação de OS Sistemas e Infraestrutura.
# Usado para montar o Docstring e validação na função, caso o usuário informa matrícula que não está na lista
def obter_usuarios_responsavel(
    area: int,
) -> tuple[str, set[str], list[str], dict[str, int]]:
    """
    Busca usuários responsáveis de uma área no sistema SIGA.

    Args:
        area: Código da área (1 = Sistemas, 2 = Infraestrutura)

    Returns:
        tuple contendo:
        - str: String formatada para docstrings de ferramentas MCP
        - set[str]: Conjunto de IDs para validação rápida O(1)
        - list[str]: Lista formatada para mensagens de erro
        - dict[str, int]: Dicionário {nome: id} para conversão markdown
    """
    nome_area = "Sistemas" if area == 1 else "Infraestrutura"

    try:
        # Fazer requisição HTTP para buscar usuários responsáveis
        with httpx.Client(timeout=60.0) as client:
            response = client.post(
                "https://ava3.uniube.br/ava/api/usuarios/buscarUsuarioResponsavelOsSigaIA/",
                json={
                    "apiKey": getenv("AVA_API_KEY"),
                    "area": area,
                },
            )

            # Extrair dados JSON da resposta
            json_data = response.json()
            data: list[dict[str, Any]] | dict[str, Any] = (  # type: ignore
                json_data
                if isinstance(json_data, list)
                else json_data.get("result", [])
            )

            # Validar se recebeu dados válidos
            if not data or not isinstance(data, list):
                return (
                    f"        - Erro ao carregar usuários responsáveis de {nome_area}",
                    set(),
                    [],
                    {},
                )

            # Remover duplicatas usando dict (chave = ID do usuário)
            usuarios_unicos: dict[str, dict[str, Any]] = {}
            for usuario in data:
                if (
                    isinstance(usuario, dict)  # type: ignore
                    and "USUARIO" in usuario
                    and "NOME" in usuario
                ):
                    usuarios_unicos[usuario["USUARIO"]] = usuario

            # Verificar se encontrou usuários válidos
            if not usuarios_unicos:
                return (
                    f"        - Nenhum usuário responsável encontrado para {nome_area}",
                    set(),
                    [],
                    {},
                )

            # 📝 GERAR LISTA FORMATADA PARA DOCSTRING (ordenada alfabeticamente)
            usuarios_ordenados = sorted(
                usuarios_unicos.values(), key=lambda x: x["NOME"]
            )
            docstring = "\n".join(
                [
                    f'        - "{usuario["NOME"]}" (ID: {usuario["USUARIO"]})'
                    for usuario in usuarios_ordenados
                ]
            )

            # 🔍 GERAR SET DE IDS PARA VALIDAÇÃO RÁPIDA SE O USUÁRIO ESTÁ NA LISTA DE RESPONSÁVEIS DA ÁREA
            ids_validacao = {
                str(usuario["USUARIO"]) for usuario in usuarios_unicos.values()
            }

            # 🔍 GERAR LISTA PARA MENSAGENS DE ERRO, PARA AVISAR QUE O USUÁRIO NÃO ESTÁ NA LISTA DE RESPONSÁVEIS DAQUELA ÁREA
            usuarios_para_erro = [
                f'"{usuario["NOME"]}" (ID: {usuario["USUARIO"]})'
                for usuario in usuarios_ordenados
            ]

            # DICIONÁRIO - Para dict_to_markdown
            usuarios_dict = {
                usuario["NOME"]: int(usuario["USUARIO"])
                for usuario in usuarios_ordenados
            }

            # # Retorna 4 resultados: docstring, set de ids para validação rápida, lista para mensagens de erro e dicionário
            return (docstring, ids_validacao, usuarios_para_erro, usuarios_dict)

    except Exception:
        # Retornar erro em caso de falha na requisição ou processamento
        return (
            f"        - Erro ao carregar usuários responsáveis de {nome_area}",
            set(),
            [],
            {},
        )


# ✅ CONSTANTES CACHED - Executam uma vez quando o módulo é carregado
# 📊 Buscar dados para Sistemas (área 1)
(
    USUARIOS_SISTEMAS_DOCSTRING,
    USUARIOS_SISTEMAS_IDS,
    USUARIOS_SISTEMAS_PARA_ERRO,
    USUARIOS_SISTEMAS_DICT,
) = obter_usuarios_responsavel(1)
# 🔧 Buscar dados para Infraestrutura (área 2)
(
    USUARIOS_INFRAESTRUTURA_DOCSTRING,
    USUARIOS_INFRAESTRUTURA_IDS,
    USUARIOS_INFRAESTRUTURA_PARA_ERRO,
    USUARIOS_INFRAESTRUTURA_DICT,
) = obter_usuarios_responsavel(2)


# EQUIPE_TO_NUMBER (11 equipes: Sistemas + DBA)
EQUIPE_TO_NUMBER = buscar_constante_siga(
    endpoint="https://ava3.uniube.br/ava/api/segequipes/buscarEquipesSigaIA/",
    campo_chave="DESCRICAO_EQUIPE",
    campo_valor="CODIGO_EQUIPE",
    nome_constante="Equipes Sistemas + DBA",
    params={"classe": 1, "equipesIncluir": ["DBA"]},
)

# EQUIPE_INFRAESTRUTURA_TO_NUMBER (22 equipes: Todas de Infraestrutura)
EQUIPE_INFRAESTRUTURA_TO_NUMBER = buscar_constante_siga(
    endpoint="https://ava3.uniube.br/ava/api/segequipes/buscarEquipesSigaIA/",
    campo_chave="DESCRICAO_EQUIPE",
    campo_valor="CODIGO_EQUIPE",
    nome_constante="Equipes Infraestrutura",
    params={"classe": 2},
)

# EQUIPE_GERAL_TO_NUMBER (33 equipes: Todas)
EQUIPE_GERAL_TO_NUMBER = buscar_constante_siga(
    endpoint="https://ava3.uniube.br/ava/api/segequipes/buscarEquipesSigaIA/",
    campo_chave="DESCRICAO_EQUIPE",
    campo_valor="CODIGO_EQUIPE",
    nome_constante="Equipes Geral",
)

# Buca todos os tipos ativos (11 tipos - Todos ativos)
TYPE_TO_NUMBER = buscar_constante_siga(
    endpoint="https://ava3.uniube.br/ava/api/segTiposOs/buscarTiposOsSigaIA/",
    campo_chave="DESCRICAO_TIPO",
    campo_valor="CODIGO_TIPO",
    nome_constante="Type to Number",
    params={"ativo": 1},
)

# Busca os Tipos para Atendimento Avulso Sistemas (3 tipos específicos)
TIPO_TO_NUMBER_ATENDIMENTO_AVULSO = buscar_constante_siga(
    endpoint="https://ava3.uniube.br/ava/api/segTiposOs/buscarTiposOsSigaIA/",
    campo_chave="DESCRICAO_TIPO",
    campo_valor="CODIGO_TIPO",
    nome_constante="Tipo Atendimento Avulso Sistemas",
    params={"tiposIncluir": [1, 10, 19]},
)

# Busca os Tipos para Atendimento Avulso infraestrutura (10 tipos específicos)
TIPO_TO_NUMBER_ATENDIMENTO_AVULSO_INFRAESTRUTURA = buscar_constante_siga(
    endpoint="https://ava3.uniube.br/ava/api/segTiposOs/buscarTiposOsSigaIA/",
    campo_chave="DESCRICAO_TIPO",
    campo_valor="CODIGO_TIPO",
    nome_constante="Tipo Atendimento Avulso Infraestrutura",
    params={"classe": 2},
)

# Busca os Tipos para Atendimentos OS (7 tipos - Sistemas ativos, exceto Reunião e Anexo)
TIPO_TO_NUMBER_OS_SISTEMAS = buscar_constante_siga(
    endpoint="https://ava3.uniube.br/ava/api/segTiposOs/buscarTiposOsSigaIA/",
    campo_chave="DESCRICAO_TIPO",
    campo_valor="CODIGO_TIPO",
    nome_constante="Tipo OS Sistemas",
    params={"classe": 1, "ativo": 1, "tiposExcluir": [4, 12]},
)

# Busca Projetos para OS automática do banco de dados via API
PROJETO_TO_NUMBER = buscar_constante_siga(
    endpoint="https://ava3.uniube.br/ava/api/segProjetos/buscarProjetosOsSigaIA/",
    campo_chave="DESCRICAO_PROJETO",
    campo_valor="CODIGO_PROJETO",
    nome_constante="Projetos OS Sistemas",
)

# Busca Origens para Atendimentos Avulsos (7 origens, exceto "SATIC" e "Siga")
ORIGEM_TO_NUMBER = buscar_constante_siga(
    endpoint="https://ava3.uniube.br/ava/api/segorigens/buscarOrigensSigaIA/",
    campo_chave="DESCRICAO_ORIGEM",
    campo_valor="CODIGO_ORIGEM",
    nome_constante="Origens Atendimentos Avulso",
    params={"origensExcluir": [6, 8]},
)

# Busca Origens para Atendimentos para OS (todos existentes)
ORIGEM_OS_TO_NUMBER = buscar_constante_siga(
    endpoint="https://ava3.uniube.br/ava/api/segorigens/buscarOrigensSigaIA/",
    campo_chave="DESCRICAO_ORIGEM",
    campo_valor="CODIGO_ORIGEM",
    nome_constante="Origens OS",
)

# Busca Listagem para OS automática do banco de dados via API
LINGUAGEM_TO_NUMBER_OS_SISTEMAS = buscar_constante_siga(
    endpoint="https://ava3.uniube.br/ava/api/seglinguagens/buscarLinguagensOsSigaIA/",
    campo_chave="DESCRICAO_LINGUAGEM",
    campo_valor="CODIGO_LINGUAGEM",
    nome_constante="Linguagens OS Sistemas",
)

# Busca Sistemas para OS automática do banco de dados via API
SISTEMA_TO_NUMBER = buscar_constante_siga(
    endpoint="https://ava3.uniube.br/ava/api/segSistemas/buscarSistemasOsSigaIA/",
    campo_chave="DESCRICAO_SISTEMA",
    campo_valor="CODIGO_SISTEMA",
    nome_constante="Sistemas OS Sistemas",
)

# Busca Categorias para OS automática do banco de dados via API
CATEGORIA_TO_NUMBER = buscar_constante_siga(
    endpoint="https://ava3.uniube.br/ava/api/segoscategorias/buscarCategoriasOsSigaIA/",
    campo_chave="DESCRICAO_CATEGORIA",
    campo_valor="CODIGO_CATEGORIA",
    nome_constante="Categorias OS Infraestrutura",
)

# Listagem para a Combo Status para OS.
STATUS_OS_TO_NUMBER = buscar_constante_siga(
    endpoint="https://ava3.uniube.br/ava/api/segstatus/buscarStatusOsSigaIA/",
    campo_chave="DESCRICAO_STATUS",
    campo_valor="CODIGO_STATUS",
    nome_constante="Status OS",
)

# Listagem para a Combo Interna para OS.
OS_INTERNA_OS_TO_NUMBER = {
    "Sim": 1,
    "Não": 0,
}

# Listagem para a Combo Criticidade para OS.
CRITICIDADE_OS_TO_NUMBER = {
    "Nenhuma": 0,
    "Baixa": 1,
    "Média": 2,
    "Alta": 3,
}

# Listagem para a Combo Criticidade para OS.
PRIORIDADE_USUARIO_OS_TO_NUMBER = {
    "Nenhuma": 0,
    "Urgente": 1,
    "Alta": 2,
    "Média": 3,
    "Baixa": 4,
}

# Constante para situação do usuário
SITUACAO_USUARIO_TO_NUMBER = {
    "Bloqueado": 0,
    "Ativo": 1,
    "Bloqueado (Afastamento)": 2,
    "Bloqueado pelo RH (Individual)": 3,
    "Bloqueado por Falta de Justificativa de Ponto (Individual)": 4,
    "Bloqueado Licença sem Remuneração": 5,
}

constantes_md = dict_to_markdown(
    ("tipos do atendimento os", TYPE_TO_NUMBER),
    ("tipos atendimento avulso sistemas", TIPO_TO_NUMBER_ATENDIMENTO_AVULSO),
    (
        "tipos atendimento avulso infraestrutura",
        TIPO_TO_NUMBER_ATENDIMENTO_AVULSO_INFRAESTRUTURA,
    ),
    ("tipos atendimentos sistemas os", TIPO_TO_NUMBER_OS_SISTEMAS),
    ("origens atendimentos avulsos", ORIGEM_TO_NUMBER),
    ("origens os", ORIGEM_OS_TO_NUMBER),
    ("sistemas", SISTEMA_TO_NUMBER),
    ("categorias", CATEGORIA_TO_NUMBER),
    ("equipes sistemas", EQUIPE_TO_NUMBER),
    ("equipes infraestrutura", EQUIPE_INFRAESTRUTURA_TO_NUMBER),
    ("equipe geral", EQUIPE_GERAL_TO_NUMBER),
    ("projetos", PROJETO_TO_NUMBER),
    ("linguagens programação", LINGUAGEM_TO_NUMBER_OS_SISTEMAS),
    ("os interna", OS_INTERNA_OS_TO_NUMBER),
    ("status os", STATUS_OS_TO_NUMBER),
    ("criticidade", CRITICIDADE_OS_TO_NUMBER),
    ("prioridade do usuario os", PRIORIDADE_USUARIO_OS_TO_NUMBER),
    ("situação do usuário os", SITUACAO_USUARIO_TO_NUMBER),
    ("usuarios responsaveis sistemas", USUARIOS_SISTEMAS_DICT),
    ("usuários responsáveis infraestrutura", USUARIOS_INFRAESTRUTURA_DICT),
)

SYSTEM_INSTRUCTIONS: Prompt = Prompt.from_text(
    langfuse.get_prompt("siga.developer").compile()
).compile(constantes=constantes_md)

if MCP_TRANSPORT == "stdio":
    SYSTEM_INSTRUCTIONS.compile(
        colaboradores=COLABORADORES_PROMPT,
        data=converter_data_siga("hoje"),
        nome_usuario=NOME_USUARIO_ATUAL,
        matricula=MATRICULA_USUARIO_ATUAL,
        preferencias_usuario=getenv("USER_PREFERENCES", "Sem preferências definidas."),
        constantes=constantes_md,
    )
