# frozen-string-literal: true
require 'cli/ui'

module CLI
  module UI
    module Spinner
      autoload :Async,      'cli/ui/spinner/async'
      autoload :SpinGroup,  'cli/ui/spinner/spin_group'

      PERIOD = 0.1 # seconds
      TASK_FAILED = :task_failed

      RUNES = CLI::UI::OS.current.supports_emoji? ? %w(⠋ ⠙ ⠹ ⠸ ⠼ ⠴ ⠦ ⠧ ⠇ ⠏).freeze : %w(\\ | / - \\ | / -).freeze

      begin
        colors = [CLI::UI::Color::CYAN.code] * (RUNES.size / 2).ceil +
          [CLI::UI::Color::MAGENTA.code] * (RUNES.size / 2).to_i
        GLYPHS = colors.zip(RUNES).map(&:join)
      end

      class << self
        attr_accessor(:index)

        # We use this from CLI::UI::Widgets::Status to render an additional
        # spinner next to the "working" element. While this global state looks
        # a bit repulsive at first, it's worth realizing that:
        #
        # * It's managed by the SpinGroup#wait method, not individual tasks; and
        # * It would be complete insanity to run two separate but concurrent SpinGroups.
        #
        # While it would be possible to stitch through some connection between
        # the SpinGroup and the Widgets included in its title, this is simpler
        # in practice and seems unlikely to cause issues in practice.
        def current_rune
          RUNES[index || 0]
        end
      end

      # Adds a single spinner
      # Uses an interactive session to allow the user to pick an answer
      # Can use arrows, y/n, numbers (1/2), and vim bindings to control
      #
      # https://user-images.githubusercontent.com/3074765/33798295-d94fd822-dce3-11e7-819b-43e5502d490e.gif
      #
      # ==== Attributes
      #
      # * +title+ - Title of the spinner to use
      #
      # ==== Options
      #
      # * +:auto_debrief+ - Automatically debrief exceptions? Default to true
      #
      # ==== Block
      #
      # * *spinner+ - Instance of the spinner. Can call +update_title+ to update the user of changes
      #
      # ==== Example Usage:
      #
      #   CLI::UI::Spinner.spin('Title') { sleep 1.0 }
      #
      def self.spin(title, auto_debrief: true, &block)
        sg = SpinGroup.new(auto_debrief: auto_debrief)
        sg.add(title, &block)
        sg.wait
      end
    end
  end
end