# app/models/user.rb
class User < ApplicationRecord
  devise :database_authenticatable,
         
         :recoverable,
         :rememberable,
         :validatable

  # Perfil de acesso: nulo é válido (motorista não usa; e quem ainda não foi
  # migrado cai no padrão do papel — ver #permissoes_efetivas).
  belongs_to :perfil_acesso, optional: true, inverse_of: :users

  # ── Roles ──────────────────────────────────────────────────
  # externo: acesso somente-leitura ao dashboard (ex.: gerências de outras áreas
  # que só precisam visualizar os indicadores). Login normal por e-mail/senha.
  enum role: { admin: 0, gerente: 1, operador: 2, motorista: 3, externo: 4 }

  ROLES_LABEL = {
    'admin'     => 'Administrador',
    'gerente'   => 'Gerente',
    'operador'  => 'Operador',
    'motorista' => 'Motorista',
    'externo'   => 'Externo (só dashboard)'
  }.freeze

  # ── Validações ──────────────────────────────────────────────
  validates :nome,  presence: true, length: { minimum: 3 }
  validates :role,  presence: true
  validates :pin_code,
            length: { is: 4 },
            numericality: { only_integer: true },
            allow_nil: true,
            if: :motorista?

  validate :pin_unico_para_motoristas, if: :motorista?

  # E-mail em branco vira NULL: evita colisão no índice único quando vários
  # motoristas são criados sem e-mail (no Postgres NULLs são distintos entre si).
  before_validation :normalizar_email_em_branco

  # Motoristas podem não ter e-mail (login via PIN)
  def email_required?
    !motorista?
  end

  def password_required?
    !motorista? ? super : false
  end

  # ── Escopos ─────────────────────────────────────────────────
  scope :ativos,       -> { where(ativo: true) }
  scope :por_nome,     -> { order(:nome) }
  scope :nao_motoristas, -> { where.not(role: :motorista) }

  # ── Helpers ─────────────────────────────────────────────────
  def nome_display
    nome.presence || email
  end

  def role_label
    ROLES_LABEL[role] || role.humanize
  end

  # Conta desativada não entra — nem por e-mail/senha.
  #
  # Só o login por PIN checava `ativo?` (Users::SessionsController), então
  # desativar um gerente não impedia nada, apesar do formulário prometer
  # "usuários inativos não conseguem fazer login". Devise chama este método em
  # todo login e em toda request de sessão existente, então desativar alguém já
  # derruba a sessão aberta dele.
  def active_for_authentication?
    super && ativo?
  end

  def inactive_message
    ativo? ? super : :conta_desativada
  end

  # ── Permissões ──────────────────────────────────────────────
  # O que o usuário pode fazer sai do PERFIL DE ACESSO (PerfilAcesso), que o ADM
  # monta na tela. Enquanto ele não tem perfil, vale o padrão do papel legado
  # (Permissao::PADRAO_POR_ROLE) — é o que mantém o sistema funcionando durante a
  # migração e o que faz um usuário recém-criado não ficar sem nada.
  def pode?(chave)
    permissoes_efetivas.include?(chave.to_s)
  end

  # Set (não Array): `pode?` é chamado dezenas de vezes por render de tela — uma
  # vez por item de menu e por botão.
  #
  # ⚠️ A primeira linha existe para NÃO tocar o banco quando não há perfil: os
  # specs de policy usam `build(:admin)` (objeto sem id), e `perfil_acesso`
  # dispararia consulta com id nulo.
  def permissoes_efetivas
    @permissoes_efetivas ||=
      if perfil_acesso_id.nil?
        Set.new(Permissao.do_role(role))
      else
        Set.new(perfil_acesso&.permissoes_validas || Permissao.do_role(role))
      end
  end

  # A coluna nasce numa migration própria. Se o código subir antes de `db:migrate`
  # rodar, `perfil_acesso_id` não existe e TODA tela quebraria por NoMethodError —
  # aqui o sistema simplesmente continua no padrão do papel até a coluna chegar.
  # Pode sair depois que a migration estiver aplicada em produção.
  def perfil_acesso_id
    return nil unless self.class.column_names.include?('perfil_acesso_id')

    super
  end

  # Trocar o perfil no meio da request (tela de usuários) tem que refletir.
  def recarregar_permissoes!
    @permissoes_efetivas = nil
    self
  end

  # Primeira tela que este usuário pode abrir, na ordem em que o menu as mostra.
  #
  # Existe para não haver LOOP: a raiz do app é o dashboard e o tratamento de
  # "acesso negado" redireciona para a raiz — um perfil sem `dashboard.ver`
  # entraria em nega → raiz → nega para sempre. `nil` significa "não pode abrir
  # nada", e quem chama mostra a tela de sem-acesso.
  HOME_POR_PERMISSAO = [
    ['dashboard.ver',       :dashboard_path],
    ['dashboard.operacoes', :operacoes_dashboard_path],
    ['consolidacao.ver',    :consolidacoes_path],
    ['admin.usuarios',      :admin_usuarios_path],
    ['admin.perfis',        :admin_perfis_path],
    ['admin.configuracoes', :admin_configuracoes_path],
    ['admin.romaneio',      :admin_romaneios_path],
    ['notificacao.contatos', :admin_contatos_path],
    ['notificacao.eventos',  :admin_eventos_path],
    ['notificacao.envios',   :admin_envios_path]
  ].freeze

  def home_rota
    return :motorista_dashboard_path if motorista?

    HOME_POR_PERMISSAO.find { |chave, _| pode?(chave) }&.last
  end

  # Mantidos porque a navbar e vários controllers já os chamam — agora são só
  # apelidos das chaves correspondentes.
  def pode_ver_config?
    pode?('admin.configuracoes')
  end

  def pode_consolidar?
    pode?('consolidacao.ver')
  end

  # ── Trava do último administrador ───────────────────────────
  # Quem, ATIVO, ainda consegue reabrir a porta do sistema (mexer em perfis e em
  # usuários). Sem isto, o ADM consegue se trancar para fora: a tela que controla
  # acesso é justamente a que ele perderia, e a volta só existiria por console.
  #
  # `ignorando` simula "e se esta pessoa for desativada, excluída ou trocada de
  # perfil?" — passe o usuário que está sendo alterado.
  def self.administradores_de_acesso(ignorando: nil)
    ativos.includes(:perfil_acesso)
          .reject { |u| ignorando && u.id == ignorando.id }
          .select { |u| u.pode?('admin.perfis') && u.pode?('admin.usuarios_gerenciar') }
  end

  def self.ultimo_administrador?(usuario)
    return false unless usuario.pode?('admin.perfis') && usuario.pode?('admin.usuarios_gerenciar')

    administradores_de_acesso(ignorando: usuario).empty?
  end

  # Token de login rápido via QR Code (extrato) — Fase 7/8
  def regenerar_login_token!
    update!(login_token: SecureRandom.urlsafe_base64(24))
  end

  private

  def normalizar_email_em_branco
    self.email = nil if email.blank?
  end

  def pin_unico_para_motoristas
    return if pin_code.blank?

    conflito = User.motorista.where(pin_code: pin_code).where.not(id: id)
    errors.add(:pin_code, 'já está em uso por outro motorista') if conflito.exists?
  end
end
