# frozen_string_literal: true

require_relative 'example_file/version'

require 'diffy'
require 'highline'
require 'paint'

## Class for example file
class ExampleFile
	SUFFIX = '.example'
	HIGHLINE = HighLine.new

	class << self
		def all(directory)
			Dir[File.join(directory, '**', "*#{SUFFIX}*")]
				.map { |file_name| new file_name }
		end
	end

	attr_reader :choices
	attr_writer :question_prefix

	def initialize(file_name)
		@file_name = file_name
		@regular_file_name = @file_name.sub SUFFIX, ''

		@basename = Paint[File.basename(@file_name), :green, :bold]
		@regular_basename = Paint[File.basename(@regular_file_name), :red, :bold]

		@choices = DEFAULT_CHOICES.dup
		@question_prefix = nil
	end

	def actualize_regular_file
		return create_regular_file unless regular_file_exist?

		return unless updated?

		return update_regular_file if diff.chomp.empty?

		ask_question_and_make_actions
	end

	def initialize_regular_file
		if File.exist? @regular_file_name
			raise "File `#{File.basename(@regular_file_name)}` already exists"
		end

		FileUtils.cp @file_name, @regular_file_name
	end

	private

	def updated?
		File.mtime(@file_name) > File.mtime(@regular_file_name)
	end

	def regular_file_exist?
		File.exist? @regular_file_name
	end

	def create_regular_file
		initialize_regular_file
		edit_file @regular_file_name
	end

	def update_regular_file
		FileUtils.touch @regular_file_name
	end

	def diff
		@diff ||= Diffy::Diff
			.new(@regular_file_name, @file_name, source: 'files', context: 3)
			.to_s(:color)
	end

	DEFAULT_CHOICES = {
		edit: proc { edit_file @regular_file_name },
		replace: proc { rewrite_regular_file },
		'replace-and-edit': proc do
			rewrite_regular_file
			edit_file @regular_file_name
		end,
		keep: proc do
			update_regular_file
			puts 'File modified time updated'
		end
	}.freeze

	private_constant :DEFAULT_CHOICES

	def ask_question_and_make_actions
		puts warning_with_diff

		HIGHLINE.choose do |menu|
			## I don't know how to catch complex options like `replace-and-edit`, via shortcut like `rae`
			# menu.layout = :one_line

			menu.header = "What to do with #{@regular_basename} "

			choices.each do |answer, block|
				menu.choice(answer) { instance_exec(&block) }
			end
		end
	end

	def warning_with_diff
		<<~WARN
			#{@question_prefix}#{@basename} was modified after #{@regular_basename}.

			```diff
			#{diff}
			```

		WARN
	end

	def edit_file(filename)
		abort '`EDITOR` environment variable is empty, see README' if ENV['EDITOR'].to_s.empty?

		system "eval $EDITOR #{filename}"
	end

	def rewrite_regular_file
		File.write @regular_file_name, File.read(@file_name)
	end
end