require 'colorize'

module Chronicle
  module ETL
    module CLI
      # Main entrypoint for CLI app
      class Main < Chronicle::ETL::CLI::CLIBase
        class_before :set_log_level
        class_before :set_color_output

        class_option :log_level, desc: 'Log level (debug, info, warn, error, fatal, silent)', default: 'info'
        class_option :verbose, aliases: '-v', desc: 'Set log level to verbose', type: :boolean
        class_option :silent, desc: 'Silence all output', type: :boolean
        class_option :'no-color', desc: 'Disable colour output', type: :boolean

        default_task 'jobs'

        desc 'connectors:COMMAND', 'Connectors available for ETL jobs', hide: true
        subcommand 'connectors', Connectors

        desc 'jobs:COMMAND', 'Configure and run jobs', hide: true
        subcommand 'jobs', Jobs

        desc 'plugins:COMMAND', 'Configure plugins', hide: true
        subcommand 'plugins', Plugins

        desc 'secrets:COMMAND', 'Manage secrets', hide: true
        subcommand 'secrets', Secrets

        desc 'authorizations', 'Authorize', hide: true
        subcommand 'authorizations', Authorizations

        # Entrypoint for the CLI
        def self.start(given_args = ARGV, config = {})
          # take a subcommand:command and splits them so Thor knows how to hand off to the subcommand class
          if given_args.any? && given_args[0].include?(':')
            commands = given_args.shift.split(':')
            given_args = given_args.unshift(commands).flatten
          end

          super(given_args, config)
        end

        def self.exit_on_failure?
          true
        end

        desc 'version', 'Show version'
        map %w[--version -v] => :version
        def version
          shell.say "chronicle-etl #{Chronicle::ETL::VERSION}"
        end

        # Displays help options for chronicle-etl
        def help(meth = nil, _subcommand = false)
          if meth && !respond_to?(meth)
            klass, task = ::Thor::Util.find_class_and_task_by_namespace("#{meth}:#{meth}")
            klass.start(['-h', task].compact, shell:)
          else
            shell.say 'ABOUT:'.bold
            shell.say "  #{'chronicle-etl'.italic} is a toolkit for extracting and working with your digital"
            shell.say '  history. 📜'
            shell.say
            shell.say "  A job #{'extracts'.underline} personal data from a source, #{'transforms'.underline} it (Chronicle"
            shell.say "  Schema or preserves raw data), and then #{'loads'.underline} it to a destination. Use"
            shell.say '  built-in extractors (json, csv, stdin) and loaders (csv, json, table,'
            shell.say '  rest) or use plugins to connect to third-party services.'
            shell.say
            shell.say '  Plugins: https://github.com/chronicle-app/chronicle-etl#currently-available'
            shell.say
            shell.say 'USAGE:'.bold
            shell.say '  # Basic job usage:'.italic.light_black
            shell.say '  $ chronicle-etl --extractor NAME --transformer NAME --loader NAME'
            shell.say
            shell.say '  # Read test.csv and display it to stdout as a table:'.italic.light_black
            shell.say '  $ chronicle-etl --extractor csv --input data.csv --loader table'
            shell.say
            shell.say '  # Show available plugins:'.italic.light_black
            shell.say '  $ chronicle-etl plugins:list'
            shell.say
            shell.say '  # Save an access token as a secret and use it in a job:'.italic.light_black
            shell.say '  $ chronicle-etl secrets:set pinboard access_token username:foo123'
            shell.say '  $ chronicle-etl secrets:list'
            shell.say '  $ chronicle-etl -e pinboard --since 1mo'
            shell.say
            shell.say '  # Show full job options:'.italic.light_black
            shell.say '  $ chronicle-etl jobs help run'
            shell.say
            shell.say 'FULL DOCUMENTATION:'.bold
            shell.say '  https://github.com/chronicle-app/chronicle-etl'.blue
            shell.say

            list = []
            ::Thor::Util.thor_classes_in(Chronicle::ETL::CLI).each do |thor_class|
              list += thor_class.printable_tasks(false)
            end
            list.sort! { |a, b| a[0] <=> b[0] }
            list.unshift ['help', '# This help menu']

            shell.say
            shell.say 'ALL COMMANDS:'.bold
            shell.print_table(list, indent: 2, truncate: true)
            shell.say
            shell.say 'VERSION:'.bold
            shell.say "  #{Chronicle::ETL::VERSION}"
            shell.say
            shell.say '  Display current version:'.italic.light_black
            shell.say '  $ chronicle-etl --version'
          end
        end

        no_commands do
          def set_color_output
            String.disable_colorization true if options[:'no-color'] || ENV['NO_COLOR']
          end

          def set_log_level
            if options[:silent]
              Chronicle::ETL::Logger.log_level = Chronicle::ETL::Logger::SILENT
            elsif options[:verbose]
              Chronicle::ETL::Logger.log_level = Chronicle::ETL::Logger::DEBUG
            elsif options[:log_level]
              level = Chronicle::ETL::Logger.const_get(options[:log_level].upcase)
              Chronicle::ETL::Logger.log_level = level
            end
          end
        end
      end
    end
  end
end
