# == Schema Information
#
# Table name: channel_voice
#
#  id                    :bigint           not null, primary key
#  additional_attributes :jsonb
#  phone_number          :string           not null
#  provider              :string           default("twilio"), not null
#  provider_config       :jsonb            not null
#  created_at            :datetime         not null
#  updated_at            :datetime         not null
#  account_id            :integer          not null
#
# Indexes
#
#  index_channel_voice_on_account_id    (account_id)
#  index_channel_voice_on_phone_number  (phone_number) UNIQUE
#
class Channel::Voice < ApplicationRecord
  include Channelable

  self.table_name = 'channel_voice'

  validates :phone_number, presence: true, uniqueness: true
  validates :provider, presence: true
  validates :provider_config, presence: true

  # Validate phone number format (E.164 format)
  validates :phone_number, format: { with: /\A\+[1-9]\d{1,14}\z/ }

  # Provider-specific configs stored in JSON
  validate :validate_provider_config
  before_validation :provision_twilio_on_create, on: :create, if: :twilio?

  EDITABLE_ATTRS = [:phone_number, :provider, { provider_config: {} }].freeze

  def name
    "Voice (#{phone_number})"
  end

  def messaging_window_enabled?
    false
  end

  def initiate_call(to:, conference_sid: nil, agent_id: nil)
    case provider
    when 'twilio'
      Voice::Provider::Twilio::Adapter.new(self).initiate_call(
        to: to,
        conference_sid: conference_sid,
        agent_id: agent_id
      )
    else
      raise "Unsupported voice provider: #{provider}"
    end
  end

  # Public URLs used to configure Twilio webhooks
  def voice_call_webhook_url
    digits = phone_number.delete_prefix('+')
    Rails.application.routes.url_helpers.twilio_voice_call_url(phone: digits)
  end

  def voice_status_webhook_url
    digits = phone_number.delete_prefix('+')
    Rails.application.routes.url_helpers.twilio_voice_status_url(phone: digits)
  end

  private

  def twilio?
    provider == 'twilio'
  end

  def validate_provider_config
    return if provider_config.blank?

    case provider
    when 'twilio'
      validate_twilio_config
    end
  end

  def validate_twilio_config
    config = provider_config.with_indifferent_access
    # Require credentials and provisioned TwiML App SID
    required_keys = %w[account_sid auth_token api_key_sid api_key_secret twiml_app_sid]
    required_keys.each do |key|
      errors.add(:provider_config, "#{key} is required for Twilio provider") if config[key].blank?
    end
  end

  def provider_config_hash
    if provider_config.is_a?(Hash)
      provider_config
    else
      JSON.parse(provider_config.to_s)
    end
  end

  def provision_twilio_on_create
    service = ::Twilio::VoiceWebhookSetupService.new(channel: self)
    app_sid = service.perform
    return if app_sid.blank?

    cfg = provider_config.with_indifferent_access
    cfg[:twiml_app_sid] = app_sid
    self.provider_config = cfg
  rescue StandardError => e
    error_details = {
      error_class: e.class.to_s,
      message: e.message,
      phone_number: phone_number,
      account_id: account_id,
      backtrace: e.backtrace&.first(5)
    }
    Rails.logger.error("TWILIO_VOICE_SETUP_ON_CREATE_ERROR: #{error_details}")
    errors.add(:base, "Twilio setup failed: #{e.message}")
  end

  public :provider_config_hash
end
