import { defineSchema, defineTable } from "convex/server";
import { Infer, v } from "convex/values";

export const simboloTipo = v.union(
  v.literal("cargo_comissionado"),
  v.literal("funcao_gratificada")
);
export type SimboloTipo = Infer<typeof simboloTipo>;

export const ataqueCiberneticoTipo = v.union(
  v.literal("phishing"),
  v.literal("malware"),
  v.literal("ransomware"),
  v.literal("brute_force"),
  v.literal("credential_stuffing"),
  v.literal("sql_injection"),
  v.literal("xss"),
  v.literal("path_traversal"),
  v.literal("command_injection"),
  v.literal("nosql_injection"),
  v.literal("xxe"),
  v.literal("man_in_the_middle"),
  v.literal("ddos"),
  v.literal("engenharia_social"),
  v.literal("cve_exploit"),
  v.literal("apt"),
  v.literal("zero_day"),
  v.literal("supply_chain"),
  v.literal("fileless_malware"),
  v.literal("polymorphic_malware"),
  v.literal("ransomware_lateral"),
  v.literal("deepfake_phishing"),
  v.literal("adversarial_ai"),
  v.literal("side_channel"),
  v.literal("firmware_bootloader"),
  v.literal("bec"),
  v.literal("botnet"),
  v.literal("ot_ics"),
  v.literal("quantum_attack")
);
export type AtaqueCiberneticoTipo = Infer<typeof ataqueCiberneticoTipo>;

export const severidadeSeguranca = v.union(
  v.literal("informativo"),
  v.literal("baixo"),
  v.literal("moderado"),
  v.literal("alto"),
  v.literal("critico")
);
export type SeveridadeSeguranca = Infer<typeof severidadeSeguranca>;

export const statusEventoSeguranca = v.union(
  v.literal("detectado"),
  v.literal("investigando"),
  v.literal("contido"),
  v.literal("falso_positivo"),
  v.literal("escalado"),
  v.literal("resolvido")
);
export type StatusEventoSeguranca = Infer<typeof statusEventoSeguranca>;

export const sensorSegurancaTipo = v.union(
  v.literal("network"),
  v.literal("endpoint"),
  v.literal("application"),
  v.literal("gateway"),
  v.literal("ot"),
  v.literal("honeypot")
);
export type SensorSegurancaTipo = Infer<typeof sensorSegurancaTipo>;

export const sensorSegurancaStatus = v.union(
  v.literal("ativo"),
  v.literal("inativo"),
  v.literal("degradado"),
  v.literal("manutencao")
);
export type SensorSegurancaStatus = Infer<typeof sensorSegurancaStatus>;

export const threatIntelTipo = v.union(
  v.literal("open_source"),
  v.literal("commercial"),
  v.literal("internal"),
  v.literal("gov"),
  v.literal("research")
);

export const threatIntelFormato = v.union(
  v.literal("json"),
  v.literal("stix"),
  v.literal("csv"),
  v.literal("text"),
  v.literal("custom")
);

export const acaoIncidenteTipo = v.union(
  v.literal("block_ip"),
  v.literal("unblock_ip"),
  v.literal("block_port"),
  v.literal("liberar_porta"),
  v.literal("notificar"),
  v.literal("isolar_host"),
  v.literal("gerar_relatorio"),
  v.literal("criar_ticket"),
  v.literal("ajuste_regra"),
  v.literal("custom")
);

export const acaoIncidenteStatus = v.union(
  v.literal("pendente"),
  v.literal("executando"),
  v.literal("concluido"),
  v.literal("falhou")
);

export const reportStatus = v.union(
  v.literal("pendente"),
  v.literal("processando"),
  v.literal("concluido"),
  v.literal("falhou")
);

// Status de templates de fluxo
export const flowTemplateStatus = v.union(
  v.literal("draft"),
  v.literal("published"),
  v.literal("archived")
);
export type FlowTemplateStatus = Infer<typeof flowTemplateStatus>;

// Status de instâncias de fluxo
export const flowInstanceStatus = v.union(
  v.literal("active"),
  v.literal("completed"),
  v.literal("cancelled")
);
export type FlowInstanceStatus = Infer<typeof flowInstanceStatus>;

// Status de passos de instância de fluxo
export const flowInstanceStepStatus = v.union(
  v.literal("pending"),
  v.literal("in_progress"),
  v.literal("completed"),
  v.literal("blocked")
);
export type FlowInstanceStepStatus = Infer<typeof flowInstanceStepStatus>;

export const situacaoContrato = v.union(
  v.literal("em_execucao"),
  v.literal("rescendido"),
  v.literal("aguardando_assinatura"),
  v.literal("finalizado")
);

