import { v } from "convex/values";
import { mutation, query } from "./_generated/server";
import type { Id } from "./_generated/dataModel";

/**
 * Lista de menus do sistema
 */
export const MENUS_SISTEMA = [
  { path: "/recursos-humanos", nome: "Recursos Humanos", descricao: "Gestão de funcionários e símbolos" },
  { path: "/recursos-humanos/funcionarios", nome: "Funcionários", descricao: "Cadastro e gestão de funcionários" },
  { path: "/recursos-humanos/simbolos", nome: "Símbolos", descricao: "Cadastro e gestão de símbolos" },
  { path: "/financeiro", nome: "Financeiro", descricao: "Gestão financeira" },
  { path: "/controladoria", nome: "Controladoria", descricao: "Controle e auditoria" },
  { path: "/licitacoes", nome: "Licitações", descricao: "Gestão de licitações" },
  { path: "/compras", nome: "Compras", descricao: "Gestão de compras" },
  { path: "/juridico", nome: "Jurídico", descricao: "Departamento jurídico" },
  { path: "/comunicacao", nome: "Comunicação", descricao: "Gestão de comunicação" },
  { path: "/programas-esportivos", nome: "Programas Esportivos", descricao: "Gestão de programas esportivos" },
  { path: "/secretaria-executiva", nome: "Secretaria Executiva", descricao: "Secretaria executiva" },
  { path: "/gestao-pessoas", nome: "Gestão de Pessoas", descricao: "Gestão de recursos humanos" },
  { path: "/ti", nome: "Tecnologia da Informação", descricao: "TI e suporte técnico" },
  { path: "/ti/painel-administrativo", nome: "Painel Administrativo TI", descricao: "Painel de administração do sistema" },
  { path: "/ti/monitoramento", nome: "Monitoramento SGSE", descricao: "Monitoramento técnico do sistema em tempo real" },
] as const;

/**
 * Listar todas as permissões de menu para uma role
 */
export const listarPorRole = query({
  args: { roleId: v.id("roles") },
  returns: v.array(
    v.object({
      _id: v.id("menuPermissoes"),
      roleId: v.id("roles"),
      menuPath: v.string(),
      podeAcessar: v.boolean(),
      podeConsultar: v.boolean(),
      podeGravar: v.boolean(),
    })
  ),
  handler: async (ctx, args) => {
    return await ctx.db
      .query("menuPermissoes")
      .withIndex("by_role", (q) => q.eq("roleId", args.roleId))
      .collect();
  },
});

/**
 * Verificar se um usuário tem permissão para acessar um menu
 * Prioridade: Permissão personalizada > Permissão da role
 */
export const verificarAcesso = query({
  args: {
    usuarioId: v.id("usuarios"),
    menuPath: v.string(),
  },
  returns: v.object({
    podeAcessar: v.boolean(),
    podeConsultar: v.boolean(),
    podeGravar: v.boolean(),
    motivo: v.optional(v.string()),
  }),
  handler: async (ctx, args) => {
    // Buscar o usuário
    const usuario = await ctx.db.get(args.usuarioId);
    if (!usuario) {
      return {
        podeAcessar: false,
        podeConsultar: false,
        podeGravar: false,
        motivo: "Usuário não encontrado",
      };
    }

    // Verificar se o usuário está ativo
    if (!usuario.ativo) {
      return {
        podeAcessar: false,
        podeConsultar: false,
        podeGravar: false,
        motivo: "Usuário inativo",
      };
    }

    // Buscar a role do usuário
    const role = await ctx.db.get(usuario.roleId);
    if (!role) {
      return {
        podeAcessar: false,
        podeConsultar: false,
        podeGravar: false,
        motivo: "Role não encontrada",
      };
    }

    // Apenas TI_MASTER (nível 0) tem acesso total irrestrito
    // Admin, TI_USUARIO e outros (nível >= 1) têm permissões configuráveis
    if (role.nivel === 0) {
      return {
        podeAcessar: true,
        podeConsultar: true,
        podeGravar: true,
      };
    }

    // Dashboard e Solicitar Acesso são públicos
    if (args.menuPath === "/" || args.menuPath === "/solicitar-acesso") {
      return {
        podeAcessar: true,
        podeConsultar: true,
        podeGravar: false,
      };
    }

    // 1. Verificar se existe permissão personalizada para este usuário
    const permissaoPersonalizada = await ctx.db
      .query("menuPermissoesPersonalizadas")
      .withIndex("by_usuario_and_menu", (q) =>
        q.eq("usuarioId", args.usuarioId).eq("menuPath", args.menuPath)
      )
      .first();

    if (permissaoPersonalizada) {
      return {
        podeAcessar: permissaoPersonalizada.podeAcessar,
        podeConsultar: permissaoPersonalizada.podeConsultar,
        podeGravar: permissaoPersonalizada.podeGravar,
      };
    }

    // 2. Se não houver permissão personalizada, verificar permissão da role
    const permissaoRole = await ctx.db
      .query("menuPermissoes")
      .withIndex("by_role_and_menu", (q) =>
        q.eq("roleId", usuario.roleId).eq("menuPath", args.menuPath)
      )
      .first();

    if (!permissaoRole) {
      return {
        podeAcessar: false,
        podeConsultar: false,
        podeGravar: false,
        motivo: "Sem permissão configurada para este menu",
      };
    }

    return {
      podeAcessar: permissaoRole.podeAcessar,
      podeConsultar: permissaoRole.podeConsultar,
      podeGravar: permissaoRole.podeGravar,
    };
  },
});

