require "tty-file"
require "geny/context/view"

module Geny
  module Actions
    # Utilities for rendering and copying templates.
    # @see https://rubydoc.info/github/piotrmurach/tty-file/master/TTY/File TTY::File
    class Templates
      # Creates a new instance
      # @param root [String] the root path where templates live
      # @param view [View] a view that exposes locals and helpers
      def initialize(root:, view:)
        @root = root
        @view = view
      end

      # Copy a template file. The file will be evaluated with ERB.
      # All command-line options and helper methods are available in
      # the template.
      #
      # @example
      #   templates.copy("hello.erb", "hello.txt")
      #   templates.copy("hello.erb", "hello.txt", locals: {name: "world"})
      def copy(source, *args, **opts)
        source = expand_path(source)
        context, opts = build_context(opts)
        TTY::File.copy_file(source, *args, context: context, **opts)
      end

      # Copy a template directory. All files will be evaluated with ERB.
      # All command-line options and helper methods are available in
      # the template.
      #
      # @example
      #   templates.copy_dir("boilerplate", output)
      #   templates.copy_dir("boilerplate", output, locals: {name: "world"})
      def copy_dir(source, *args, **opts)
        source = expand_path(source)
        context, opts = build_context(opts)
        TTY::File.copy_dir(source, *args, context: context, **opts)
      end

      # Render an ERB template. All command-line options and helper
      # methods are available in the template.
      #
      # @example
      #   templates.render("hello.erb")
      #   templates.render("hello.erb", locals: {name: "world"})
      def render(path, **opts)
        path = expand_path(path)
        input = File.binread(path)
        context, _opts = build_context(opts)
        erb = ERB.new(input, nil, "-", "@output_buffer")
        erb.result(context.instance_eval("binding"))
      end

      private

      def build_context(locals: {}, **opts)
        [@view.merge(locals), opts]
      end

      def expand_path(path)
        File.expand_path(path, @root)
      end
    end
  end
end