export default defineSchema({
  // Setores da organização
  setores: defineTable({
    nome: v.string(),
    sigla: v.string(),
    criadoPor: v.id("usuarios"),
    createdAt: v.number(),
  })
    .index("by_nome", ["nome"])
    .index("by_sigla", ["sigla"]),

  // Relação muitos-para-muitos entre funcionários e setores
  funcionarioSetores: defineTable({
    funcionarioId: v.id("funcionarios"),
    setorId: v.id("setores"),
    createdAt: v.number(),
  })
    .index("by_funcionarioId", ["funcionarioId"])
    .index("by_setorId", ["setorId"])
    .index("by_funcionarioId_and_setorId", ["funcionarioId", "setorId"]),

  // Templates de fluxo
  flowTemplates: defineTable({
    name: v.string(),
    description: v.optional(v.string()),
    status: flowTemplateStatus,
    createdBy: v.id("usuarios"),
    createdAt: v.number(),
  })
    .index("by_status", ["status"])
    .index("by_createdBy", ["createdBy"]),

  // Passos de template de fluxo
  flowSteps: defineTable({
    flowTemplateId: v.id("flowTemplates"),
    name: v.string(),
    description: v.optional(v.string()),
    position: v.number(),
    expectedDuration: v.number(), // em dias
    setorId: v.id("setores"),
    defaultAssigneeId: v.optional(v.id("usuarios")),
    requiredDocuments: v.optional(v.array(v.string())),
  })
    .index("by_flowTemplateId", ["flowTemplateId"])
    .index("by_flowTemplateId_and_position", ["flowTemplateId", "position"]),

  // Instâncias de fluxo
  flowInstances: defineTable({
    flowTemplateId: v.id("flowTemplates"),
    contratoId: v.optional(v.id("contratos")),
    managerId: v.id("usuarios"),
    status: flowInstanceStatus,
    startedAt: v.number(),
    finishedAt: v.optional(v.number()),
    currentStepId: v.optional(v.id("flowInstanceSteps")),
  })
    .index("by_flowTemplateId", ["flowTemplateId"])
    .index("by_contratoId", ["contratoId"])
    .index("by_managerId", ["managerId"])
    .index("by_status", ["status"]),

  // Passos de instância de fluxo
  flowInstanceSteps: defineTable({
    flowInstanceId: v.id("flowInstances"),
    flowStepId: v.id("flowSteps"),
    setorId: v.id("setores"),
    assignedToId: v.optional(v.id("usuarios")),
    status: flowInstanceStepStatus,
    startedAt: v.optional(v.number()),
    finishedAt: v.optional(v.number()),
    notes: v.optional(v.string()),
    notesUpdatedBy: v.optional(v.id("usuarios")),
    notesUpdatedAt: v.optional(v.number()),
    dueDate: v.optional(v.number()),
  })
    .index("by_flowInstanceId", ["flowInstanceId"])
    .index("by_flowInstanceId_and_status", ["flowInstanceId", "status"])
    .index("by_setorId", ["setorId"])
    .index("by_assignedToId", ["assignedToId"]),

  // Documentos de instância de fluxo
  flowInstanceDocuments: defineTable({
    flowInstanceStepId: v.id("flowInstanceSteps"),
    uploadedById: v.id("usuarios"),
    storageId: v.id("_storage"),
    name: v.string(),
    uploadedAt: v.number(),
  })
    .index("by_flowInstanceStepId", ["flowInstanceStepId"])
    .index("by_uploadedById", ["uploadedById"]),

  // Sub-etapas de fluxo (para templates e instâncias)
  flowSubSteps: defineTable({
    flowStepId: v.optional(v.id("flowSteps")), // Para templates
    flowInstanceStepId: v.optional(v.id("flowInstanceSteps")), // Para instâncias
    name: v.string(),
    description: v.optional(v.string()),
    status: v.union(
      v.literal("pending"),
      v.literal("in_progress"),
      v.literal("completed"),
      v.literal("blocked")
    ),
    position: v.number(),
    createdBy: v.id("usuarios"),
    createdAt: v.number(),
  })
    .index("by_flowStepId", ["flowStepId"])
    .index("by_flowInstanceStepId", ["flowInstanceStepId"]),

  // Notas de steps e sub-etapas
  flowStepNotes: defineTable({
    flowStepId: v.optional(v.id("flowSteps")),
    flowInstanceStepId: v.optional(v.id("flowInstanceSteps")),
    flowSubStepId: v.optional(v.id("flowSubSteps")),
    texto: v.string(),
    criadoPor: v.id("usuarios"),
    criadoEm: v.number(),
    arquivos: v.array(v.id("_storage")),
  })
    .index("by_flowStepId", ["flowStepId"])
    .index("by_flowInstanceStepId", ["flowInstanceStepId"])
    .index("by_flowSubStepId", ["flowSubStepId"]),

  contratos: defineTable({
    contratadaId: v.id("empresas"),
    objeto: v.string(),
    numeroNotaEmpenho: v.string(),
    responsavelId: v.id("funcionarios"),
    departamento: v.string(),
    situacao: situacaoContrato,
    numeroProcessoLicitatorio: v.string(),
    modalidade: v.string(),
    numeroContrato: v.string(),
    anoContrato: v.number(),
    dataInicioVigencia: v.string(),
    dataFimVigencia: v.string(),
    nomeFiscal: v.string(),
    valorTotal: v.string(),
    dataAditivoPrazo: v.optional(v.string()),
    diasAvisoVencimento: v.number(),
    criadoPor: v.id("usuarios"),
    criadoEm: v.number(),
    atualizadoEm: v.optional(v.number()),
  })
    .index("by_responsavel", ["responsavelId"])
    .index("by_situacao", ["situacao"])
    .index("by_vigencia_inicio", ["dataInicioVigencia"])
    .index("by_vigencia_fim", ["dataFimVigencia"]),

  todos: defineTable({
    text: v.string(),
    completed: v.boolean(),
  }),
  enderecos: defineTable({
    cep: v.string(),
    logradouro: v.string(),
    numero: v.string(),
    complemento: v.optional(v.string()),
    bairro: v.string(),
    cidade: v.string(),
    uf: v.string(),
    criadoPor: v.optional(v.id("usuarios")),
    atualizadoPor: v.optional(v.id("usuarios")),
  }).index("by_cep", ["cep"]),
  empresas: defineTable({
    razao_social: v.string(),
    nome_fantasia: v.optional(v.string()),
    cnpj: v.string(),
    telefone: v.string(),
    email: v.string(),
    descricao: v.optional(v.string()),
    enderecoId: v.optional(v.id("enderecos")),
    criadoPor: v.optional(v.id("usuarios")),
  })
    .index("by_razao_social", ["razao_social"])
    .index("by_cnpj", ["cnpj"]),
  contatosEmpresa: defineTable({
    empresaId: v.id("empresas"),
    nome: v.string(),
    funcao: v.string(),
    email: v.string(),
    telefone: v.string(),
    adicionadoPor: v.optional(v.id("usuarios")),
    descricao: v.optional(v.string()),
  })
    .index("by_empresa", ["empresaId"])
    .index("by_email", ["email"]),
  funcionarios: defineTable({
    // Campos obrigatórios existentes
    nome: v.string(),
    nascimento: v.string(),
    rg: v.string(),
    cpf: v.string(),
    endereco: v.string(),
    cep: v.string(),
    cidade: v.string(),
    uf: v.string(),
    telefone: v.string(),
    email: v.string(),
    matricula: v.optional(v.string()),
    admissaoData: v.optional(v.string()),
    desligamentoData: v.optional(v.string()),
    simboloId: v.id("simbolos"),
    simboloTipo: simboloTipo,
    gestorId: v.optional(v.id("usuarios")),
    statusFerias: v.optional(
      v.union(v.literal("ativo"), v.literal("em_ferias"))
    ),

    // Regime de trabalho (para cálculo correto de férias)
    regimeTrabalho: v.optional(
      v.union(
        v.literal("clt"), // CLT - Consolidação das Leis do Trabalho
        v.literal("estatutario_pe"), // Servidor Público Estadual de Pernambuco
        v.literal("estatutario_federal"), // Servidor Público Federal
        v.literal("estatutario_municipal") // Servidor Público Municipal
      )
    ),

    // Dados Pessoais Adicionais (opcionais)
    nomePai: v.optional(v.string()),
    nomeMae: v.optional(v.string()),
    naturalidade: v.optional(v.string()),
    naturalidadeUF: v.optional(v.string()),
    sexo: v.optional(
      v.union(v.literal("masculino"), v.literal("feminino"), v.literal("outro"))
    ),
    estadoCivil: v.optional(
      v.union(
        v.literal("solteiro"),
        v.literal("casado"),
        v.literal("divorciado"),
        v.literal("viuvo"),
        v.literal("uniao_estavel")
      )
    ),
    nacionalidade: v.optional(v.string()),

    // Documentos Pessoais
    rgOrgaoExpedidor: v.optional(v.string()),
    rgDataEmissao: v.optional(v.string()),
    carteiraProfissionalNumero: v.optional(v.string()),
    carteiraProfissionalSerie: v.optional(v.string()),
    carteiraProfissionalDataEmissao: v.optional(v.string()),
    reservistaNumero: v.optional(v.string()),
    reservistaSerie: v.optional(v.string()),
    tituloEleitorNumero: v.optional(v.string()),
    tituloEleitorZona: v.optional(v.string()),
    tituloEleitorSecao: v.optional(v.string()),
    pisNumero: v.optional(v.string()),

    // Formação e Saúde
    grauInstrucao: v.optional(
      v.union(
        v.literal("fundamental"),
        v.literal("medio"),
        v.literal("superior"),
        v.literal("pos_graduacao"),
        v.literal("mestrado"),
        v.literal("doutorado")
      )
    ),
    formacao: v.optional(v.string()),
    formacaoRegistro: v.optional(v.string()),
    grupoSanguineo: v.optional(
      v.union(v.literal("A"), v.literal("B"), v.literal("AB"), v.literal("O"))
    ),
    fatorRH: v.optional(v.union(v.literal("positivo"), v.literal("negativo"))),

    // Cargo e Vínculo
    descricaoCargo: v.optional(v.string()),
    nomeacaoPortaria: v.optional(v.string()),
    nomeacaoData: v.optional(v.string()),
    nomeacaoDOE: v.optional(v.string()),
    pertenceOrgaoPublico: v.optional(v.boolean()),
    orgaoOrigem: v.optional(v.string()),
    aposentado: v.optional(
      v.union(v.literal("nao"), v.literal("funape_ipsep"), v.literal("inss"))
    ),

    // Dados Bancários
    contaBradescoNumero: v.optional(v.string()),
    contaBradescoDV: v.optional(v.string()),
    contaBradescoAgencia: v.optional(v.string()),

    // Documentos Anexos (Storage IDs)
    certidaoAntecedentesPF: v.optional(v.id("_storage")),
    certidaoAntecedentesJFPE: v.optional(v.id("_storage")),
    certidaoAntecedentesSDS: v.optional(v.id("_storage")),
    certidaoAntecedentesTJPE: v.optional(v.id("_storage")),
    certidaoImprobidade: v.optional(v.id("_storage")),
    rgFrente: v.optional(v.id("_storage")),
    rgVerso: v.optional(v.id("_storage")),
    cpfFrente: v.optional(v.id("_storage")),
    cpfVerso: v.optional(v.id("_storage")),
    situacaoCadastralCPF: v.optional(v.id("_storage")),
    tituloEleitorFrente: v.optional(v.id("_storage")),
    tituloEleitorVerso: v.optional(v.id("_storage")),
    comprovanteVotacao: v.optional(v.id("_storage")),
    carteiraProfissionalFrente: v.optional(v.id("_storage")),
    carteiraProfissionalVerso: v.optional(v.id("_storage")),
    comprovantePIS: v.optional(v.id("_storage")),
    certidaoRegistroCivil: v.optional(v.id("_storage")),
    certidaoNascimentoDependentes: v.optional(v.id("_storage")),
    cpfDependentes: v.optional(v.id("_storage")),
    reservistaDoc: v.optional(v.id("_storage")),
    comprovanteEscolaridade: v.optional(v.id("_storage")),
    comprovanteResidencia: v.optional(v.id("_storage")),
    comprovanteContaBradesco: v.optional(v.id("_storage")),

    // Dependentes do funcionário (uploads opcionais)
    dependentes: v.optional(
      v.array(
        v.object({
          parentesco: v.union(
            v.literal("filho"),
            v.literal("filha"),
            v.literal("conjuge"),
            v.literal("outro")
          ),
          nome: v.string(),
          cpf: v.string(),
          nascimento: v.string(),
          documentoId: v.optional(v.id("_storage")),
          // Benefícios/declarações por dependente
          salarioFamilia: v.optional(v.boolean()),
          impostoRenda: v.optional(v.boolean()),
        })
      )
    ),

    // Declarações (Storage IDs)
    declaracaoAcumulacaoCargo: v.optional(v.id("_storage")),
    declaracaoDependentesIR: v.optional(v.id("_storage")),
    declaracaoIdoneidade: v.optional(v.id("_storage")),
    termoNepotismo: v.optional(v.id("_storage")),
    termoOpcaoRemuneracao: v.optional(v.id("_storage")),
  })
    .index("by_matricula", ["matricula"])
    .index("by_nome", ["nome"])
    .index("by_simboloId", ["simboloId"])
    .index("by_simboloTipo", ["simboloTipo"])
    .index("by_cpf", ["cpf"])
    .index("by_rg", ["rg"])
    .index("by_gestor", ["gestorId"]),

  atestados: defineTable({
    funcionarioId: v.id("funcionarios"),
    tipo: v.union(
      v.literal("atestado_medico"),
      v.literal("declaracao_comparecimento")
    ),
    dataInicio: v.string(),
    dataFim: v.string(),
    cid: v.optional(v.string()), // Apenas para atestado médico
    observacoes: v.optional(v.string()),
    documentoId: v.optional(v.id("_storage")),
    criadoPor: v.id("usuarios"),
    criadoEm: v.number(),
  })
    .index("by_funcionario", ["funcionarioId"])
    .index("by_tipo", ["tipo"])
    .index("by_data_inicio", ["dataInicio"])
    .index("by_funcionario_and_tipo", ["funcionarioId", "tipo"]),

  licencas: defineTable({
    funcionarioId: v.id("funcionarios"),
    tipo: v.union(v.literal("maternidade"), v.literal("paternidade")),
    dataInicio: v.string(),
    dataFim: v.string(),
    documentoId: v.optional(v.id("_storage")),
    observacoes: v.optional(v.string()),
    licencaOriginalId: v.optional(v.id("licencas")), // Para prorrogações
    ehProrrogacao: v.boolean(),
    criadoPor: v.id("usuarios"),
    criadoEm: v.number(),
  })
    .index("by_funcionario", ["funcionarioId"])
    .index("by_tipo", ["tipo"])
    .index("by_data_inicio", ["dataInicio"])
    .index("by_licenca_original", ["licencaOriginalId"])
    .index("by_funcionario_and_tipo", ["funcionarioId", "tipo"]),

  ferias: defineTable({
    funcionarioId: v.id("funcionarios"),
    anoReferencia: v.number(),
    dataInicio: v.string(),
    dataFim: v.string(),
    diasFerias: v.number(),
    status: v.union(
      v.literal("aguardando_aprovacao"),
      v.literal("aprovado"),
      v.literal("reprovado"),
      v.literal("data_ajustada_aprovada"),
      v.literal("EmFérias"),
      v.literal("Cancelado_RH")
    ),
    gestorId: v.optional(v.id("usuarios")),
    observacao: v.optional(v.string()),
    motivoReprovacao: v.optional(v.string()),
    dataAprovacao: v.optional(v.number()),
    dataReprovacao: v.optional(v.number()),
    diasAbono: v.number(),
    historicoAlteracoes: v.optional(
      v.array(
        v.object({
          data: v.number(),
          usuarioId: v.id("usuarios"),
          acao: v.string(),
        })
      )
    ),
  })
    .index("by_funcionario", ["funcionarioId"])
    .index("by_funcionario_and_ano", ["funcionarioId", "anoReferencia"])
    .index("by_funcionario_and_status", ["funcionarioId", "status"])
    .index("by_status", ["status"])
    .index("by_ano", ["anoReferencia"]),

  notificacoesFerias: defineTable({
    destinatarioId: v.id("usuarios"),
    feriasId: v.id("ferias"),
    tipo: v.union(
      v.literal("nova_solicitacao"),
      v.literal("aprovado"),
      v.literal("reprovado"),
      v.literal("data_ajustada")
    ),
    lida: v.boolean(),
    mensagem: v.string(),
  })
    .index("by_destinatario", ["destinatarioId"])
    .index("by_destinatario_and_lida", ["destinatarioId", "lida"]),

  // Solicitações de Ausências
  solicitacoesAusencias: defineTable({
    funcionarioId: v.id("funcionarios"),
    dataInicio: v.string(),
    dataFim: v.string(),
    motivo: v.string(),
    status: v.union(
      v.literal("aguardando_aprovacao"),
      v.literal("aprovado"),
      v.literal("reprovado")
    ),
    gestorId: v.optional(v.id("usuarios")),
    dataAprovacao: v.optional(v.number()),
    dataReprovacao: v.optional(v.number()),
    motivoReprovacao: v.optional(v.string()),
    observacao: v.optional(v.string()),
    criadoEm: v.number(),
  })
    .index("by_funcionario", ["funcionarioId"])
    .index("by_status", ["status"])
    .index("by_funcionario_and_status", ["funcionarioId", "status"]),

  notificacoesAusencias: defineTable({
    destinatarioId: v.id("usuarios"),
    solicitacaoAusenciaId: v.id("solicitacoesAusencias"),
    tipo: v.union(
      v.literal("nova_solicitacao"),
      v.literal("aprovado"),
      v.literal("reprovado")
    ),
    lida: v.boolean(),
    mensagem: v.string(),
  })
    .index("by_destinatario", ["destinatarioId"])
    .index("by_destinatario_and_lida", ["destinatarioId", "lida"]),


  times: defineTable({
    nome: v.string(),
    descricao: v.optional(v.string()),
    gestorId: v.id("usuarios"),
    gestorSuperiorId: v.optional(v.id("usuarios")),
    ativo: v.boolean(),
    cor: v.optional(v.string()), // Cor para identificação visual
  })
    .index("by_gestor", ["gestorId"])
    .index("by_gestor_superior", ["gestorSuperiorId"]),

  timesMembros: defineTable({
    timeId: v.id("times"),
    funcionarioId: v.id("funcionarios"),
    dataEntrada: v.number(),
    dataSaida: v.optional(v.number()),
    ativo: v.boolean(),
  })
    .index("by_time", ["timeId"])
    .index("by_funcionario", ["funcionarioId"])
    .index("by_time_and_ativo", ["timeId", "ativo"]),

  cursos: defineTable({
    funcionarioId: v.id("funcionarios"),
    descricao: v.string(),
    data: v.string(),
    certificadoId: v.optional(v.id("_storage")),
  }).index("by_funcionario", ["funcionarioId"]),

  simbolos: defineTable({
    nome: v.string(),
    tipo: simboloTipo,
    descricao: v.string(),
    vencValor: v.string(),
    repValor: v.string(),
    valor: v.string(),
  }),

  // Sistema de Autenticação e Controle de Acesso
  usuarios: defineTable({
    authId: v.string(),
    nome: v.string(),
    email: v.string(),
    funcionarioId: v.optional(v.id("funcionarios")),
    roleId: v.id("roles"),
    ativo: v.boolean(),
    primeiroAcesso: v.boolean(),
    ultimoAcesso: v.optional(v.number()),
    criadoEm: v.number(),
    atualizadoEm: v.number(),

    // Controle de Bloqueio e Segurança
    bloqueado: v.optional(v.boolean()),
    motivoBloqueio: v.optional(v.string()),
    dataBloqueio: v.optional(v.number()),
    tentativasLogin: v.optional(v.number()), // contador de tentativas falhas
    ultimaTentativaLogin: v.optional(v.number()), // timestamp da última tentativa

    // Campos de Chat e Perfil

    fotoPerfil: v.optional(v.id("_storage")),
    avatar: v.optional(v.string()), // URL do avatar gerado (ex: DiceBear)
    setor: v.optional(v.string()),
    statusMensagem: v.optional(v.string()), // max 100 chars
    statusPresenca: v.optional(
      v.union(
        v.literal("online"),
        v.literal("offline"),
        v.literal("ausente"),
        v.literal("externo"),
        v.literal("em_reuniao")
      )
    ),
    ultimaAtividade: v.optional(v.number()), // timestamp
    notificacoesAtivadas: v.optional(v.boolean()),
    somNotificacao: v.optional(v.boolean()),
    temaPreferido: v.optional(v.string()), // tema de aparência escolhido pelo usuário
  })
    .index("by_email", ["email"])
    .index("by_role", ["roleId"])
    .index("by_ativo", ["ativo"])
    .index("by_status_presenca", ["statusPresenca"])
    .index("by_bloqueado", ["bloqueado"])
    .index("by_funcionarioId", ["funcionarioId"])
    .index("authId", ["authId"]),

  roles: defineTable({
    nome: v.string(), // "admin", "ti_master", "ti_usuario", "usuario_avancado", "usuario"
    descricao: v.string(),
    nivel: v.number(), // 0 = admin, 1 = ti_master, 2 = ti_usuario, 3+ = customizado
    setor: v.optional(v.string()), // "ti", "rh", "financeiro", etc.
    customizado: v.optional(v.boolean()), // se é um perfil customizado criado por TI_MASTER
    criadoPor: v.optional(v.id("usuarios")), // usuário TI_MASTER que criou este perfil
    editavel: v.optional(v.boolean()), // se pode ser editado (false para roles fixas)
  })
    .index("by_nome", ["nome"])
    .index("by_nivel", ["nivel"])
    .index("by_setor", ["setor"])
    .index("by_customizado", ["customizado"]),

  permissoes: defineTable({
    nome: v.string(), // "funcionarios.criar", "simbolos.editar", etc.
    descricao: v.string(),
    recurso: v.string(), // "funcionarios", "simbolos", "usuarios", etc.
    acao: v.string(), // "criar", "ler", "editar", "excluir"
  })
    .index("by_recurso", ["recurso"])
    .index("by_recurso_e_acao", ["recurso", "acao"])
    .index("by_nome", ["nome"]),

  rolePermissoes: defineTable({
    roleId: v.id("roles"),
    permissaoId: v.id("permissoes"),
  })
    .index("by_role", ["roleId"])
    .index("by_permissao", ["permissaoId"]),

  sessoes: defineTable({
    usuarioId: v.id("usuarios"),
    token: v.string(),
    ipAddress: v.optional(v.string()),
    userAgent: v.optional(v.string()),
    criadoEm: v.number(),
    expiraEm: v.number(),
    ativo: v.boolean(),
  })
    .index("by_usuario", ["usuarioId"])
    .index("by_token", ["token"])
    .index("by_ativo", ["ativo"])
    .index("by_expiracao", ["expiraEm"]),

  logsAcesso: defineTable({
    usuarioId: v.id("usuarios"),
    tipo: v.union(
      v.literal("login"),
      v.literal("logout"),
      v.literal("acesso_negado"),
      v.literal("senha_alterada"),
      v.literal("sessao_expirada")
    ),
    ipAddress: v.optional(v.string()),
    userAgent: v.optional(v.string()),
    detalhes: v.optional(v.string()),
    timestamp: v.number(),
  })
    .index("by_usuario", ["usuarioId"])
    .index("by_tipo", ["tipo"])
    .index("by_timestamp", ["timestamp"]),

  // Logs de Login Detalhados
  logsLogin: defineTable({
    usuarioId: v.optional(v.id("usuarios")), // pode ser null se falha antes de identificar usuário
    matriculaOuEmail: v.string(), // tentativa de login
    sucesso: v.boolean(),
    motivoFalha: v.optional(v.string()), // "senha_incorreta", "usuario_bloqueado", "usuario_inexistente"
    ipAddress: v.optional(v.string()),
    userAgent: v.optional(v.string()),
    device: v.optional(v.string()),
    browser: v.optional(v.string()),
    sistema: v.optional(v.string()),
    timestamp: v.number(),
  })
    .index("by_usuario", ["usuarioId"])
    .index("by_sucesso", ["sucesso"])
    .index("by_timestamp", ["timestamp"])
    .index("by_ip", ["ipAddress"]),

  // Logs de Atividades
  logsAtividades: defineTable({
    usuarioId: v.id("usuarios"),
    acao: v.string(), // "criar", "editar", "excluir", "bloquear", "desbloquear", etc.
    recurso: v.string(), // "funcionarios", "simbolos", "usuarios", "perfis", etc.
    recursoId: v.optional(v.string()), // ID do recurso afetado
    detalhes: v.optional(v.string()), // JSON com detalhes da ação
    timestamp: v.number(),
  })
    .index("by_usuario", ["usuarioId"])
    .index("by_acao", ["acao"])
    .index("by_recurso", ["recurso"])
    .index("by_timestamp", ["timestamp"])
    .index("by_recurso_id", ["recurso", "recursoId"]),

  // Histórico de Bloqueios
  bloqueiosUsuarios: defineTable({
    usuarioId: v.id("usuarios"),
    motivo: v.string(),
    bloqueadoPor: v.id("usuarios"), // ID do TI_MASTER que bloqueou
    dataInicio: v.number(),
    dataFim: v.optional(v.number()), // quando foi desbloqueado
    desbloqueadoPor: v.optional(v.id("usuarios")),
    ativo: v.boolean(), // se é o bloqueio atual ativo
  })
    .index("by_usuario", ["usuarioId"])
    .index("by_bloqueado_por", ["bloqueadoPor"])
    .index("by_ativo", ["ativo"])
    .index("by_data_inicio", ["dataInicio"]),

  // Perfis Customizados

  // Templates de Mensagens
  templatesMensagens: defineTable({
    codigo: v.string(), // "USUARIO_BLOQUEADO", "SENHA_RESETADA", etc.
    nome: v.string(),
    tipo: v.union(
      v.literal("sistema"), // predefinido, não editável
      v.literal("customizado") // criado por TI_MASTER
    ),
    titulo: v.string(),
    corpo: v.string(), // pode ter variáveis {{variavel}}
    variaveis: v.optional(v.array(v.string())), // ["motivo", "senha", etc.]
    criadoPor: v.optional(v.id("usuarios")),
    criadoEm: v.number(),
  })
    .index("by_codigo", ["codigo"])
    .index("by_tipo", ["tipo"])
    .index("by_criado_por", ["criadoPor"]),

  // Configuração de Email/SMTP
  configuracaoEmail: defineTable({
    servidor: v.string(), // smtp.gmail.com
    porta: v.number(), // 587, 465, etc.
    usuario: v.string(),
    senhaHash: v.string(), // senha criptografada reversível (AES-GCM) - necessário para descriptografar e usar no SMTP
    emailRemetente: v.string(),
    nomeRemetente: v.string(),
    usarSSL: v.boolean(),
    usarTLS: v.boolean(),
    ativo: v.boolean(),
    testadoEm: v.optional(v.number()),
    configuradoPor: v.id("usuarios"),
    atualizadoEm: v.number(),
  }).index("by_ativo", ["ativo"]),

  // Configuração de Jitsi Meet
  configuracaoJitsi: defineTable({
    domain: v.string(), // Domínio do servidor Jitsi (ex: "localhost:8443" ou "meet.example.com")
    appId: v.string(), // ID da aplicação Jitsi
    roomPrefix: v.string(), // Prefixo para nomes de salas
    useHttps: v.boolean(), // Usar HTTPS
    acceptSelfSignedCert: v.optional(v.boolean()), // Aceitar certificados autoassinados (útil para desenvolvimento)
    // Configurações SSH/Docker para configuração automática do servidor
    sshHost: v.optional(v.string()), // Host SSH para acesso ao servidor Docker (ex: "192.168.1.100" ou "servidor.local")
    sshPort: v.optional(v.number()), // Porta SSH (padrão: 22)
    sshUsername: v.optional(v.string()), // Usuário SSH
    sshPasswordHash: v.optional(v.string()), // Hash da senha SSH (criptografada)
    sshKeyPath: v.optional(v.string()), // Caminho para chave SSH (alternativa à senha)
    dockerComposePath: v.optional(v.string()), // Caminho do docker-compose.yml (ex: "/home/user/jitsi-docker")
    jitsiConfigPath: v.optional(v.string()), // Caminho base das configurações Jitsi (ex: "~/.jitsi-meet-cfg")
    ativo: v.boolean(), // Configuração ativa
    testadoEm: v.optional(v.number()), // Timestamp do último teste de conexão
    configuradoEm: v.optional(v.number()), // Timestamp da última configuração do servidor Docker
    configuradoNoServidor: v.optional(v.boolean()), // Indica se a configuração foi aplicada no servidor
    configuradoNoServidorEm: v.optional(v.number()), // Timestamp de quando foi configurado no servidor
    configuradoPor: v.id("usuarios"), // Usuário que configurou
    atualizadoEm: v.number(), // Timestamp de atualização
  }).index("by_ativo", ["ativo"]),

  // Fila de Emails
  notificacoesEmail: defineTable({
    destinatario: v.string(), // email
    destinatarioId: v.optional(v.id("usuarios")),
    assunto: v.string(),
    corpo: v.string(), // HTML ou texto
    templateId: v.optional(v.id("templatesMensagens")),
    status: v.union(
      v.literal("pendente"),
      v.literal("enviando"),
      v.literal("enviado"),
      v.literal("falha")
    ),
    tentativas: v.number(),
    ultimaTentativa: v.optional(v.number()),
    erroDetalhes: v.optional(v.string()),
    enviadoPor: v.id("usuarios"),
    criadoEm: v.number(),
    enviadoEm: v.optional(v.number()),
    agendadaPara: v.optional(v.number()), // timestamp para agendamento
  })
    .index("by_status", ["status"])
    .index("by_destinatario", ["destinatarioId"])
    .index("by_enviado_por", ["enviadoPor"])
    .index("by_criado_em", ["criadoEm"])
    .index("by_agendamento", ["agendadaPara"]),

  configuracaoAcesso: defineTable({
    chave: v.string(), // "sessao_duracao", "max_tentativas_login", etc.
    valor: v.string(),
    descricao: v.string(),
  }).index("by_chave", ["chave"]),

  // Rate Limiting de Emails
  rateLimitEmails: defineTable({
    remetenteId: v.id("usuarios"),
    timestamp: v.number(),
    contador: v.number(), // quantidade de emails enviados neste período
    periodo: v.union(
      v.literal("minuto"), // último minuto
      v.literal("hora") // última hora
    ),
  })
    .index("by_remetente_periodo", ["remetenteId", "periodo", "timestamp"])
    .index("by_timestamp", ["timestamp"]),

  // Sistema de Chat
  conversas: defineTable({
    tipo: v.union(
      v.literal("individual"),
      v.literal("grupo"),
      v.literal("sala_reuniao")
    ),
    nome: v.optional(v.string()), // nome do grupo/sala

    participantes: v.array(v.id("usuarios")), // IDs dos participantes
    administradores: v.optional(v.array(v.id("usuarios"))), // IDs dos administradores (apenas para sala_reuniao)
    ultimaMensagem: v.optional(v.string()),
    ultimaMensagemTimestamp: v.optional(v.number()),
    ultimaMensagemRemetenteId: v.optional(v.id("usuarios")), // ID do remetente da última mensagem
    criadoPor: v.id("usuarios"),
    criadoEm: v.number(),
  })
    .index("by_criado_por", ["criadoPor"])
    .index("by_tipo", ["tipo"])
    .index("by_ultima_mensagem", ["ultimaMensagemTimestamp"]),

  mensagens: defineTable({
    conversaId: v.id("conversas"),
    remetenteId: v.id("usuarios"),
    tipo: v.union(
      v.literal("texto"),
      v.literal("arquivo"),
      v.literal("imagem")
    ),
    conteudo: v.string(), // texto ou nome do arquivo
    conteudoBusca: v.optional(v.string()), // versão normalizada para busca
    arquivoId: v.optional(v.id("_storage")),
    arquivoNome: v.optional(v.string()),
    arquivoTamanho: v.optional(v.number()),
    arquivoTipo: v.optional(v.string()),
    linkPreview: v.optional(
      v.object({
        url: v.string(),
        titulo: v.optional(v.string()),
        descricao: v.optional(v.string()),
        imagem: v.optional(v.string()),
        site: v.optional(v.string()),
      })
    ),
    reagiuPor: v.optional(
      v.array(
        v.object({
          usuarioId: v.id("usuarios"),
          emoji: v.string(),
        })
      )
    ),
    mencoes: v.optional(v.array(v.id("usuarios"))),
    respostaPara: v.optional(v.id("mensagens")), // ID da mensagem que está respondendo
    agendadaPara: v.optional(v.number()), // timestamp
    enviadaEm: v.number(),
    editadaEm: v.optional(v.number()),
    deletada: v.optional(v.boolean()),
    lidaPor: v.optional(v.array(v.id("usuarios"))), // IDs dos usuários que leram a mensagem
  })
    .index("by_conversa", ["conversaId", "enviadaEm"])
    .index("by_remetente", ["remetenteId"])
    .index("by_agendamento", ["agendadaPara"])
    .index("by_resposta", ["respostaPara"]),

  leituras: defineTable({
    conversaId: v.id("conversas"),
    usuarioId: v.id("usuarios"),
    ultimaMensagemLida: v.id("mensagens"),
    lidaEm: v.number(),
  })
    .index("by_conversa_usuario", ["conversaId", "usuarioId"])
    .index("by_usuario", ["usuarioId"]),

  // Sistema de Chamadas de Áudio/Vídeo
  chamadas: defineTable({
    conversaId: v.id("conversas"),
    tipo: v.union(v.literal("audio"), v.literal("video")),
    roomName: v.string(), // Nome único da sala Jitsi
    criadoPor: v.id("usuarios"), // Anfitrião/criador
    participantes: v.array(v.id("usuarios")),
    status: v.union(
      v.literal("aguardando"),
      v.literal("em_andamento"),
      v.literal("finalizada"),
      v.literal("cancelada")
    ),
    iniciadaEm: v.optional(v.number()),
    finalizadaEm: v.optional(v.number()),
    duracaoSegundos: v.optional(v.number()),
    gravando: v.boolean(),
    gravacaoIniciadaPor: v.optional(v.id("usuarios")),
    gravacaoIniciadaEm: v.optional(v.number()),
    gravacaoFinalizadaEm: v.optional(v.number()),
    configuracoes: v.optional(v.object({
      audioHabilitado: v.boolean(),
      videoHabilitado: v.boolean(),
      participantesConfig: v.optional(v.array(v.object({
        usuarioId: v.id("usuarios"),
        audioHabilitado: v.boolean(),
        videoHabilitado: v.boolean(),
        forcadoPeloAnfitriao: v.optional(v.boolean()), // Se foi forçado pelo anfitrião
      })))
    })),
    criadoEm: v.number(),
  })
    .index("by_conversa", ["conversaId", "status"])
    .index("by_criado_por", ["criadoPor"])
    .index("by_status", ["status"])
    .index("by_room_name", ["roomName"]),

  notificacoes: defineTable({
    usuarioId: v.id("usuarios"),
    tipo: v.union(
      v.literal("nova_mensagem"),
      v.literal("mencao"),
      v.literal("grupo_criado"),
      v.literal("adicionado_grupo"),
      v.literal("alerta_seguranca"),
      v.literal("etapa_fluxo_concluida")
    ),
    conversaId: v.optional(v.id("conversas")),
    mensagemId: v.optional(v.id("mensagens")),
    remetenteId: v.optional(v.id("usuarios")),
    titulo: v.string(),
    descricao: v.string(),
    lida: v.boolean(),
    criadaEm: v.number(),
  })
    .index("by_usuario", ["usuarioId", "lida", "criadaEm"])
    .index("by_usuario_lida", ["usuarioId", "lida"]),

  digitando: defineTable({
    conversaId: v.id("conversas"),
    usuarioId: v.id("usuarios"),
    iniciouEm: v.number(),
  })
    .index("by_conversa", ["conversaId", "iniciouEm"])
    .index("by_usuario", ["usuarioId"]),

  // Push Notifications
  pushSubscriptions: defineTable({
    usuarioId: v.id("usuarios"),
    endpoint: v.string(), // URL do serviço de push
    keys: v.object({
      p256dh: v.string(), // Chave pública
      auth: v.string(), // Chave de autenticação
    }),
    userAgent: v.optional(v.string()),
    criadoEm: v.number(),
    ultimaAtividade: v.number(),
    ativo: v.boolean(),
  })
    .index("by_usuario", ["usuarioId", "ativo"])
    .index("by_endpoint", ["endpoint"]),

  // Preferências de Notificação por Conversa
  preferenciasNotificacaoConversa: defineTable({
    usuarioId: v.id("usuarios"),
    conversaId: v.id("conversas"),
    pushAtivado: v.boolean(), // Receber push notifications
    emailAtivado: v.boolean(), // Receber emails quando offline
    somAtivado: v.boolean(), // Tocar som
    silenciado: v.boolean(), // Silenciar completamente
    apenasMencoes: v.boolean(), // Notificar apenas quando mencionado
    criadoEm: v.number(),
    atualizadoEm: v.number(),
  })
    .index("by_usuario_conversa", ["usuarioId", "conversaId"])
    .index("by_conversa", ["conversaId"]),

  // Tabelas de Monitoramento do Sistema
  systemMetrics: defineTable({
    timestamp: v.number(),
    // Métricas de Sistema
    cpuUsage: v.optional(v.number()),
    memoryUsage: v.optional(v.number()),
    networkLatency: v.optional(v.number()),
    storageUsed: v.optional(v.number()),
    // Métricas de Aplicação
    usuariosOnline: v.optional(v.number()),
    mensagensPorMinuto: v.optional(v.number()),
    tempoRespostaMedio: v.optional(v.number()),
    errosCount: v.optional(v.number()),
  }).index("by_timestamp", ["timestamp"]),

  alertConfigurations: defineTable({
    metricName: v.string(),
    threshold: v.number(),
    operator: v.union(
      v.literal(">"),
      v.literal("<"),
      v.literal(">="),
      v.literal("<="),
      v.literal("==")
    ),
    enabled: v.boolean(),
    notifyByEmail: v.boolean(),
    notifyByChat: v.boolean(),
    createdBy: v.id("usuarios"),
    lastModified: v.number(),
  }).index("by_enabled", ["enabled"]),

  alertHistory: defineTable({
    configId: v.id("alertConfigurations"),
    metricName: v.string(),
    metricValue: v.number(),
    threshold: v.number(),
    timestamp: v.number(),
    status: v.union(v.literal("triggered"), v.literal("resolved")),
    notificationsSent: v.object({
      email: v.boolean(),
      chat: v.boolean(),
    }),
  })
    .index("by_timestamp", ["timestamp"])
    .index("by_status", ["status"])
    .index("by_config", ["configId", "timestamp"]),

  tickets: defineTable({
    numero: v.string(),
    titulo: v.string(),
    descricao: v.string(),
    tipo: v.union(
      v.literal("reclamacao"),
      v.literal("elogio"),
      v.literal("sugestao"),
      v.literal("chamado")
    ),
    categoria: v.optional(v.string()),
    status: v.union(
      v.literal("aberto"),
      v.literal("em_andamento"),
      v.literal("aguardando_usuario"),
      v.literal("resolvido"),
      v.literal("encerrado"),
      v.literal("cancelado")
    ),
    prioridade: v.union(
      v.literal("baixa"),
      v.literal("media"),
      v.literal("alta"),
      v.literal("critica")
    ),
    solicitanteId: v.id("usuarios"),
    solicitanteNome: v.string(),
    solicitanteEmail: v.string(),
    responsavelId: v.optional(v.id("usuarios")),
    setorResponsavel: v.optional(v.string()),
    slaConfigId: v.optional(v.id("slaConfigs")),
    conversaId: v.optional(v.id("conversas")),
    prazoResposta: v.optional(v.number()),
    prazoConclusao: v.optional(v.number()),
    prazoEncerramento: v.optional(v.number()),
    timeline: v.optional(
      v.array(
        v.object({
          etapa: v.string(),
          status: v.union(
            v.literal("pendente"),
            v.literal("em_andamento"),
            v.literal("concluido"),
            v.literal("vencido")
          ),
          prazo: v.optional(v.number()),
          concluidoEm: v.optional(v.number()),
          observacao: v.optional(v.string()),
        })
      )
    ),
    alertasEmitidos: v.optional(
      v.array(
        v.object({
          tipo: v.union(
            v.literal("resposta"),
            v.literal("conclusao"),
            v.literal("encerramento")
          ),
          emitidoEm: v.number(),
        })
      )
    ),
    anexos: v.optional(
      v.array(
        v.object({
          arquivoId: v.id("_storage"),
          nome: v.optional(v.string()),
          tipo: v.optional(v.string()),
          tamanho: v.optional(v.number()),
        })
      )
    ),
    tags: v.optional(v.array(v.string())),
    canalOrigem: v.optional(v.string()),
    ultimaInteracaoEm: v.number(),
    criadoEm: v.number(),
    atualizadoEm: v.number(),
  })
    .index("by_numero", ["numero"])
    .index("by_status", ["status"])
    .index("by_solicitante", ["solicitanteId", "status"])
    .index("by_responsavel", ["responsavelId", "status"])
    .index("by_setor", ["setorResponsavel", "status"]),

  ticketInteractions: defineTable({
    ticketId: v.id("tickets"),
    autorId: v.optional(v.id("usuarios")),
    origem: v.union(
      v.literal("usuario"),
      v.literal("ti"),
      v.literal("sistema")
    ),
    tipo: v.union(
      v.literal("mensagem"),
      v.literal("status"),
      v.literal("anexo"),
      v.literal("alerta")
    ),
    conteudo: v.string(),
    anexos: v.optional(
      v.array(
        v.object({
          arquivoId: v.id("_storage"),
          nome: v.optional(v.string()),
          tipo: v.optional(v.string()),
          tamanho: v.optional(v.number()),
        })
      )
    ),
    statusAnterior: v.optional(
      v.union(
        v.literal("aberto"),
        v.literal("em_andamento"),
        v.literal("aguardando_usuario"),
        v.literal("resolvido"),
        v.literal("encerrado"),
        v.literal("cancelado")
      )
    ),
    statusNovo: v.optional(
      v.union(
        v.literal("aberto"),
        v.literal("em_andamento"),
        v.literal("aguardando_usuario"),
        v.literal("resolvido"),
        v.literal("encerrado"),
        v.literal("cancelado")
      )
    ),
    visibilidade: v.union(
      v.literal("publico"),
      v.literal("interno")
    ),
    criadoEm: v.number(),
  })
    .index("by_ticket", ["ticketId"])
    .index("by_ticket_type", ["ticketId", "tipo"])
    .index("by_autor", ["autorId"]),

  slaConfigs: defineTable({
    nome: v.string(),
    descricao: v.optional(v.string()),
    prioridade: v.optional(
      v.union(
        v.literal("baixa"),
        v.literal("media"),
        v.literal("alta"),
        v.literal("critica")
      )
    ),
    tempoRespostaHoras: v.number(),
    tempoConclusaoHoras: v.number(),
    tempoEncerramentoHoras: v.optional(v.number()),
    alertaAntecedenciaHoras: v.number(),
    ativo: v.boolean(),
    criadoPor: v.id("usuarios"),
    atualizadoPor: v.optional(v.id("usuarios")),
    criadoEm: v.number(),
    atualizadoEm: v.number(),
  })
    .index("by_ativo", ["ativo"])
    .index("by_prioridade", ["prioridade", "ativo"])
    .index("by_nome", ["nome"]),

  ticketAssignments: defineTable({
    ticketId: v.id("tickets"),
    responsavelId: v.id("usuarios"),
    atribuidoPor: v.id("usuarios"),
    motivo: v.optional(v.string()),
    ativo: v.boolean(),
    criadoEm: v.number(),
    encerradoEm: v.optional(v.number()),
  })
    .index("by_ticket", ["ticketId", "ativo"])
    .index("by_responsavel", ["responsavelId", "ativo"]),

  // Sistema de Segurança Cibernética
  networkSensors: defineTable({
    nome: v.string(),
    tipo: sensorSegurancaTipo,
    status: sensorSegurancaStatus,
    escopo: v.optional(v.string()),
    ipMonitorado: v.optional(v.string()),
    hostname: v.optional(v.string()),
    regioes: v.optional(v.array(v.string())),
    portasMonitoradas: v.optional(v.array(v.number())),
    protocolos: v.optional(v.array(v.string())),
    capacidades: v.optional(v.array(v.string())),
    ultimaSincronizacao: v.number(),
    ultimoHeartbeat: v.optional(v.number()),
    latenciaMs: v.optional(v.number()),
    errosConsecutivos: v.optional(v.number()),
    agenteVersao: v.optional(v.string()),
    notas: v.optional(v.string()),
  })
    .index("by_tipo", ["tipo"])
    .index("by_status", ["status"])
    .index("by_hostname", ["hostname"]),

  ipReputation: defineTable({
    indicador: v.string(),
    categoria: v.union(
      v.literal("ip"),
      v.literal("dominio"),
      v.literal("hash"),
      v.literal("email")
    ),
    reputacao: v.number(), // -100 (malicioso) até 100 (confiável)
    severidadeMax: severidadeSeguranca,
    whitelist: v.boolean(),
    blacklist: v.boolean(),
    ocorrencias: v.number(),
    primeiroRegistro: v.number(),
    ultimoRegistro: v.number(),
    bloqueadoAte: v.optional(v.number()),
    origem: v.optional(v.string()),
    comentarios: v.optional(v.string()),
    classificacoes: v.optional(v.array(v.string())),
    ultimaAcaoId: v.optional(v.id("incidentActions")),
  })
    .index("by_indicador", ["indicador"])
    .index("by_reputacao", ["reputacao"])
    .index("by_blacklist", ["blacklist"])
    .index("by_whitelist", ["whitelist"]),

  portRules: defineTable({
    porta: v.number(),
    protocolo: v.union(
      v.literal("tcp"),
      v.literal("udp"),
      v.literal("icmp"),
      v.literal("quic"),
      v.literal("any")
    ),
    acao: v.union(
      v.literal("permitir"),
      v.literal("bloquear"),
      v.literal("monitorar"),
      v.literal("rate_limit")
    ),
    temporario: v.boolean(),
    severidadeMin: severidadeSeguranca,
    duracaoSegundos: v.optional(v.number()),
    expiraEm: v.optional(v.number()),
    criadoPor: v.id("usuarios"),
    atualizadoPor: v.optional(v.id("usuarios")),
    criadoEm: v.number(),
    atualizadoEm: v.number(),
    notas: v.optional(v.string()),
    tags: v.optional(v.array(v.string())),
    listaReferencia: v.optional(v.id("ipReputation")),
  })
    .index("by_porta_protocolo", ["porta", "protocolo"])
    .index("by_acao", ["acao"])
    .index("by_expiracao", ["expiraEm"]),

  threatIntelFeeds: defineTable({
    nomeFonte: v.string(),
    tipo: threatIntelTipo,
    formato: threatIntelFormato,
    url: v.optional(v.string()),
    ativo: v.boolean(),
    prioridade: v.union(
      v.literal("baixa"),
      v.literal("media"),
      v.literal("alta"),
      v.literal("critica")
    ),
    ultimaSincronizacao: v.optional(v.number()),
    entradasProcessadas: v.optional(v.number()),
    errosConsecutivos: v.optional(v.number()),
    autenticacaoNecessaria: v.optional(v.boolean()),
    configuracao: v.optional(
      v.object({
        tokenId: v.optional(v.id("_storage")),
        escopo: v.optional(v.string()),
      })
    ),
    criadoPor: v.id("usuarios"),
    atualizadoPor: v.optional(v.id("usuarios")),
    criadoEm: v.number(),
    atualizadoEm: v.number(),
  })
    .index("by_tipo", ["tipo"])
    .index("by_ativo", ["ativo"])
    .index("by_prioridade", ["prioridade"]),

  securityEvents: defineTable({
    referencia: v.string(),
    timestamp: v.number(),
    tipoAtaque: ataqueCiberneticoTipo,
    severidade: severidadeSeguranca,
    status: statusEventoSeguranca,
    descricao: v.string(),
    origemIp: v.optional(v.string()),
    origemRegiao: v.optional(v.string()),
    origemAsn: v.optional(v.string()),
    destinoIp: v.optional(v.string()),
    destinoPorta: v.optional(v.number()),
    protocolo: v.optional(v.string()),
    transporte: v.optional(v.string()),
    sensorId: v.optional(v.id("networkSensors")),
    detectadoPor: v.optional(v.string()),
    mitreTechnique: v.optional(v.string()),
    geolocalizacao: v.optional(
      v.object({
        pais: v.optional(v.string()),
        regiao: v.optional(v.string()),
        cidade: v.optional(v.string()),
        latitude: v.optional(v.number()),
        longitude: v.optional(v.number()),
      })
    ),
    fingerprint: v.optional(
      v.object({
        userAgent: v.optional(v.string()),
        deviceId: v.optional(v.string()),
        ja3: v.optional(v.string()),
        tlsVersion: v.optional(v.string()),
      })
    ),
    indicadores: v.optional(
      v.array(
        v.object({
          tipo: v.string(),
          valor: v.string(),
          confianca: v.optional(v.number()),
        })
      )
    ),
    metricas: v.optional(
      v.object({
        pps: v.optional(v.number()),
        bps: v.optional(v.number()),
        rpm: v.optional(v.number()),
        errosPorSegundo: v.optional(v.number()),
        hostsAfetados: v.optional(v.number()),
      })
    ),
    correlacoes: v.optional(v.array(v.id("securityEvents"))),
    referenciasExternas: v.optional(v.array(v.string())),
    tags: v.optional(v.array(v.string())),
    criadoPor: v.optional(v.id("usuarios")),
    atualizadoEm: v.number(),
  })
    .index("by_referencia", ["referencia"])
    .index("by_timestamp", ["timestamp"])
    .index("by_tipo", ["tipoAtaque", "timestamp"])
    .index("by_severidade", ["severidade", "timestamp"])
    .index("by_status", ["status", "timestamp"]),

  incidentActions: defineTable({
    eventoId: v.id("securityEvents"),
    tipo: acaoIncidenteTipo,
    origem: v.union(v.literal("automatico"), v.literal("manual")),
    status: acaoIncidenteStatus,
    executadoPor: v.optional(v.id("usuarios")),
    detalhes: v.optional(v.string()),
    resultado: v.optional(v.string()),
    relacionadoA: v.optional(v.id("ipReputation")),
    criadoEm: v.number(),
    atualizadoEm: v.number(),
  })
    .index("by_evento", ["eventoId", "status"])
    .index("by_tipo", ["tipo", "status"]),

  reportRequests: defineTable({
    solicitanteId: v.id("usuarios"),
    filtros: v.object({
      dataInicio: v.number(),
      dataFim: v.number(),
      severidades: v.optional(v.array(severidadeSeguranca)),
      tiposAtaque: v.optional(v.array(ataqueCiberneticoTipo)),
      incluirIndicadores: v.optional(v.boolean()),
      incluirMetricas: v.optional(v.boolean()),
      incluirAcoes: v.optional(v.boolean()),
    }),
    status: reportStatus,
    resultadoId: v.optional(v.id("_storage")),
    observacoes: v.optional(v.string()),
    criadoEm: v.number(),
    atualizadoEm: v.number(),
    concluidoEm: v.optional(v.number()),
    erro: v.optional(v.string()),
  })
    .index("by_status", ["status"])
    .index("by_solicitante", ["solicitanteId", "status"])
    .index("by_criado_em", ["criadoEm"]),

  rateLimitConfig: defineTable({
    nome: v.string(),
    tipo: v.union(
      v.literal("ip"),
      v.literal("usuario"),
      v.literal("endpoint"),
      v.literal("global")
    ),
    identificador: v.optional(v.string()),
    limite: v.number(),
    janelaSegundos: v.number(),
    estrategia: v.union(
      v.literal("fixed_window"),
      v.literal("sliding_window"),
      v.literal("token_bucket")
    ),
    acaoExcedido: v.union(
      v.literal("bloquear"),
      v.literal("throttle"),
      v.literal("alertar")
    ),
    bloqueioTemporarioSegundos: v.optional(v.number()),
    ativo: v.boolean(),
    prioridade: v.number(),
    criadoPor: v.id("usuarios"),
    atualizadoPor: v.optional(v.id("usuarios")),
    criadoEm: v.number(),
    atualizadoEm: v.number(),
    notas: v.optional(v.string()),
    tags: v.optional(v.array(v.string()))
  })
    .index("by_tipo_identificador", ["tipo", "identificador"])
    .index("by_ativo", ["ativo"])
    .index("by_prioridade", ["prioridade"])
  ,
  alertConfigs: defineTable({
    nome: v.string(),
    canais: v.object({
      email: v.boolean(),
      chat: v.boolean(),
    }),
    emails: v.array(v.string()),
    chatUsers: v.array(v.string()),
    severidadeMin: severidadeSeguranca,
    tiposAtaque: v.optional(v.array(ataqueCiberneticoTipo)),
    reenvioMin: v.number(),
    criadoPor: v.id("usuarios"),
    criadoEm: v.number(),
    atualizadoEm: v.number(),
  })
    .index("by_criadoEm", ["criadoEm"]),

  // Sistema de Controle de Ponto
  registrosPonto: defineTable({
    funcionarioId: v.id("funcionarios"),
    tipo: v.union(
      v.literal("entrada"),
      v.literal("saida_almoco"),
      v.literal("retorno_almoco"),
      v.literal("saida")
    ),
    data: v.string(), // YYYY-MM-DD
    hora: v.number(),
    minuto: v.number(),
    segundo: v.number(),
    timestamp: v.number(), // Timestamp completo para ordenação
    imagemId: v.optional(v.id("_storage")),
    sincronizadoComServidor: v.boolean(),
    toleranciaMinutos: v.number(),
    dentroDoPrazo: v.boolean(),
    
    // Informações de Rede
    ipAddress: v.optional(v.string()),
    ipPublico: v.optional(v.string()),
    ipLocal: v.optional(v.string()),
    
    // Informações do Navegador
    userAgent: v.optional(v.string()),
    browser: v.optional(v.string()),
    browserVersion: v.optional(v.string()),
    engine: v.optional(v.string()),
    
    // Informações do Sistema
    sistemaOperacional: v.optional(v.string()),
    osVersion: v.optional(v.string()),
    arquitetura: v.optional(v.string()),
    plataforma: v.optional(v.string()),
    
    // Informações de Localização
    latitude: v.optional(v.number()),
    longitude: v.optional(v.number()),
    precisao: v.optional(v.number()),
    altitude: v.optional(v.union(v.number(), v.null())),
    altitudeAccuracy: v.optional(v.union(v.number(), v.null())),
    heading: v.optional(v.union(v.number(), v.null())),
    speed: v.optional(v.union(v.number(), v.null())),
    confiabilidadeGPS: v.optional(v.number()), // 0-1 (frontend)
    scoreConfiancaBackend: v.optional(v.number()), // 0-1 (backend)
    suspeitaSpoofing: v.optional(v.boolean()),
    motivoSuspeita: v.optional(v.string()),
    avisosValidacao: v.optional(v.array(v.string())), // Array de avisos detalhados da validação
    distanciaIPvsGPS: v.optional(v.number()), // Distância em metros entre IP geolocation e GPS
    velocidadeUltimoRegistro: v.optional(v.number()), // Velocidade em km/h do último registro
    distanciaUltimoRegistro: v.optional(v.number()), // Distância em metros do último registro
    tempoDecorridoHoras: v.optional(v.number()), // Tempo em horas desde o último registro
    // Informações de Geofencing
    enderecoMarcacaoEsperado: v.optional(v.id("enderecosMarcacao")), // Endereço mais próximo esperado
    distanciaEnderecoEsperado: v.optional(v.number()), // Distância em metros do endereço esperado
    dentroRaioPermitido: v.optional(v.boolean()), // Se está dentro do raio permitido
    enderecoMarcacaoUsado: v.optional(v.id("enderecosMarcacao")), // Qual endereço foi usado na validação
    raioToleranciaUsado: v.optional(v.number()), // Raio usado na validação em metros
    endereco: v.optional(v.string()),
    cidade: v.optional(v.string()),
    estado: v.optional(v.string()),
    pais: v.optional(v.string()),
    timezone: v.optional(v.string()),
    
    // Informações do Dispositivo
    deviceType: v.optional(v.string()),
    deviceModel: v.optional(v.string()),
    screenResolution: v.optional(v.string()),
    coresTela: v.optional(v.number()),
    idioma: v.optional(v.string()),
    
    // Informações Adicionais
    isMobile: v.optional(v.boolean()),
    isTablet: v.optional(v.boolean()),
    isDesktop: v.optional(v.boolean()),
    connectionType: v.optional(v.string()),
    memoryInfo: v.optional(v.string()),
    
    // Informações de Sensores (Acelerômetro e Giroscópio)
    acelerometroX: v.optional(v.number()),
    acelerometroY: v.optional(v.number()),
    acelerometroZ: v.optional(v.number()),
    movimentoDetectado: v.optional(v.boolean()),
    magnitudeMovimento: v.optional(v.number()),
    variacaoAcelerometro: v.optional(v.number()),
    giroscopioAlpha: v.optional(v.number()),
    giroscopioBeta: v.optional(v.number()),
    giroscopioGamma: v.optional(v.number()),
    sensorDisponivel: v.optional(v.boolean()),
    permissaoSensorNegada: v.optional(v.boolean()),
    
    // Justificativa opcional para o registro
    justificativa: v.optional(v.string()),
    
    // Campos para homologação
    editadoPorGestor: v.optional(v.boolean()),
    homologacaoId: v.optional(v.id("homologacoesPonto")),
    
    criadoEm: v.number(),
  })
    .index("by_funcionario_data", ["funcionarioId", "data"])
    .index("by_data", ["data"])
    .index("by_dentro_prazo", ["dentroDoPrazo", "data"])
    .index("by_funcionario_timestamp", ["funcionarioId", "timestamp"]),

  // Endereços de Marcação - Locais permitidos para registro de ponto
  enderecosMarcacao: defineTable({
    nome: v.string(), // Ex: "Sede Principal", "Home Office João Silva", "Cliente ABC"
    descricao: v.optional(v.string()), // Descrição opcional
    // Coordenadas (obrigatórias)
    latitude: v.number(),
    longitude: v.number(),
    // Endereço físico (para exibição)
    endereco: v.string(), // Ex: "Rua Exemplo, 123"
    bairro: v.optional(v.string()), // Bairro do endereço
    cep: v.optional(v.string()),
    cidade: v.string(),
    estado: v.string(),
    pais: v.optional(v.string()), // Padrão: "Brasil"
    // Configurações
    raioMetros: v.number(), // Raio de tolerância em metros (ex: 100m, 500m, 1000m)
    ativo: v.boolean(),
    // Tipos de uso
    tipo: v.union(
      v.literal("sede"), // Sede principal (para todos)
      v.literal("home_office"), // Home office específico
      v.literal("deslocamento"), // Deslocamento temporário
      v.literal("cliente") // Local de cliente
    ),
    // Metadados
    criadoPor: v.id("usuarios"),
    criadoEm: v.number(),
    atualizadoPor: v.optional(v.id("usuarios")),
    atualizadoEm: v.optional(v.number()),
  })
    .index("by_ativo", ["ativo"])
    .index("by_tipo", ["tipo"])
    .index("by_cidade", ["cidade"]),

  // Associação Funcionário ↔ Endereço de Marcação
  funcionarioEnderecosMarcacao: defineTable({
    funcionarioId: v.id("funcionarios"),
    enderecoMarcacaoId: v.id("enderecosMarcacao"),
    // Configurações específicas do funcionário
    raioMetrosPersonalizado: v.optional(v.number()), // Pode ter raio diferente do padrão
    // Período de validade (para deslocamentos temporários)
    dataInicio: v.optional(v.string()), // YYYY-MM-DD
    dataFim: v.optional(v.string()), // YYYY-MM-DD
    // Status
    ativo: v.boolean(),
    // Metadados
    criadoPor: v.id("usuarios"),
    criadoEm: v.number(),
  })
    .index("by_funcionario", ["funcionarioId"])
    .index("by_endereco", ["enderecoMarcacaoId"])
    .index("by_funcionario_ativo", ["funcionarioId", "ativo"])
    .index("by_endereco_ativo", ["enderecoMarcacaoId", "ativo"]),

  configuracaoPonto: defineTable({
    horarioEntrada: v.string(), // HH:mm
    horarioSaidaAlmoco: v.string(), // HH:mm
    horarioRetornoAlmoco: v.string(), // HH:mm
    horarioSaida: v.string(), // HH:mm
    toleranciaMinutos: v.number(),
    // Nomes personalizados dos tipos de registro
    nomeEntrada: v.optional(v.string()), // Padrão: "Entrada 1"
    nomeSaidaAlmoco: v.optional(v.string()), // Padrão: "Saída 1"
    nomeRetornoAlmoco: v.optional(v.string()), // Padrão: "Entrada 2"
    nomeSaida: v.optional(v.string()), // Padrão: "Saída 2"
    // Ajuste de fuso horário (GMT offset em horas)
    gmtOffset: v.optional(v.number()), // Padrão: 0 (UTC)
    // Configurações de geofencing
    validarLocalizacao: v.optional(v.boolean()), // Habilitar/desabilitar validação de localização
    toleranciaDistanciaMetros: v.optional(v.number()), // Raio padrão global em metros
    ativo: v.boolean(),
    atualizadoPor: v.id("usuarios"),
    atualizadoEm: v.number(),
  })
    .index("by_ativo", ["ativo"]),

  configuracaoRelogio: defineTable({
    servidorNTP: v.optional(v.string()),
    portaNTP: v.optional(v.number()),
    usarServidorExterno: v.boolean(),
    fallbackParaPC: v.boolean(),
    ultimaSincronizacao: v.optional(v.number()),
    offsetSegundos: v.optional(v.number()),
    // Ajuste de fuso horário (GMT offset em horas)
    gmtOffset: v.optional(v.number()), // Padrão: 0 (UTC)
    atualizadoPor: v.id("usuarios"),
    atualizadoEm: v.number(),
  })
    .index("by_ativo", ["usarServidorExterno"]),

  // Banco de Horas - Saldo diário de horas trabalhadas
  bancoHoras: defineTable({
    funcionarioId: v.id("funcionarios"),
    data: v.string(), // YYYY-MM-DD
    cargaHorariaDiaria: v.number(), // Horas esperadas do dia (em minutos)
    horasTrabalhadas: v.number(), // Horas realmente trabalhadas (em minutos)
    saldoMinutos: v.number(), // Saldo do dia (positivo = horas extras, negativo = déficit)
    registrosPontoIds: v.array(v.id("registrosPonto")), // IDs dos registros do dia
    calculadoEm: v.number(),
  })
    .index("by_funcionario_data", ["funcionarioId", "data"])
    .index("by_funcionario", ["funcionarioId"])
    .index("by_data", ["data"]),

  // Homologações de Ponto - Edições e ajustes realizados pelo gestor
  homologacoesPonto: defineTable({
    registroId: v.optional(v.id("registrosPonto")), // ID do registro editado (se for edição)
    funcionarioId: v.id("funcionarios"),
    gestorId: v.id("usuarios"),
    // Dados do registro original (se for edição)
    horaAnterior: v.optional(v.number()),
    minutoAnterior: v.optional(v.number()),
    // Dados do registro novo (se for edição)
    horaNova: v.optional(v.number()),
    minutoNova: v.optional(v.number()),
    // Motivo e observações
    motivoId: v.optional(v.string()), // ID do motivo (referência a atestados/declarações)
    motivoTipo: v.optional(v.string()), // Tipo do motivo (atestado, declaracao, etc)
    motivoDescricao: v.optional(v.string()), // Descrição do motivo
    observacoes: v.optional(v.string()),
    // Tipo de ajuste (se for ajuste de banco de horas)
    tipoAjuste: v.optional(v.union(
      v.literal("compensar"),
      v.literal("abonar"),
      v.literal("descontar")
    )),
    // Período do ajuste (se for ajuste de banco de horas)
    periodoDias: v.optional(v.number()),
    periodoHoras: v.optional(v.number()),
    periodoMinutos: v.optional(v.number()),
    // Ajuste em minutos (calculado)
    ajusteMinutos: v.optional(v.number()),
    criadoEm: v.number(),
  })
    .index("by_funcionario", ["funcionarioId"])
    .index("by_gestor", ["gestorId"])
    .index("by_registro", ["registroId"])
    .index("by_data", ["criadoEm"]),

  // Dispensas de Registro - Períodos onde funcionário está dispensado de registrar ponto
  dispensasRegistro: defineTable({
    funcionarioId: v.id("funcionarios"),
    gestorId: v.id("usuarios"),
    dataInicio: v.string(), // YYYY-MM-DD
    horaInicio: v.number(),
    minutoInicio: v.number(),
    dataFim: v.string(), // YYYY-MM-DD
    horaFim: v.number(),
    minutoFim: v.number(),
    motivo: v.string(),
    isento: v.boolean(), // Se true, não expira (casos excepcionais)
    ativo: v.boolean(),
    criadoEm: v.number(),
  })
    .index("by_funcionario", ["funcionarioId"])
    .index("by_gestor", ["gestorId"])
    .index("by_ativo", ["ativo"])
    .index("by_data_inicio", ["dataInicio"])
    .index("by_data_fim", ["dataFim"]),
});
