require 'sprockets'
require 'sprockets/engines'
require 'barber'

class Ember::Appkit::Rails::Template < Tilt::Template
  def self.default_mime_type
    'application/javascript'
  end

  def prepare; end

  def evaluate(scope, locals, &block)
    raw = handlebars?(scope)

    if raw
      template = data
    else
      template = mustache_to_handlebars(scope, data)
    end

    if configuration.precompile
      if raw
        template = precompile_handlebars(template)
      else
        template = precompile_ember_handlebars(template)
      end
    else
      if raw
        template = compile_handlebars(data)
      else
        template = compile_ember_handlebars(template)
      end
    end

    if configuration.output_type == :amd
      target = amd_template_target(scope)

      "define('#{target}', ['exports'], function(__exports__){ __exports__.default = #{template} });"
    else
      target = global_template_target(scope)

      "#{target} = #{template}\n"
    end
  end

  private

  def handlebars?(scope)
    scope.pathname.to_s =~ /\.raw\.(handlebars|hjs|hbs)/
  end

  def amd_template_target(scope)
    "#{configuration.amd_namespace}/#{scope.logical_path.split(".").first}"
  end

  def global_template_target(scope)
    "Ember.TEMPLATES[#{template_path(scope.logical_path).inspect}]"
  end

  def compile_handlebars(string)
    "Handlebars.compile(#{indent(string).inspect});"
  end

  def precompile_handlebars(string)
    Barber::FilePrecompiler.call(string)
  end

  def compile_ember_handlebars(string)
    "Ember.Handlebars.compile(#{indent(string).inspect});"
  end

  def precompile_ember_handlebars(string)
    Barber::Ember::FilePrecompiler.call(string)
  end

  def mustache_to_handlebars(scope, template)
    if scope.pathname.to_s =~ /\.mustache\.(handlebars|hjs|hbs)/
      template.gsub(/\{\{(\w[^\}\}]+)\}\}/){ |x| "{{unbound #{$1}}}" }
    else
      template
    end
  end

  def template_path(path)
    root = configuration.templates_root

    if root.kind_of? Array
      root.each do |root|
        path.sub!(/#{Regexp.quote(root)}\//, '')
      end
    else
      unless root.empty?
        path.sub!(/#{Regexp.quote(root)}\/?/, '')
      end
    end

    path = path.split('/')

    path.join(configuration.templates_path_separator)
  end

  def configuration
    ::Rails.configuration.handlebars
  end

  def indent(string)
    string.gsub(/$(.)/m, "\\1  ").strip
  end
end
