class Channel::Driver::Sms::Twilio
  NAME = 'sms/twilio'.freeze

  def fetchable?(_channel)
    false
  end

  def send(options, attr, _notification = false)
    Rails.logger.info "Sending SMS to recipient #{attr[:recipient]}"

    return true if Setting.get('import_mode')

    Rails.logger.info "Backend sending Twilio SMS to #{attr[:recipient]}"
    begin
      if Setting.get('developer_mode') != true
        result = api(options).messages.create(
          from: options[:sender],
          to:   attr[:recipient],
          body: attr[:message],
        )

        raise result.error_message if result.error_code.positive?
      end

      true
    rescue => e
      Rails.logger.debug "Twilio error: #{e.inspect}"
      raise e
    end
  end

  def process(_options, attr, channel)
    Rails.logger.info "Receiving SMS frim recipient #{attr[:From]}"

    # prevent already created articles
    if Ticket::Article.find_by(message_id: attr[:SmsMessageSid])
      return ['application/xml; charset=UTF-8;', Twilio::TwiML::MessagingResponse.new.to_s]
    end

    # find sender
    user = User.where(mobile: attr[:From]).order(:updated_at).first
    if !user
      _from_comment, preferences = Cti::CallerId.get_comment_preferences(attr[:From], 'from')
      if preferences && preferences['from'] && preferences['from'][0]
        if preferences['from'][0]['level'] == 'known' && preferences['from'][0]['object'] == 'User'
          user = User.find_by(id: preferences['from'][0]['o_id'])
        end
      end
    end
    if !user
      user = User.create!(
        firstname: attr[:From],
        mobile:    attr[:From],
      )
    end

    UserInfo.current_user_id = user.id

    # find ticket
    article_type_sms = Ticket::Article::Type.find_by(name: 'sms')
    state_ids = Ticket::State.where(name: %w[closed merged removed]).pluck(:id)
    ticket = Ticket.where(customer_id: user.id, create_article_type_id: article_type_sms.id).where.not(state_id: state_ids).order(:updated_at).first
    if ticket
      new_state = Ticket::State.find_by(default_create: true)
      if ticket.state_id != new_state.id
        ticket.state = Ticket::State.find_by(default_follow_up: true)
        ticket.save!
      end
    else
      if channel.group_id.blank?
        raise Exceptions::UnprocessableEntity, 'Group needed in channel definition!'
      end

      group = Group.find_by(id: channel.group_id)
      if !group
        raise Exceptions::UnprocessableEntity, 'Group is invalid!'
      end

      title = attr[:Body]
      if title.length > 40
        title = "#{title[0, 40]}..."
      end
      ticket = Ticket.new(
        group_id:    channel.group_id,
        title:       title,
        state_id:    Ticket::State.find_by(default_create: true).id,
        priority_id: Ticket::Priority.find_by(default_create: true).id,
        customer_id: user.id,
        preferences: {
          channel_id: channel.id,
          sms:        {
            AccountSid: attr['AccountSid'],
            From:       attr['From'],
            To:         attr['To'],
          }
        }
      )
      ticket.save!
    end

    Ticket::Article.create!(
      ticket_id:    ticket.id,
      type:         article_type_sms,
      sender:       Ticket::Article::Sender.find_by(name: 'Customer'),
      body:         attr[:Body],
      from:         attr[:From],
      to:           attr[:To],
      message_id:   attr[:SmsMessageSid],
      content_type: 'text/plain',
      preferences:  {
        channel_id: channel.id,
        sms:        {
          AccountSid: attr['AccountSid'],
          From:       attr['From'],
          To:         attr['To'],
        }
      }
    )

    ['application/xml; charset=UTF-8;', Twilio::TwiML::MessagingResponse.new.to_s]
  end

  def self.definition
    {
      name:         'twilio',
      adapter:      'sms/twilio',
      account:      [
        { name: 'options::webhook_token', display: 'Webhook Token', tag: 'input', type: 'text', limit: 200, null: false, default: Digest::MD5.hexdigest(rand(999_999_999_999).to_s), disabled: true, readonly: true },
        { name: 'options::account_id', display: 'Account SID', tag: 'input', type: 'text', limit: 200, null: false, placeholder: 'XXXXXX' },
        { name: 'options::token', display: 'Token', tag: 'input', type: 'text', limit: 200, null: false },
        { name: 'options::sender', display: 'Sender', tag: 'input', type: 'text', limit: 200, null: false, placeholder: '+491710000000' },
        { name: 'group_id', display: 'Destination Group', tag: 'select', null: false, relation: 'Group', nulloption: true, filter: { active: true } },
      ],
      notification: [
        { name: 'options::account_id', display: 'Account SID', tag: 'input', type: 'text', limit: 200, null: false, placeholder: 'XXXXXX' },
        { name: 'options::token', display: 'Token', tag: 'input', type: 'text', limit: 200, null: false },
        { name: 'options::sender', display: 'Sender', tag: 'input', type: 'text', limit: 200, null: false, placeholder: '+491710000000' },
      ],
    }
  end

  private

  def api(options)
    @api ||= ::Twilio::REST::Client.new options[:account_id], options[:token]
  end
end
