# app/services/notificacao/resolvedor_variaveis.rb
#
# Completa o contexto de um disparo com as variáveis que o template REALMENTE
# usa. É o que permite escrever {{entregas_mes}} ou {{telefone_suporte}} numa
# mensagem sem que o gatilho precise saber dessas variáveis.
#
# SOB DEMANDA, de propósito: `{{entregas_mes}}` é uma query no espelho de
# rastreio. Resolver o catálogo inteiro em todo disparo faria dezenas de
# consultas para preencher variáveis que ninguém escreveu.
#
# Precedência (a primeira que responde vence):
#   1. o que o gatilho já mandou (contexto real do acontecimento);
#   2. variável de sistema (empresa, data, hora…);
#   3. variável de dados (consulta ao banco);
#   4. variável personalizada do ADM.
#
# ⚠️ NADA aqui levanta. Uma variável que falha vira string vazia — a mesma regra
#    do renderizador, e pelo mesmo motivo: mensagem com buraco é ruim, disparo
#    derrubado por causa de um texto é pior.
module Notificacao
  module ResolvedorVariaveis
    MARCADOR = /\{\{\s*(\w+)\s*\}\}/

    module_function

    # textos: tudo que será interpolado (blocos do template, assunto, corpo).
    # dados:  o contexto que o gatilho produziu.
    def completar(textos, dados = {})
      contexto = (dados || {}).transform_keys(&:to_s)
      faltantes = usadas(textos) - contexto.keys

      faltantes.each_with_object(contexto.dup) do |chave, resultado|
        valor = resolver(chave)
        resultado[chave] = valor unless valor.nil?
      end
    end

    # Chaves {{assim}} encontradas em qualquer texto (String, Array ou Hash de
    # blocos — o template é jsonb aninhado).
    def usadas(textos)
      varrer(textos).scan(MARCADOR).flatten.uniq
    end

    def resolver(chave)
      chave = chave.to_s
      valor = valor_de_sistema(chave) || valor_de_dados(chave) || valor_personalizado(chave)
      valor&.to_s
    end

    # ── privados de módulo ──────────────────────────────────────
    def varrer(objeto)
      case objeto
      when String then objeto
      when Hash   then objeto.values.map { |v| varrer(v) }.join(' ')
      when Array  then objeto.map { |v| varrer(v) }.join(' ')
      else ''
      end
    end

    def valor_de_sistema(chave)
      meta = CatalogoVariaveis::SISTEMA[chave]
      meta && executar(meta[:resolver], chave)
    end

    def valor_de_dados(chave)
      meta = CatalogoVariaveis::DADOS[chave]
      meta && executar(meta[:resolver], chave)
    end

    def valor_personalizado(chave)
      return nil unless VariavelPersonalizada.table_exists?

      VariavelPersonalizada.ativas.find_by(chave: chave)&.valor
    rescue StandardError => e
      Rails.logger.error("[Variaveis] personalizada #{chave}: #{e.class}: #{e.message}")
      nil
    end

    def executar(bloco, chave)
      return nil if bloco.nil?

      resultado = bloco.call
      # Número cru numa mensagem fica sem separador de milhar ("4977").
      resultado.is_a?(Numeric) ? Formatador.numero(resultado) : resultado.to_s
    rescue StandardError => e
      Rails.logger.error("[Variaveis] #{chave}: #{e.class}: #{e.message}")
      nil
    end
  end
end
