class Gateway < ApplicationRecord # Normalize metadata to always be a Hash attribute :metadata, :jsonb, default: {} has_many :sms_messages, dependent: :nullify before_validation :ensure_metadata_is_hash validates :device_id, presence: true, uniqueness: true validates :api_key_digest, presence: true validates :status, inclusion: { in: %w[online offline error] } scope :online, -> { where(status: "online") } scope :offline, -> { where(status: "offline") } scope :active, -> { where(active: true) } scope :by_priority, -> { order(priority: :desc, id: :asc) } # Find the best available gateway for sending messages def self.available_for_sending online.active.by_priority.first end # Generate a new API key for the gateway def generate_api_key! raw_key = "gw_live_#{SecureRandom.hex(32)}" self.api_key_digest = Digest::SHA256.hexdigest(raw_key) save! raw_key end # Check if gateway is currently online based on heartbeat def online? status == "online" && last_heartbeat_at.present? && last_heartbeat_at > 2.minutes.ago end # Update heartbeat timestamp and status def heartbeat! update!(status: "online", last_heartbeat_at: Time.current) end # Mark gateway as offline def mark_offline! update!(status: "offline") end # Increment message counters def increment_sent_count! increment!(:messages_sent_today) increment!(:total_messages_sent) end def increment_received_count! increment!(:messages_received_today) increment!(:total_messages_received) end # Reset daily counters (called by scheduled job) def self.reset_daily_counters! update_all(messages_sent_today: 0, messages_received_today: 0) end private def ensure_metadata_is_hash self.metadata = {} if metadata.nil? self.metadata = {} unless metadata.is_a?(Hash) end end