# frozen_string_literal: true

module GFSM
  module Commands
    class Changelog < BaseCommand

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

      def self.help
        cli_info = GFSM::Tools::VersionBumperSettings.cli_info

        <<~HELP
        Usage:
        gfsm changelog [help|generate] [--output-file <path>] [--no-incremental] #{cli_info[:usage]}

        Commands:
        help                                  # Prints this help
        generate                              # Generate the changelog for the current version

        Options:
        --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
        --only-new-entries                    # When provided, the generated changelog won't look for an existing changelog file and will contain only the new entries for the current version, without the Changelog or version headings
        #{cli_info[:options]}

        Environment variables:
        OUTPUT_FILE                           # Equivalent to --output-file
        NO_INCREMENTAL                        # Equivalent to --no-incremental
        ONLY_ENTRIES                          # Equivalent to --only-new-entries
        #{cli_info[:environment_variables]}
        HELP
      end

      def run(args = [])
        case args.shift
        when 'help'
          GFSM::Output.puts(GFSM::Commands::Changelog.help)
        when 'generate'
          no_incremental = ENV.has_key?("NO_INCREMENTAL") || args.include?("--no-incremental")
          only_new_entries = ENV.has_key?("ONLY_NEW_ENTRIES") || args.include?("--only-new-entries")
          output_file_path = get_output_file_path(args)
          changelog_section = compute_this_version_section(args, only_new_entries)

          if only_new_entries
            GFSM::Output.puts changelog_section
          elsif !output_file_path
            GFSM::Output.puts <<~CHANGELOG
              # Changelog
              #{changelog_section}
              CHANGELOG
          else
            if File.file?(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
        else
          GFSM::Output.warn(GFSM::Commands::Version.help)
        end

        true
      end

      private

      def compute_this_version_section(args, only_new_entries)
        settings = GFSM::Tools::VersionBumperSettings.new(args)
        version_bumper = GFSM::Tools::VersionBumper.new(settings)
        version = version_bumper.execute
        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 += "#{change_type.to_changelog_entry}\n\n"

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

          changelog_entries += "\n"
        end

        changelog_entries = changelog_entries[0...-1] unless changelog_entries.empty?

        return changelog_entries if only_new_entries

        section = "#{NEXT_ENTRY_MARKER}\n## #{version}"

        return section if !subdivisions || subdivisions.empty?

        "#{section}\n\n#{changelog_entries}"
      end

      def extract_switch_value_if_present(args, switch, default_value, env_name)
        return ENV.fetch(env_name) if ENV.has_key?(env_name)

        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", "OUTPUT_FILE")
      end
    end
  end
end