module RailsMFA::Model

def enable_mfa_for(*methods)

def enable_mfa_for(*methods)
  class_attribute :rails_mfa_methods, instance_accessor: false
  self.rails_mfa_methods = methods.map(&:to_sym)
end

def generate_totp_secret!

def generate_totp_secret!
  secret = ROTP::Base32.random_base32
  # host app should store secret encrypted in a column like :mfa_secret
  update!(mfa_secret: secret) if respond_to?(:update!)
  secret
end

def phone_number_for_sms

def phone_number_for_sms
  # host app should implement proper phone number attribute
  respond_to?(:phone) ? phone : raise("Define phone attribute or override phone_number_for_sms")
end

def send_numeric_code(via: :sms)

def send_numeric_code(via: :sms)
  tm = TokenManager.new
  code = tm.generate_numeric_code(id)
  case via.to_sym
  when :sms
    raise "sms_provider not configured" unless RailsMFA.configuration.sms_provider
    RailsMFA.configuration.sms_provider.call(phone_number_for_sms, "Your verification code is: #{code}")
  when :email
    raise "email_provider not configured" unless RailsMFA.configuration.email_provider
    RailsMFA.configuration.email_provider.call(email, "Your verification code", "Code: #{code}")
  else
    raise "Unsupported channel"
  end
  code
end

def totp_provisioning_uri(issuer: "RailsMFA")

def totp_provisioning_uri(issuer: "RailsMFA")
  raise "No mfa_secret present" unless respond_to?(:mfa_secret) && mfa_secret
  ROTP::TOTP.new(mfa_secret, issuer: issuer).provisioning_uri(respond_to?(:email) ? email : "user")
end

def verify_numeric_code(code)

def verify_numeric_code(code)
  tm = TokenManager.new
  tm.verify_numeric_code(id, code)
end

def verify_totp(code)

def verify_totp(code)
  return false unless respond_to?(:mfa_secret) && mfa_secret
  totp = ROTP::TOTP.new(mfa_secret)
  totp.verify(code, drift_behind: 30)
end