# frozen_string_literal: true

class Core::Repositories::Billing::ChatbotAi::Reset < Core::Repositories::AbstractRepository
  def initialize
  end

  def call
    Billings::ChatbotAiPackage.find_each(batch_size: 500) do |package|
      # hold reset if in the last month there is a minus usage
      if package.extra < 0
        package.update(is_reset_hold: true)
        next
      end

      reset(package)
    end

    Success true
  end

  def reset package
    package_log = Billings::ChatbotAiPackageLog.create(
                    chatbot_ai_package_id: package.id,
                    action:                'reset',
                    status:                'pending'
    )

    # value before
    value_before = {
      credit: package.credit,
      extra:  package.extra
    }

    initial_package = Billings::InitialChatbotAiPackage.find_by(chatbot_ai_package_id: package.id)
    beginning_of_the_month = (Time.zone.now.in_time_zone('Asia/Jakarta').beginning_of_month - 7.hours) # Prevent time gap of UTC

    is_failed = false
    error_message = ''
    Billings::ApplicationRecord.transaction do
      package.with_lock do
        chatbot_ai_gap = get_chatbot_ai_usage(package, beginning_of_the_month)
        chatbot_ai_credit = initial_package.credit - chatbot_ai_gap.credit

        # set extra from package if payment type is prepaid and set extra from initial if payment type is postpaid
        chatbot_ai_extra = package.extra
        if package.payment_type.eql?('postpaid')
          chatbot_ai_extra = initial_package.extra
        end

        if chatbot_ai_credit < 0
          chatbot_ai_extra += chatbot_ai_credit
          chatbot_ai_credit = 0
        end

        value_after = {
          credit: chatbot_ai_credit,
          extra:  chatbot_ai_extra
        }

        package.credit = chatbot_ai_credit
        package.extra = chatbot_ai_extra
        package.is_reset_hold = false

        raise error_messages_for(package) unless package.save
        package_log.update!(status: 'done', value_before: value_before, value_after: value_after)

        create_conversation_log(package, value_before, value_after)
      end
    rescue => e
      is_failed = true
      error_message = e.message.presence || ''
      Rails.logger.error(error_message.presence || 'Unknown error')
    end

    if is_failed.eql?(true)
      package_log.update!(status: 'failed', value_before: value_before, value_after: { message: error_message })
      return Failure error_message
    end

    Success true
  end

  private

  def get_chatbot_ai_usage(package, beginning_of_the_month)
    chatbot_ai_credit_gap = Billings::ChatbotAiConversationLog
      .where(chatbot_ai_package_id: package.id, credited_to: 'chatbot_ai_credit')
      .where('created_at > ?', beginning_of_the_month).count

    chatbot_ai_extra_gap = Billings::ChatbotAiConversationLog
      .where(chatbot_ai_package_id: package.id, credit: 1, credited_to: 'chatbot_ai_extra')
      .where('created_at > ?', beginning_of_the_month).count

    Hashie::Mash.new(credit: chatbot_ai_credit_gap, extra: chatbot_ai_extra_gap)
  end

  def create_conversation_log(package, value_before, value_after)
    credit_logs = [
      {
        chatbot_ai_package_id: package.id,
        action:                'reset',
        debited_to:            'chatbot_ai_credit',
        debit:                 value_after[:credit],
        value_before:          value_before[:credit],
        value_after:           value_after[:credit],
        is_outstanding:        false
      },
      {
        chatbot_ai_package_id: package.id,
        action:                'reset',
        debited_to:            'chatbot_ai_extra',
        debit:                 value_after[:extra],
        value_before:          value_before[:extra],
        value_after:           value_after[:extra],
        is_outstanding:        value_after[:extra] < 0
      }
    ]

    Billings::ChatbotAiConversationLog.insert_all!(credit_logs)
  end
end
