# frozen_string_literal: true

require 'cryptum/version'
require 'rbtrace'
require 'yaml'
require 'json'
require 'fileutils'
require 'tty-spinner'

# Root-Level Namespace for cryptum
module Cryptum
  $stdout.sync = true
  $stdout.flush

  autoload :API, 'cryptum/api'
  autoload :BotConf, 'cryptum/bot_conf'
  autoload :Event, 'cryptum/event'
  autoload :Indicator, 'cryptum/indicator'
  autoload :Log, 'cryptum/log'
  autoload :Matrix, 'cryptum/matrix'
  autoload :Option, 'cryptum/option'
  autoload :OrderBook, 'cryptum/order_book'
  autoload :Portfolio, 'cryptum/portfolio'
  autoload :ProbabilityEngine, 'cryptum/probability_engine'
  autoload :UI, 'cryptum/ui'
  autoload :WebSock, 'cryptum/web_sock'

  public_class_method def self.bin
    File.join root, 'bin'
  end

  public_class_method def self.etc
    File.join root, 'etc'
  end

  public_class_method def self.lib
    File.join root, 'lib'
  end

  public_class_method def self.order_book
    File.join root, 'order_book'
  end

  public_class_method def self.root
    File.dirname __dir__
  end

  public_class_method def self.open_symbol
    "\u00f8"
  end

  public_class_method def self.up_arrow
    "\u2191"
  end

  public_class_method def self.down_arrow
    "\u2193"
  end

  public_class_method def self.flat_arrow
    '_'
  end

  # Deserialize Cryptum Bot Conf
  public_class_method def self.read_bot_conf(opts = {})
    option_choice = opts[:option_choice]

    bot_conf_file = "#{option_choice.repo_root}/etc/bot_confs/#{option_choice.symbol}_bot_conf.yaml"
    unless File.exist?(bot_conf_file)
      FileUtils.cp(
        "#{option_choice.repo_root}/etc/bot_confs/BOT_CONF.TEMPLATE",
        bot_conf_file
      )
    end

    YAML.load_file(
      bot_conf_file,
      symbolize_names: true
    )
  rescue Errno::ENOENT, NoMethodError => e
    File.open('/tmp/cryptum-errors.txt', 'a') do |f|
      f.puts Time.now.strftime('%Y-%m-%d %H:%M:%S.%N %z')
      f.puts "Module: #{self}"
      f.puts "#{e}\n\n\n"
    end

    retry
  rescue Interrupt
    # Exit Gracefully if CTRL+C is Pressed During Session
    Cryptum.exit_gracefully(which_self: self)
  rescue StandardError => e
    # Produce a Stacktrace for anything else
    Curses.close_screen
    raise e
  end

  # Update Key/Value Pair in Bot Conf and Serialize to YAML File
  public_class_method def self.update_bot_conf_key(opts = {})
    option_choice = opts[:option_choice]
    bot_conf = opts[:bot_conf]
    key = opts[:key].to_s.to_sym
    value = opts[:value]

    bot_conf_file = "#{option_choice.repo_root}/etc/bot_confs/#{option_choice.symbol}_bot_conf.yaml"

    bot_conf[key] = value
    File.write(bot_conf_file, bot_conf.to_yaml)
  rescue Errno::ENOENT, NoMethodError => e
    File.open('/tmp/cryptum-errors.txt', 'a') do |f|
      f.puts Time.now.strftime('%Y-%m-%d %H:%M:%S.%N %z')
      f.puts "Module: #{self}"
      f.puts "#{e}\n\n\n"
    end

    retry
  rescue Interrupt
    # Exit Gracefully if CTRL+C is Pressed During Session
    Cryptum.exit_gracefully(which_self: self)
  rescue StandardError => e
    # Produce a Stacktrace for anything else
    Curses.close_screen
    raise e
  end

  # Update Key/Value Pair in Bot Conf and Serialize to YAML File
  public_class_method def self.beautify_large_number(opts = {})
    value = opts[:value].to_s

    split_str_num = value.split('.')
    whole_num = split_str_num.first
    fraction = 0
    fraction = split_str_num.last if split_str_num.length > 1

    is_negative = false
    is_negative = true if whole_num.chars.first == '-'
    whole_num = whole_num[1..] if is_negative
    beautify_whole = whole_num.reverse.scan(/.{1,3}/).join(',').reverse
    beautify_num = "#{beautify_whole}.#{fraction}" unless is_negative
    beautify_num = "-#{beautify_whole}.#{fraction}" if is_negative

    beautify_num
  rescue Interrupt
    # Exit Gracefully if CTRL+C is Pressed During Session
    Cryptum.exit_gracefully(which_self: self)
  rescue StandardError => e
    # Produce a Stacktrace for anything else
    Curses.close_screen
    raise e
  end

  public_class_method def self.exit_gracefully(opts = {})
    which_self = opts[:which_self]
    event_history = opts[:event_history]
    # option_choice = opts[:option_choice]
    # env = opts[:env]

    # Clear out candle data to ensure
    # Cryptum Statistics Only Apply to
    # Live Sessions
    if event_history
      File.write(
        order_book_file,
        JSON.pretty_generate(event_history.order_book)
      )
    end

    Curses.close_screen
    puts "Interrupt detected in #{which_self}...goodbye."

    exit 0
  rescue NameError
    puts "\nInterrupt detected in #{which_self}...goodbye."

    exit 0
  rescue StandardError => e
    # Produce a Stacktrace for anything else
    raise e
  end

  public_class_method def self.help
    constants.sort
  end
end