require 'thread'

module TxCatcher

  # Cleans DB so that its size doesn't go above Config.max_db_transactions_stored
  class Cleaner

    class << self

      def stopped?
        @@stopped
      end
    
      def start(run_once: false)
        loop do
          @@cleaning_counter = { transactions: 0, deposits: 0, addresses: 0 }
          db_tx_count = if Config.protected_transactions
            TxCatcher::Transaction.where(Sequel.~(protected: true)).count
          else
            TxCatcher::Transaction.count
          end
          Logger.report "Cleaning transactions in DB..."
          Logger.report "#{db_tx_count} now, needs to be below #{Config.max_db_transactions_stored}\n"
          if db_tx_count > Config.max_db_transactions_stored
            number_to_delete = (db_tx_count - Config.max_db_transactions_stored) + (Config.max_db_transactions_stored*0.1).round
            clean_transactions(number_to_delete)
            Logger.report "DB cleaned: #{@@cleaning_counter.to_s}"
          else
            Logger.report "Nothing to be cleaned from DB, size is below threshold."
          end
          if @stop || run_once
            @@stopped = true
            break
          end
          sleep Config.db_clean_period_seconds
        end
      end

      def start_in_thread(run_once: false)
        @@stopped = false
        @@stop    = false
        Thread.new do
          start(run_once: run_once)
        end
        @@stopped
      end

      def stop
        @@stop = true
      end

      def clean_transactions(n)
        transactions = Transaction.order(Sequel.asc(:created_at))
        transactions.where(Sequel.~(protected: true)) if Config.protected_transactions

        t = n/100
        t = 1 if t == 0
        t.times do
          limit = n <= 100 ? n : 100
          transactions.limit(limit).each do |t|
            Logger.report "- Removing tx #{t.txid}"
            clean_deposits(t)
            TxCatcher.db_connection[:transactions].filter(id: t.id).delete
            @@cleaning_counter[:transactions] += 1
          end
        end
      end

      def clean_deposits(transaction)
        transaction.deposits.each do |d|
          if d.address && d.address.deposits.count == 1
            TxCatcher.db_connection[:addresses].filter(id: d.address.id).delete
            @@cleaning_counter[:addresses] += 1
          end
          TxCatcher.db_connection[:deposits].filter(id: d.id).delete
          @@cleaning_counter[:deposits] += 1
        end
      end

    end # class << self
  end # Cleaner
end # TxCatcher