# frozen_string_literal: true

module GDK
  module Command
    # Handles `gdk config` command execution
    #
    # This command accepts the following subcommands:
    # - list
    # - get <config key>
    # - set <config key> <value>
    class Config < BaseCommand
      # We need to handle conflicting configuration (Vite vs. webpack).
      # Config is validated before saving.
      def self.validate_config?
        false
      end

      def run(args = [])
        case args.shift
        when 'get'
          config_get(*args)
        when 'set'
          GDK::Output.abort('Usage: gdk config set <name> <value>', report_error: false) if args.length != 2

          config_set(*args)
        when 'list'
          GDK::Output.puts(config)
          true
        else
          GDK::Output.warn('Usage: gdk config [<get>|set] <name> [<value>]')
          GDK::Output.warn('       gdk config list')
          abort
        end
      end

      private

      def config_get(*name)
        GDK::Output.abort('Usage: gdk config get <name>', report_error: false) if name.empty?

        GDK::Output.puts(config.dig(*name))

        true
      rescue GDK::ConfigSettings::SettingUndefined
        GDK::Output.abort("Cannot get config for #{name.join('.')}", report_error: false)
      rescue GDK::ConfigSettings::UnsupportedConfiguration, GDK::ConfigType::SettingsArray::ArrayAccessError => e
        GDK::Output.abort("#{e.message}.", e, report_error: false)
      end

      def config_set(slug, value)
        value_stored_in_gdk_yml = config.user_defined?(*slug)
        old_value = config.dig(*slug)
        new_value = config.bury!(slug, value)

        Command.validate_config!

        if old_value == new_value && value_stored_in_gdk_yml
          GDK::Output.warn("'#{slug}' is already set to '#{old_value}'")
          return true
        elsif old_value == new_value && !value_stored_in_gdk_yml
          GDK::Output.success("'#{slug}' is now set to '#{new_value}' (explicitly setting '#{old_value}').")
        elsif old_value != new_value && value_stored_in_gdk_yml
          GDK::Output.success("'#{slug}' is now set to '#{new_value}' (previously '#{old_value}').")
        else
          GDK::Output.success("'#{slug}' is now set to '#{new_value}' (previously using default '#{old_value}').")
        end

        config.save_yaml!
        GDK::Output.info("Don't forget to run 'gdk reconfigure'.")

        true
      rescue GDK::ConfigSettings::SettingUndefined => e
        GDK::Output.abort("Cannot get config for '#{slug}'.", e, report_error: false)
      rescue TypeError => e
        GDK::Output.abort(e.message, e, report_error: false)
      rescue StandardError => e
        GDK::Output.error(e.message, e)
        abort
      end
    end
  end
end