/**
 * Atualizar ou criar permissão de menu para uma role
 */
export const atualizarPermissao = mutation({
  args: {
    roleId: v.id("roles"),
    menuPath: v.string(),
    podeAcessar: v.boolean(),
    podeConsultar: v.boolean(),
    podeGravar: v.boolean(),
  },
  returns: v.id("menuPermissoes"),
  handler: async (ctx, args) => {
    // Verificar se já existe uma permissão
    const existente = await ctx.db
      .query("menuPermissoes")
      .withIndex("by_role_and_menu", (q) =>
        q.eq("roleId", args.roleId).eq("menuPath", args.menuPath)
      )
      .first();

    if (existente) {
      // Atualizar permissão existente
      await ctx.db.patch(existente._id, {
        podeAcessar: args.podeAcessar,
        podeConsultar: args.podeConsultar,
        podeGravar: args.podeGravar,
      });
      return existente._id;
    } else {
      // Criar nova permissão
      return await ctx.db.insert("menuPermissoes", {
        roleId: args.roleId,
        menuPath: args.menuPath,
        podeAcessar: args.podeAcessar,
        podeConsultar: args.podeConsultar,
        podeGravar: args.podeGravar,
      });
    }
  },
});

/**
 * Remover permissão de menu
 */
export const removerPermissao = mutation({
  args: {
    permissaoId: v.id("menuPermissoes"),
  },
  returns: v.null(),
  handler: async (ctx, args) => {
    await ctx.db.delete(args.permissaoId);
    return null;
  },
});

/**
 * Inicializar permissões padrão para uma role
 */
export const inicializarPermissoesRole = mutation({
  args: {
    roleId: v.id("roles"),
  },
  returns: v.null(),
  handler: async (ctx, args) => {
    // Buscar a role
    const role = await ctx.db.get(args.roleId);
    if (!role) {
      throw new Error("Role não encontrada");
    }

    // Admin e TI não precisam de permissões específicas (acesso total)
    if (role.nivel <= 1) {
      return null;
    }

    // Para outras roles, criar permissões básicas (apenas consulta)
    for (const menu of MENUS_SISTEMA) {
      // Verificar se já existe permissão
      const existente = await ctx.db
        .query("menuPermissoes")
        .withIndex("by_role_and_menu", (q) =>
          q.eq("roleId", args.roleId).eq("menuPath", menu.path)
        )
        .first();

      if (!existente) {
        // Criar permissão padrão (sem acesso)
        await ctx.db.insert("menuPermissoes", {
          roleId: args.roleId,
          menuPath: menu.path,
          podeAcessar: false,
          podeConsultar: false,
          podeGravar: false,
        });
      }
    }

    return null;
  },
});

/**
 * Listar todos os menus do sistema
 */
export const listarMenus = query({
  args: {},
  returns: v.array(
    v.object({
      path: v.string(),
      nome: v.string(),
      descricao: v.string(),
    })
  ),
  handler: async (ctx) => {
    return MENUS_SISTEMA.map((menu) => ({
      path: menu.path,
      nome: menu.nome,
      descricao: menu.descricao,
    }));
  },
});

/**
 * Obter matriz de permissões (role x menu) para o painel de controle
 */
export const obterMatrizPermissoes = query({
  args: {},
  returns: v.array(
    v.object({
      role: v.object({
        _id: v.id("roles"),
        nome: v.string(),
        nivel: v.number(),
        descricao: v.string(),
      }),
      permissoes: v.array(
        v.object({
          menuPath: v.string(),
          menuNome: v.string(),
          podeAcessar: v.boolean(),
          podeConsultar: v.boolean(),
          podeGravar: v.boolean(),
          permissaoId: v.optional(v.id("menuPermissoes")),
        })
      ),
    })
  ),
  handler: async (ctx) => {
    // Buscar todas as roles
    // TI_MASTER (nível 0) aparece mas não é editável
    // Admin, TI_USUARIO e outros (nível >= 1) são configuráveis
    const roles = await ctx.db.query("roles").collect();

    const matriz = [];

    for (const role of roles) {
      const permissoes = [];

      for (const menu of MENUS_SISTEMA) {
        // Buscar permissão específica
        const permissao = await ctx.db
          .query("menuPermissoes")
          .withIndex("by_role_and_menu", (q) =>
            q.eq("roleId", role._id).eq("menuPath", menu.path)
          )
          .first();

        // Admin e TI têm acesso total automático
        if (role.nivel <= 1) {
          permissoes.push({
            menuPath: menu.path,
            menuNome: menu.nome,
            podeAcessar: true,
            podeConsultar: true,
            podeGravar: true,
            permissaoId: permissao?._id,
          });
        } else {
          permissoes.push({
            menuPath: menu.path,
            menuNome: menu.nome,
            podeAcessar: permissao?.podeAcessar ?? false,
            podeConsultar: permissao?.podeConsultar ?? false,
            podeGravar: permissao?.podeGravar ?? false,
            permissaoId: permissao?._id,
          });
        }
      }

      matriz.push({
        role: {
          _id: role._id,
          nome: role.nome,
          nivel: role.nivel,
          descricao: role.descricao,
        },
        permissoes,
      });
    }

    return matriz;
  },
});

