# app/models/contato.rb
#
# Destinatário das notificações, cadastrado à mão pelo ADM: nome, número e/ou
# e-mail, e o grupo a que pertence.
#
# Telefone é gravado SEMPRE em E.164 (+5511920051157). O ADM digita como quiser
# — "(11) 92005-1157", "011 92005 1157" — e a normalização acontece aqui, uma
# vez, na gravação. Mandar o texto cru para o provedor devolve erro de destino
# inválido que o rescue do envio esconderia.
class Contato < ApplicationRecord
  belongs_to :grupo_contato, optional: true
  belongs_to :user, optional: true
  has_many :notificacao_envios, dependent: :nullify

  EMAIL_RE = /\A[^@\s]+@[^@\s]+\z/

  # Um destinatário é uma PESSOA (telefone e/ou e-mail) ou um GRUPO do WhatsApp.
  # O grupo entra aqui, e não em tabela própria, para herdar grupo interno,
  # assinatura de eventos e log de envios sem duplicar essa máquina.
  TIPOS = %w[pessoa grupo_whatsapp].freeze

  # Identificador de grupo do WhatsApp: "120363012345678901@g.us".
  JID_GRUPO_RE = /\A\d{5,}@g\.us\z/

  validates :nome, presence: true
  validates :tipo, inclusion: { in: TIPOS }
  validates :email, format: { with: EMAIL_RE }, allow_blank: true
  validate  :telefone_ou_email, if: :pessoa?
  validate  :telefone_valido,   if: :pessoa?
  validate  :grupo_identificado, if: :grupo_whatsapp?

  before_validation :normalizar

  scope :ativos,    -> { where(ativo: true) }
  scope :ordenados, -> { order(Arel.sql('LOWER(nome)')) }
  scope :pessoas, -> { where(tipo: 'pessoa') }
  scope :grupos_whatsapp, -> { where(tipo: 'grupo_whatsapp') }
  # "Tem WhatsApp" = número de pessoa OU identificador de grupo.
  scope :com_whatsapp, -> {
    where.not(telefone: [nil, '']).or(where.not(whatsapp_grupo_jid: [nil, '']))
  }
  scope :com_email,    -> { where.not(email: [nil, '']) }

  # Filtra pelo canal do disparo. 'ambos' = quem tiver qualquer um dos dois.
  scope :com_canal, ->(canal) {
    case canal.to_s
    when 'whatsapp' then com_whatsapp
    when 'email'    then com_email
    else where("(telefone IS NOT NULL AND telefone <> '') OR (email IS NOT NULL AND email <> '')")
    end
  }

  def pessoa?         = tipo.to_s != 'grupo_whatsapp'
  def grupo_whatsapp? = tipo.to_s == 'grupo_whatsapp'

  def whatsapp? = destino_whatsapp.present?
  def email?    = email.present? && pessoa?

  # Para onde o WhatsApp vai: o JID do grupo ou o número da pessoa. É o que a
  # ponte recebe — ela aceita as duas formas.
  def destino_whatsapp
    grupo_whatsapp? ? whatsapp_grupo_jid.presence : telefone.presence
  end

  # {{contato}} na mensagem. Em grupo não existe "primeiro nome" — cortar
  # "Motoristas SP" em "Motoristas" só empobreceria o texto.
  def primeiro_nome
    grupo_whatsapp? ? nome.to_s : nome.to_s.split.first.to_s
  end

  private

  def normalizar
    self.nome  = nome.to_s.strip.squeeze(' ').presence
    self.tipo  = tipo.presence || 'pessoa'

    if grupo_whatsapp?
      # Grupo não tem telefone nem e-mail: limpar evita um cadastro meio pessoa,
      # meio grupo, que mandaria a mesma mensagem duas vezes.
      self.telefone = nil
      self.email    = nil
      self.whatsapp_grupo_jid  = whatsapp_grupo_jid.to_s.strip.presence
      self.whatsapp_grupo_nome = whatsapp_grupo_nome.to_s.strip.presence
    else
      self.whatsapp_grupo_jid  = nil
      self.whatsapp_grupo_nome = nil
      self.email = email.to_s.strip.downcase.presence
      # Mantém o que foi digitado se não der para normalizar — a validação acusa
      # e o ADM vê o próprio valor de volta no campo para corrigir.
      bruto = telefone.to_s.strip.presence
      self.telefone = bruto && (ConfiguracaoNotificacao.normalizar_telefone(bruto) || bruto)
    end
  end

  def grupo_identificado
    return if whatsapp_grupo_jid.to_s.match?(JID_GRUPO_RE)

    errors.add(:whatsapp_grupo_jid,
               'inválido: escolha um grupo da lista (o identificador termina em @g.us)')
  end

  def telefone_ou_email
    return if telefone.present? || email.present?

    errors.add(:base, 'Informe ao menos um WhatsApp ou um e-mail.')
  end

  def telefone_valido
    return if telefone.blank?
    return if ConfiguracaoNotificacao.normalizar_telefone(telefone).present?

    errors.add(:telefone, 'não parece um número brasileiro válido (DDD + número)')
  end
end
