var fs = require('fs')
var path = require('path')
var handlebars = require('handlebars')
var moment = require('moment')

exports.create = function (options) {
  var DIR_TEMPLATES = path.join(__dirname, '..', '..', 'templates')
  var DIR_THEME = path.join(DIR_TEMPLATES, 'themes', options.theme)

  function isTemplate (filepath) {
    return path.extname(filepath) === '.hbs'
  }

  function compileTemplate (hbsFile) {
    var src = fs.readFileSync(hbsFile)
    return handlebars.compile(src.toString())
  }

  // main entry points
  var templates = {
    'album': compileTemplate(path.join(DIR_TEMPLATES, 'album.hbs'))
  }

  // common partials
  handlebars.registerPartial('analytics', compileTemplate(path.join(DIR_TEMPLATES, 'analytics.hbs')))
  handlebars.registerPartial('thumbnail', compileTemplate(path.join(DIR_TEMPLATES, 'thumbnail.hbs')))

  // theme partials
  var files = fs.readdirSync(DIR_THEME)
  files.filter(isTemplate).forEach(function (filename) {
    var templateName = path.basename(filename, path.extname(filename))
    handlebars.registerPartial(templateName, compileTemplate(path.join(DIR_THEME, filename)))
  })

  // utility helper
  // render a date in a legible format
  handlebars.registerHelper('date', function (date) {
    return moment(date).format('DD MMM YYYY')
  })

  // utility helper
  // render the first X items in an array
  handlebars.registerHelper('slice', function (context, block) {
    var ret = ''
    var count = parseInt(block.hash.count) || 1
    var i = 0
    var j = (count < context.length) ? count : context.length
    for (i, j; i < j; i++) {
      ret += block.fn(context[i])
    }
    return ret
  })

  // utility helper
  // execute the child block N times
  handlebars.registerHelper('times', function (n, block) {
    var accum = ''
    for (var i = 0; i < n; ++i) { accum += block.fn(i) }
    return accum
  })

  // utility helper
  // execute a block if a condition matches
  // ideally we want to use unit-testable models instead
  // however this lets theme authors be more creative without changing the core model
  // THANKS TO http://doginthehat.com.au/2012/02/comparison-block-helper-for-handlebars-templates/#comment-44
  handlebars.registerHelper('compare', function (lvalue, operator, rvalue, options) {
    var operators, result
    if (arguments.length < 3) {
      throw new Error("Handlerbars Helper 'compare' needs 2 parameters")
    }
    if (options === undefined) {
      options = rvalue
      rvalue = operator
      operator = '==='
    }
    operators = {
      '==': function (l, r) { return l == r }, // eslint-disable-line eqeqeq
      '===': function (l, r) { return l === r },
      '!=': function (l, r) { return l != r }, // eslint-disable-line eqeqeq
      '!==': function (l, r) { return l !== r },
      '<': function (l, r) { return l < r },
      '>': function (l, r) { return l > r },
      '<=': function (l, r) { return l <= r },
      '>=': function (l, r) { return l >= r }
    }
    if (!operators[operator]) {
      throw new Error(`Handlerbars Helper 'compare' doesn't know the operator ${operator}`)
    }
    result = operators[operator](lvalue, rvalue)
    if (result) {
      return options.fn(this)
    } else {
      return options.inverse(this)
    }
  })

  // utility helper
  // return the relative path from the current folder to the argument
  var currentFolder = '.'
  handlebars.registerHelper('relative', function (target, options) {
    return path.relative(currentFolder, target)
  })

  return {
    render: function (template, data, folder) {
      currentFolder = folder
      return templates[template](data)
    }
  }
}