/**
 * Criar ou atualizar permissão personalizada por matrícula
 */
export const atualizarPermissaoPersonalizada = mutation({
  args: {
    matricula: v.string(),
    menuPath: v.string(),
    podeAcessar: v.boolean(),
    podeConsultar: v.boolean(),
    podeGravar: v.boolean(),
  },
  returns: v.union(v.id("menuPermissoesPersonalizadas"), v.null()),
  handler: async (ctx, args) => {
    // Buscar usuário pela matrícula
    const usuario = await ctx.db
      .query("usuarios")
      .withIndex("by_matricula", (q) => q.eq("matricula", args.matricula))
      .first();

    if (!usuario) {
      throw new Error("Usuário não encontrado com esta matrícula");
    }

    // Verificar se já existe permissão personalizada
    const existente = await ctx.db
      .query("menuPermissoesPersonalizadas")
      .withIndex("by_usuario_and_menu", (q) =>
        q.eq("usuarioId", usuario._id).eq("menuPath", args.menuPath)
      )
      .first();

    if (existente) {
      // Atualizar permissão existente
      await ctx.db.patch(existente._id, {
        podeAcessar: args.podeAcessar,
        podeConsultar: args.podeConsultar,
        podeGravar: args.podeGravar,
      });
      return existente._id;
    } else {
      // Criar nova permissão
      return await ctx.db.insert("menuPermissoesPersonalizadas", {
        usuarioId: usuario._id,
        matricula: args.matricula,
        menuPath: args.menuPath,
        podeAcessar: args.podeAcessar,
        podeConsultar: args.podeConsultar,
        podeGravar: args.podeGravar,
      });
    }
  },
});

/**
 * Remover permissão personalizada
 */
export const removerPermissaoPersonalizada = mutation({
  args: {
    permissaoId: v.id("menuPermissoesPersonalizadas"),
  },
  returns: v.null(),
  handler: async (ctx, args) => {
    await ctx.db.delete(args.permissaoId);
    return null;
  },
});

/**
 * Listar permissões personalizadas de um usuário por matrícula
 */
export const listarPermissoesPersonalizadas = query({
  args: {
    matricula: v.string(),
  },
  returns: v.array(
    v.object({
      _id: v.id("menuPermissoesPersonalizadas"),
      menuPath: v.string(),
      menuNome: v.string(),
      podeAcessar: v.boolean(),
      podeConsultar: v.boolean(),
      podeGravar: v.boolean(),
    })
  ),
  handler: async (ctx, args) => {
    // Buscar usuário
    const usuario = await ctx.db
      .query("usuarios")
      .withIndex("by_matricula", (q) => q.eq("matricula", args.matricula))
      .first();

    if (!usuario) {
      return [];
    }

    // Buscar permissões personalizadas
    const permissoes = await ctx.db
      .query("menuPermissoesPersonalizadas")
      .withIndex("by_usuario", (q) => q.eq("usuarioId", usuario._id))
      .collect();

    // Mapear com nomes dos menus
    return permissoes.map((p) => {
      const menu = MENUS_SISTEMA.find((m) => m.path === p.menuPath);
      return {
        _id: p._id,
        menuPath: p.menuPath,
        menuNome: menu?.nome || p.menuPath,
        podeAcessar: p.podeAcessar,
        podeConsultar: p.podeConsultar,
        podeGravar: p.podeGravar,
      };
    });
  },
});

/**
 * Buscar usuário por matrícula para o painel de personalização
 */
export const buscarUsuarioPorMatricula = query({
  args: {
    matricula: v.string(),
  },
  returns: v.union(
    v.object({
      _id: v.id("usuarios"),
      matricula: v.string(),
      nome: v.string(),
      email: v.string(),
      role: v.object({
        nome: v.string(),
        nivel: v.number(),
        descricao: v.string(),
      }),
      ativo: v.boolean(),
    }),
    v.null()
  ),
  handler: async (ctx, args) => {
    const usuario = await ctx.db
      .query("usuarios")
      .withIndex("by_matricula", (q) => q.eq("matricula", args.matricula))
      .first();

    if (!usuario) {
      return null;
    }

    const role = await ctx.db.get(usuario.roleId);
    if (!role) {
      return null;
    }

    return {
      _id: usuario._id,
      matricula: usuario.matricula,
      nome: usuario.nome,
      email: usuario.email,
      role: {
        nome: role.nome,
        nivel: role.nivel,
        descricao: role.descricao,
      },
      ativo: usuario.ativo,
    };
  },
});

