# app/services/notificacao/catalogo_variaveis.rb
#
# TODAS as variáveis que o editor de mensagem oferece, de quatro origens:
#
#   :contexto      — vêm com o disparo (motorista, consolidação, valor…). Só têm
#                    valor nos gatilhos que as produzem; em outro gatilho saem
#                    vazias, e a tela avisa isso.
#   :sistema       — não dependem de contexto nenhum (empresa, data, hora, mês).
#   :dados         — CONSULTAM O BANCO na hora do envio (entregas do mês, total a
#                    pagar…). Resolvidas sob demanda: só a variável realmente
#                    escrita no template vira query.
#   :personalizada — cadastradas pelo ADM (VariavelPersonalizada), valor fixo.
#
# Antes, `Notificacao::Variaveis::POR_GATILHO` amarrava a lista ao gatilho: o ADM
# via 6 variáveis e nada mais, e qualquer texto com número (“entregas do mês”)
# precisava de deploy. Aqui a lista é aberta — e o que não se aplica é MARCADO em
# vez de escondido.
#
# ⚠️ Um `resolver` NUNCA pode levantar: notificação não derruba fechamento. O
#    ResolvedorVariaveis engole e devolve vazio.
module Notificacao
  module CatalogoVariaveis
    ORIGENS = {
      contexto:      'Do que aconteceu',
      sistema:       'Empresa e data',
      dados:         'Números do sistema',
      personalizada: 'Suas variáveis'
    }.freeze

    # ── Sistema: sempre disponíveis ───────────────────────────
    SISTEMA = {
      'empresa' => {
        descricao: 'Nome da empresa', amostra: 'Reem Transportes',
        resolver: -> { Configuracao.valor('empresa_nome').presence || 'Reem Transportes' }
      },
      'data' => {
        descricao: 'Data de hoje (dd/mm/aaaa)', amostra: '26/08/2026',
        resolver: -> { Date.current.strftime('%d/%m/%Y') }
      },
      'hora' => {
        descricao: 'Hora do envio', amostra: '14:35',
        resolver: -> { Time.current.strftime('%H:%M') }
      },
      'dia_semana' => {
        descricao: 'Dia da semana por extenso', amostra: 'quarta-feira',
        resolver: -> { I18n.l(Date.current, format: '%A') rescue Date::DAYNAMES[Date.current.wday] }
      },
      'mes' => {
        descricao: 'Mês por extenso', amostra: 'agosto',
        resolver: -> { I18n.l(Date.current, format: '%B') rescue Date::MONTHNAMES[Date.current.month] }
      },
      'mes_ano' => {
        descricao: 'Mês/ano (mm/aaaa)', amostra: '08/2026',
        resolver: -> { Date.current.strftime('%m/%Y') }
      },
      'link_sistema' => {
        descricao: 'Endereço do sistema', amostra: 'https://app.reemtransportes.com.br',
        resolver: -> { Configuracao.valor('url_sistema').presence || ENV.fetch('APP_URL', '') }
      }
    }.freeze

    # ── Contexto: quem produz é o gatilho ─────────────────────
    # `gatilhos:` diz em quais a variável tem valor — é o que a tela usa para
    # avisar "esta sai vazia aqui".
    CONTEXTO = {
      'contato'      => { descricao: 'Primeiro nome de quem recebe', amostra: 'Carlos', gatilhos: :todos },
      'quem'         => { descricao: 'Quem executou a ação no sistema', amostra: 'Ana Paula', gatilhos: :todos },
      'motorista'    => { descricao: 'Nome do motorista', amostra: 'Carlos Matheus Pimentel' },
      'consolidacao' => { descricao: 'Nome da consolidação', amostra: 'UBS NORTE 01–14/08' },
      'periodo'      => { descricao: 'Período do fechamento', amostra: '01/08/2026 a 14/08/2026' },
      'valor'        => { descricao: 'Valor do motorista', amostra: 'R$ 5.060,00' },
      'entregas'     => { descricao: 'Entregas atendidas no fechamento', amostra: '280' },
      'link_painel'  => { descricao: 'Link do painel do motorista', amostra: 'https://app.reem.com.br/motorista' },
      'o_que_mudou'  => { descricao: 'O que foi alterado', amostra: 'Desconto de R$ 120,00 (avaria)' },
      'operacao'     => { descricao: 'Operação afetada', amostra: 'UBS NORTE AGO 2026' },
      'nf'           => { descricao: 'Nota fiscal', amostra: '85382' },
      'entregues'    => { descricao: 'Notas entregues (resumo)', amostra: '4.851' },
      'recusas'      => { descricao: 'Notas não entregues (resumo)', amostra: '122' },
      'pendentes'    => { descricao: 'Notas em aberto (resumo)', amostra: '0' },
      'retentativas' => { descricao: 'Visitas além da primeira (resumo)', amostra: '4' },
      'fora_operacao' => { descricao: 'Notas fora da operação (resumo)', amostra: '2' }
    }.freeze

    # Quais variáveis de contexto cada gatilho realmente preenche.
    POR_GATILHO = {
      'manual'                  => [],
      'consolidacao_finalizada' => %w[motorista consolidacao periodo valor entregas link_painel],
      'pagamento_efetuado'      => %w[motorista consolidacao periodo valor entregas link_painel],
      'valor_alterado'          => %w[motorista consolidacao periodo valor entregas link_painel o_que_mudou],
      'operacao_alterada'       => %w[operacao o_que_mudou nf],
      'agendado'                => %w[operacao periodo entregues recusas pendentes retentativas fora_operacao]
    }.freeze

    # ── Dados: consultam o banco na hora do envio ─────────────
    # Cada uma responde a uma pergunta que o ADM hoje só conseguiria escrevendo à
    # mão — e que ficaria desatualizada na mensagem seguinte.
    DADOS = {
      'entregas_mes' => {
        descricao: 'Entregas atendidas no mês corrente', amostra: '4.977',
        resolver: -> { Entrega.atendidas.da_conta_gade.no_periodo_checkout(Date.current.beginning_of_month, Date.current).count }
      },
      'entregas_hoje' => {
        descricao: 'Entregas atendidas hoje', amostra: '213',
        resolver: -> { Entrega.atendidas.da_conta_gade.no_periodo_checkout(Date.current, Date.current).count }
      },
      'motoristas_ativos_mes' => {
        descricao: 'Motoristas com entrega no mês', amostra: '17',
        resolver: -> { Entrega.motoristas_ativos(inicio: Date.current.beginning_of_month, fim: Date.current).size }
      },
      'consolidacoes_abertas' => {
        descricao: 'Consolidações em rascunho', amostra: '3',
        resolver: -> { Consolidacao.ativas.rascunho.count }
      },
      'total_a_pagar_mes' => {
        descricao: 'Total a pagar no mês (fechado e não pago)', amostra: 'R$ 72.508,00',
        resolver: lambda {
          totais = Analytics::TotaisPorMotorista.new(inicio: Date.current.beginning_of_month,
                                                     fim: Date.current.end_of_month)
          Formatador.moeda(totais.total_pendente)
        }
      },
      'total_pago_mes' => {
        descricao: 'Total já pago no mês', amostra: 'R$ 21.300,00',
        resolver: lambda {
          totais = Analytics::TotaisPorMotorista.new(inicio: Date.current.beginning_of_month,
                                                     fim: Date.current.end_of_month)
          Formatador.moeda(totais.total_pago)
        }
      },
      'total_consolidado_mes' => {
        descricao: 'Total consolidado no mês', amostra: 'R$ 93.808,00',
        resolver: lambda {
          totais = Analytics::TotaisPorMotorista.new(inicio: Date.current.beginning_of_month,
                                                     fim: Date.current.end_of_month)
          Formatador.moeda(totais.total_geral)
        }
      }
    }.freeze

    module_function

    # Todas as variáveis conhecidas, incluindo as que o ADM cadastrou.
    # { chave => { origem:, descricao:, amostra: } }
    def todas
      base = {}
      SISTEMA.each  { |c, m| base[c] = { origem: :sistema,  descricao: m[:descricao], amostra: m[:amostra] } }
      CONTEXTO.each { |c, m| base[c] = { origem: :contexto, descricao: m[:descricao], amostra: m[:amostra] } }
      DADOS.each    { |c, m| base[c] = { origem: :dados,    descricao: m[:descricao], amostra: m[:amostra] } }
      personalizadas.each do |v|
        base[v.chave] = { origem: :personalizada, descricao: v.descricao.presence || 'Sua variável', amostra: v.valor }
      end
      base
    end

    # A variável tem valor NESTE gatilho? Contexto de outro gatilho sai vazio —
    # a tela mostra, em vez de esconder a variável (foi o pedido: liberdade com
    # aviso, não lista curta).
    def aplicavel?(chave, gatilho)
      meta = CONTEXTO[chave.to_s]
      return true if meta.nil?                    # sistema/dados/personalizada: sempre
      return true if meta[:gatilhos] == :todos

      Array(POR_GATILHO[gatilho.to_s]).include?(chave.to_s)
    end

    def origem(chave)
      todas.dig(chave.to_s, :origem)
    end

    def existe?(chave) = todas.key?(chave.to_s)

    # Agrupadas para a tela do editor, na ordem de ORIGENS.
    def por_origem(gatilho = nil)
      agrupadas = ORIGENS.keys.index_with { |o| [] }
      todas.each do |chave, meta|
        agrupadas[meta[:origem]] << meta.merge(chave: chave, aplicavel: gatilho.nil? || aplicavel?(chave, gatilho))
      end
      agrupadas
    end

    # Contexto do PREVIEW: valores de amostra, nunca de envio real.
    def amostra(gatilho = nil)
      todas.filter_map { |chave, meta|
        [chave, meta[:amostra].to_s] if gatilho.nil? || aplicavel?(chave, gatilho)
      }.to_h
    end

    def personalizadas
      return [] unless VariavelPersonalizada.table_exists?

      VariavelPersonalizada.ativas.to_a
    rescue StandardError
      []
    end
  end
end
