# frozen_string_literal: true

module GFSM
  module Commands
    class Changelog < BaseCommand

      NEXT_ENTRY_MARKER = "<!--- next entry here -->"

      def self.help
        <<~HELP
        Usage: gfsm changelog [help] [--output-file [<path>]] [--no-incremental] [--force] [--prerelease] [--prerelease-name <prerelease_name>] [--configuration <configuration_file_path>] [--path <repository_path]

        Arguments:
            help                                  # Prints this help
            --output-file [<path>]                # Path to the output changelog file. Defaults to 'CHANGELOG.md'.
                                                  # If not specified, the generate changelog content will be written to stdout
            --no-incremental                      # When provided, the generated changelog won't look for an existing
                                                  # changelog file. When outputting to stdout the changelog will never be incremental
            --force                               # When there are no commits with a changelog trailer
                                                  # the version won't get bumped. Use this flag to force
                                                  # the version bump (will increase the patch version)
            --prerelease                          # Use this switch to also include a prerelease in the version.
                                                  # By default will add 'pre' and increment it like 'pre.1',
                                                  # 'pre.2' and so on
            --prerelease-name <name>              # Name of the prerelease that will get added when the
                                                  # switch is enabled
            --configuration <path>                # Path to the configuration YAML file
            --path <path>                         # Path to the repository. By default will use the current directory
        HELP
      end

      def run(args = [])
        if !args.empty? && args[0] == "help"
          GFSM::Output.puts(GFSM::Commands::Changelog.help)
        else
          no_incremental = args.include?("--no-incremental")
          output_file_path = get_output_file_path(args)
          changelog_section = compute_this_version_section(args)

          if !output_file_path
            GFSM::Output.puts <<~CHANGELOG
              # Changelog

              #{changelog_section}
              CHANGELOG
          else
            if File.exists?(output_file_path) && !no_incremental
              existing_content = File.read(output_file_path)

              file_content = existing_content.gsub(/#{Regexp.quote(NEXT_ENTRY_MARKER)}/i, changelog_section)

              File.open(output_file_path, 'w') { |file| file.write file_content }
            else
              File.open(output_file_path, 'w') do |file|
                file.write <<~CHANGELOG
                # Changelog

                #{changelog_section}
                CHANGELOG
              end
            end
          end
        end

        true
      end

      private

      def compute_this_version_section(args)
        force = args.include?("--force")
        prerelease = args.include?("--prerelease")
        prerelease_name = get_prerelease_name(args)
        repository_path = get_repository_path(args)
        configuration_file_path = get_configuration_file_path(args)

        version_bumper = GFSM::Tools::VersionBumper.new()
        version = version_bumper.compute_version!(force, prerelease, prerelease_name, repository_path, configuration_file_path)
        subdivisions = version_bumper.subdivisions.to_a
        subdivisions.sort_by! { |subdivision_data| subdivision_data[0].priority }.reverse!

        changelog_entries = ""

        subdivisions.each do |subdivision_data|
          change_type = subdivision_data[0]
          commits = subdivision_data[1]
          
          changelog_entries += "\n#{change_type.to_changelog_entry}\n\n"

          commits.each do |commit|
            changelog_entries += "- #{commit.to_changelog_entry}\n"
          end
        end

        if !subdivisions || subdivisions.empty?
          changelog_section = "#{NEXT_ENTRY_MARKER}\n\n## #{version}\n\n"
        else
          changelog_section = "#{NEXT_ENTRY_MARKER}\n\n## #{version}\n#{changelog_entries}"
        end
      end

      def extract_switch_value(args, switch, default_value)
        switch_index = args.find_index(switch)
        
        return default_value unless switch_index &&
                                    (switch_index + 1) < args.length

        args[switch_index + 1]
      end

      def extract_switch_value_if_present(args, switch, default_value)
        switch_index = args.find_index(switch)

        return nil unless switch_index
        return default_value unless (switch_index + 1) < args.length

        args[switch_index + 1]
      end

      def get_output_file_path(args)
        extract_switch_value_if_present(args, "--output-file", "./CHANGELOG.md")
      end

      def get_configuration_file_path(args)
        extract_switch_value(args, "--configuration", "./gfsmrc.yml")
      end

      def get_prerelease_name(args)
        extract_switch_value(args, "--prerelease-name", "pre")
      end
      
      def get_repository_path(args)
        extract_switch_value(args, "--path", ".")
      end
    end
  end
end