# frozen_string_literal: true

module Doing
  module Completion
    # Generate completions for Fish
    class FishCompletions

      attr_accessor :commands, :global_options

      def generate_helpers
        <<~EOFUNCTIONS
          function __fish_doing_needs_command
            # Figure out if the current invocation already has a command.

            set -l opts color h-help config_file= f-doing_file= n-notes v-version stdout debug default x-noauto no p-pager q-quiet yes
            set cmd (commandline -opc)
            set -e cmd[1]
            argparse -s $opts -- $cmd 2>/dev/null
            or return 0
            # These flags function as commands, effectively.
            if set -q argv[1]
              # Also print the command, so this can be used to figure out what it is.
              echo $argv[1]
              return 1
            end
            return 0
          end

          function __fish_doing_using_command
            set -l cmd (__fish_doing_needs_command)
            test -z "$cmd"
            and return 1
            contains -- $cmd $argv
            and return 0
          end

          function __fish_doing_cache_timer_expired
            set -l timer __fish_doing_cache_timer_$argv[1]
            if not set -q $timer
              set -g $timer (date '+%s')
            end

            if test (math (date '+%s') - $$timer) -gt $argv[2]
              set -g $timer (date '+%s')
              return 1
            end

            return 0
          end

          function __fish_doing_subcommands
            if not set -q __fish_doing_subcommands_cache
              or __fish_doing_cache_timer_expired subcommands 86400
              set -g -a __fish_doing_subcommands_cache (doing help -c)
            end
            printf '%s\n' $__fish_doing_subcommands_cache
          end

          function __fish_doing_complete_sections
            if not set -q __fish_doing_sections_cache
              or __fish_doing_cache_timer_expired sections 3600
              set -g -a __fish_doing_sections_cache (doing sections -c)
            end
            printf '%s\n' $__fish_doing_sections_cache
            __fish_doing_complete_show_tag
          end

          function __fish_doing_complete_views
            if not set -q __fish_doing_views_cache
              or __fish_doing_cache_timer_expired views 3600
              set -g -a __fish_doing_views_cache (doing views -c)
            end
            printf '%s\n' $__fish_doing_views_cache
          end

          function __fish_doing_export_plugin
            if not set -q __fish_doing_export_plugin_cache
              or __fish_doing_cache_timer_expired export_plugins 3600
              set -g -a __fish_doing_export_plugin_cache (doing plugins --type export -c)
            end
            printf '%s\n' $__fish_doing_export_plugin_cache
          end

          function __fish_doing_import_plugin
            if not set -q __fish_doing_import_plugin_cache
              or __fish_doing_cache_timer_expired import_plugins 3600
              set -g -a __fish_doing_import_plugin_cache (doing plugins --type import -c)
            end
            printf '%s\n' $__fish_doing_import_plugin_cache
          end

          function __fish_doing_complete_template
            if not set -q __fish_doing_template_cache
              or __fish_doing_cache_timer_expired template 3600
              set -g -a __fish_doing_template_cache (doing template -c)
            end
            printf '%s\n' $__fish_doing_template_cache
          end

          function __fish_doing_complete_tag
            if not set -q __fish_doing_tag_cache
              or __fish_doing_cache_timer_expired tags 60
              set -g -a __fish_doing_tag_cache (doing tags)
            end
            printf '%s\n' $__fish_doing_tag_cache
          end

          function __fish_doing_complete_show_tag
            if not set -q __fish_doing_tag_cache
              or __fish_doing_cache_timer_expired tags 60
              set -g -a __fish_doing_tag_cache (doing tags)
            end
            printf '@%s\n' $__fish_doing_tag_cache
          end

          function __fish_doing_complete_args
            for cmd in (doing commands_accepting -c $argv[1])
              complete -x -c doing -l $argv[1] -n "__fish_doing_using_command $cmd" -a "(__fish_doing_complete_$argv[1])"
            end
          end

          complete -c doing -f
          complete -xc doing -n '__fish_doing_needs_command' -a '(__fish_doing_subcommands)'

          complete -f -c doing -n '__fish_doing_using_command show' -a '(__fish_doing_complete_sections)'
          complete -f -c doing -n '__fish_doing_using_command view' -a '(__fish_doing_complete_views)'
          complete -f -c doing -n '__fish_doing_using_command template' -a '(__fish_doing_complete_templates)'
          complete -f -c doing -s t -l type -x -n '__fish_doing_using_command import' -a '(__fish_doing_import_plugins)'
          complete -f -c doing -n '__fish_doing_using_command help' -a '(__fish_doing_subcommands)'

          # complete -xc doing -n '__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from (doing help -c)' -a "(doing help -c)"

          function __fish_doing_complete_args
            for cmd in (doing commands_accepting -c $argv[1])
              complete -x -c doing -l $argv[1] -n "__fish_doing_using_command $cmd" -a "(__fish_doing_complete_$argv[1])"
            end
          end

          __fish_doing_complete_args tag
        EOFUNCTIONS
      end

      def generate_subcommand_completions
        out = []
        @commands.each do |cmd|
          desc = Shellwords.escape(cmd[:description])
          cmds = cmd[:commands].join(' ')
          out << "complete -xc doing -n '__fish_doing_needs_command' -a '#{cmds}' -d #{desc}"
        end

        out.join("\n")
      end

      def generate_subcommand_option_completions

        out = []
        need_export = []
        need_bool = []
        need_case = []
        need_sort = []
        need_tag_sort = []
        need_tag_order = []
        need_age = []
        need_section = []

        @commands.each_with_index do |cmd, i|
          @bar.advance(status: cmd[:commands].first)
          data = Completion.get_help_sections(cmd[:commands].first)

          if data[:synopsis].join(' ').strip.split(/ /).last =~ /(path|file)/i
            out << "complete -c doing -F -n '__fish_doing_using_command #{cmd[:commands].join(" ")}'"
          end

          if data[:command_options]
            Completion.parse_options(data[:command_options]).each do |option|
              next if option.nil?

              arg = option[:arg] ? '-r' : ''
              short = option[:short] ? "-s #{option[:short]}" : ''
              long = option[:long] ? "-l #{option[:long]}" : ''
              out << "complete -c doing #{long} #{short} -f #{arg} -n '__fish_doing_using_command #{cmd[:commands].join(' ')}' -d #{Shellwords.escape(option[:description])}"

              need_export.concat(cmd[:commands]) if option[:long] == 'output'
              need_bool.concat(cmd[:commands]) if option[:long] == 'bool'
              need_case.concat(cmd[:commands]) if option[:long] == 'case'
              need_sort.concat(cmd[:commands]) if option[:long] == 'sort'
              need_tag_sort.concat(cmd[:commands]) if option[:long] == 'tag_sort'
              need_tag_order.concat(cmd[:commands]) if option[:long] == 'tag_order'
              need_age.concat(cmd[:commands]) if option[:long] == 'age'
              need_section.concat(cmd[:commands]) if option[:long] == 'section'
            end
          end
        end

        unless need_export.empty?
          out << "complete -f -c doing -s o -l output -x -n '__fish_doing_using_command #{need_export.join(' ')}' -a '(__fish_doing_export_plugin)'"
        end

        unless need_bool.empty?
          out << "complete -f -c doing -s b -l bool -x -n '__fish_doing_using_command #{need_bool.join(' ')}' -a 'and or not pattern'"
        end

        unless need_case.empty?
          out << "complete -f -c doing -l case -x -n '__fish_doing_using_command #{need_case.join(' ')}' -a 'case-sensitive ignore smart'"
        end

        unless need_sort.empty?
          out << "complete -f -c doing -l sort -x -n '__fish_doing_using_command #{need_sort.join(' ')}' -a 'asc desc'"
        end

        unless need_tag_sort.empty?
          out << "complete -f -c doing -l tag_sort -x -n '__fish_doing_using_command #{need_tag_sort.join(' ')}' -a 'name time'"
        end

        unless need_tag_order.empty?
          out << "complete -f -c doing -l tag_order -x -n '__fish_doing_using_command #{need_tag_order.join(' ')}' -a 'asc desc'"
        end

        unless need_age.empty?
          out << "complete -f -c doing -s a -l age -x -n '__fish_doing_using_command #{need_age.join(' ')}' -a 'oldest newest'"
        end

        unless need_section.empty?
          out << "complete -f -c doing -s s -l section -x -n '__fish_doing_using_command #{need_section.join(' ')}' -a '(__fish_doing_complete_sections)'"
        end

        # clear
        out.join("\n")
      end

      def initialize
        data = Completion.get_help_sections
        @global_options = Completion.parse_options(data[:global_options])
        @commands = Completion.parse_commands(data[:commands])
        @bar = TTY::ProgressBar.new("\033[0;0;33mGenerating Fish completions: \033[0;35;40m[:bar] :status\033[0m", total: @commands.count + 1, bar_format: :square, hide_cursor: true, status: 'processing subcommands')
        width = TTY::Screen.columns - 45
        @bar.resize(width)
      end

      def generate_completions
        @bar.start
        out = []
        out << generate_helpers
        out << generate_subcommand_completions
        out << generate_subcommand_option_completions
        @bar.advance(status: '✅')
        @bar.finish
        out.join("\n")
      end
    end
  end
end