# frozen_string_literal: true

require 'cdr_signal_api'

class CdrSignal
  attr_accessor :client

  #
  # check token and return bot attributes of token
  #
  #   bot = CdrSignal.check_token('token')
  #

  def self.check_token(api_url, token)
    api = CdrSignalAPI.new(api_url, token)
    begin
      bot = api.fetch_self
    rescue StandardError => e
      raise "invalid api token: #{e.message}"
    end
    bot
  end

  #
  # create or update channel, store bot attributes and verify token
  #
  #   channel = CdrSignal.create_or_update_channel('token', params)
  #
  # returns
  #
  #   channel # instance of Channel
  #

  def self.create_or_update_channel(api_url, token, params, channel = nil)
    # verify token
    bot = CdrSignal.check_token(api_url, token)

    raise 'Bot already exists!' unless channel && CdrSignal.bot_duplicate?(bot['id'])

    raise 'Group needed!' if params[:group_id].blank?

    group = Group.find_by(id: params[:group_id])
    raise 'Group invalid!' unless group

    unless channel
      channel = CdrSignal.bot_by_bot_id(bot['id'])
      channel ||= Channel.new
    end
    channel.area = 'Signal::Account'
    channel.options = {
      adapter: 'cdr_signal',
      bot: {
        id: bot['id'],
        number: bot['number']
      },
      api_token: token,
      api_url: api_url,
      welcome: params[:welcome]
    }
    channel.group_id = group.id
    channel.active = true
    channel.save!
    channel
  end

  #
  # check if bot already exists as channel
  #
  #   success = CdrSignal.bot_duplicate?(bot_id)
  #
  # returns
  #
  #   channel # instance of Channel
  #

  def self.bot_duplicate?(bot_id, channel_id = nil)
    Channel.where(area: 'Signal::Account').each do |channel|
      next unless channel.options
      next unless channel.options[:bot]
      next unless channel.options[:bot][:id]
      next if channel.options[:bot][:id] != bot_id
      next if channel.id.to_s == channel_id.to_s

      return true
    end
    false
  end

  #
  # get channel by bot_id
  #
  #   channel = CdrSignal.bot_by_bot_id(bot_id)
  #
  # returns
  #
  #   true|false
  #

  def self.bot_by_bot_token(bot_token)
    Channel.where(area: 'Signal::Account').each do |channel|
      next unless channel.options
      next unless channel.options[:bot_token]
      return channel if channel.options[:bot_token].to_s == bot_token.to_s
    end
    nil
  end

  #
  #   date = CdrSignal.timestamp_to_date('1543414973285')
  #
  # returns
  #
  #   2018-11-28T14:22:53.285Z
  #

  def self.timestamp_to_date(timestamp_str)
    Time.at(timestamp_str.to_i).utc.to_datetime
  end

  def self.message_id(message_raw)
    format('%<source>s@%<timestamp>s', source: message_raw['source'], timestamp: message_raw['timestamp'])
  end

  #
  #   client = CdrSignal.new('token')
  #

  def initialize(api_url, token)
    @token = token
    @api_url = api_url
    @api = CdrSignalAPI.new(api_url, token)
  end

  #
  #   client.send_message(chat_id, 'some message')
  #

  def send_message(recipient, message)
    return if Rails.env.test?

    @api.send_message(recipient, message)
  end

  def user(number)
    {
      # id:         params[:message][:from][:id],
      id: number,
      username: number
      # first_name: params[:message][:from][:first_name],
      # last_name:  params[:message][:from][:last_name]
    }
  end

  def to_user(message)
    Rails.logger.debug { 'Create user from message...' }
    Rails.logger.debug { message.inspect }

    # do message_user lookup
    message_user = user(message[:source])

    # create or update user
    login = message_user[:username] || message_user[:id]

    auth = Authorization.find_by(uid: message[:source], provider: 'cdr_signal')

    user_data = {
      login: login,
      mobile: message[:source]
    }

    user = if auth
             User.find(auth.user_id)
           else
             User.where(mobile: message[:source]).order(:updated_at).first
           end
    if user
      user.update!(user_data)
    else
      user = User.create!(
        firstname: message[:source],
        mobile: message[:source],
        note: "Signal #{message_user[:username]}",
        active: true,
        role_ids: Role.signup_role_ids
      )
    end

    # create or update authorization
    auth_data = {
      uid: message_user[:id],
      username: login,
      user_id: user.id,
      provider: 'cdr_signal'
    }
    if auth
      auth.update!(auth_data)
    else
      Authorization.create(auth_data)
    end

    user
  end

  def to_ticket(message, user, group_id, channel)
    UserInfo.current_user_id = user.id

    Rails.logger.debug { 'Create ticket from message...' }
    Rails.logger.debug { message.inspect }
    Rails.logger.debug { user.inspect }
    Rails.logger.debug { group_id.inspect }

    # prepare title
    title = '-'
    title = message[:message][:body] unless message[:message][:body].nil?
    title = "#{title[0, 60]}..." if title.length > 60

    # find ticket or create one
    state_ids = Ticket::State.where(name: %w[closed merged removed]).pluck(:id)
    ticket = Ticket.where(customer_id: user.id).where.not(state_id: state_ids).order(:updated_at).first
    if ticket

      # check if title need to be updated
      ticket.title = title if ticket.title == '-'
      new_state = Ticket::State.find_by(default_create: true)
      ticket.state = Ticket::State.find_by(default_follow_up: true) if ticket.state_id != new_state.id
      ticket.save!
      return ticket
    end

    ticket = Ticket.new(
      group_id: 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,
        cdr_signal: {
          bot_token: channel.options[:bot_token],
          chat_id: message[:source]
        }
      }
    )
    ticket.save!
    ticket
  end

  def to_article(message, user, ticket, channel)
    Rails.logger.debug { 'Create article from message...' }
    Rails.logger.debug { message.inspect }
    Rails.logger.debug { user.inspect }
    Rails.logger.debug { ticket.inspect }

    UserInfo.current_user_id = user.id

    article = Ticket::Article.new(
      from: message[:source],
      to: channel[:options][:bot][:number],
      body: message[:message][:body],
      content_type: 'text/plain',
      message_id: "cdr_signal.#{message[:id]}",
      ticket_id: ticket.id,
      type_id: Ticket::Article::Type.find_by(name: 'cdr_signal').id,
      sender_id: Ticket::Article::Sender.find_by(name: 'Customer').id,
      internal: false,
      preferences: {
        cdr_signal: {
          timestamp: message[:timestamp],
          message_id: message[:id],
          from: message[:source]
        }
      }
    )

    # TODO: attachments
    # TODO voice
    # TODO emojis
    #
    if message[:message][:body]
      Rails.logger.debug { article.inspect }
      article.save!

      Store.remove(
        object: 'Ticket::Article',
        o_id: article.id
      )

      return article
    end
    raise 'invalid action'
  end

  def to_group(message, group_id, channel)
    # begin import
    Rails.logger.debug { 'signal import message' }

    # TODO: handle messages in group chats

    return if Ticket::Article.find_by(message_id: message[:id])

    ticket = nil
    # use transaction
    Transaction.execute(reset_user_id: true) do
      user = to_user(message)
      ticket = to_ticket(message, user, group_id, channel)
      to_article(message, user, ticket, channel)
    end

    ticket
  end

  def from_article(article)
    # sends a message from a zammad article

    Rails.logger.debug { "Create signal message from article to '#{article[:to]}'..." }

    @api.send_message(article[:to], article[:body])
  end
end
