const { join } = require('path')
const Handlebars = require('handlebars')
const fetch = require('node-fetch')
const { readFile, fileExists } = require('./utils')

const TEMPLATES_DIR = join(__dirname, '..', 'templates')
const MATCH_URL = /^https?:\/\/.+/
const COMPILE_OPTIONS = {
  noEscape: true
}

Handlebars.registerHelper('json', (object) => {
  return new Handlebars.SafeString(JSON.stringify(object, null, 2))
})

Handlebars.registerHelper('commit-list', (context, options) => {
  if (!context || context.length === 0) {
    return ''
  }

  const list = context
    .filter(item => {
      const commit = item.commit || item
      if (options.hash.exclude) {
        const pattern = new RegExp(options.hash.exclude, 'm')
        if (pattern.test(commit.message)) {
          return false
        }
      }
      if (options.hash.message) {
        const pattern = new RegExp(options.hash.message, 'm')
        return pattern.test(commit.message)
      }
      if (options.hash.subject) {
        const pattern = new RegExp(options.hash.subject)
        return pattern.test(commit.subject)
      }
      return true
    })
    .map(item => options.fn(item))
    .join('')

  if (!list) {
    return ''
  }

  return `${options.hash.heading}\n\n${list}`
})

Handlebars.registerHelper('matches', function (val, pattern, options) {
  const r = new RegExp(pattern, options.hash.flags || '')
  return r.test(val) ? options.fn(this) : options.inverse(this)
})

const getTemplate = async template => {
  if (MATCH_URL.test(template)) {
    const response = await fetch(template)
    return response.text()
  }
  if (await fileExists(template)) {
    return readFile(template)
  }
  const path = join(TEMPLATES_DIR, template + '.hbs')
  if (await fileExists(path) === false) {
    throw new Error(`Template '${template}' was not found`)
  }
  return readFile(path)
}

const cleanTemplate = template => {
  return template
    // Remove indentation
    .replace(/\n +/g, '\n')
    .replace(/^ +/, '')
    // Fix multiple blank lines
    .replace(/\n\n\n+/g, '\n\n')
    .replace(/\n\n$/, '\n')
}

const compileTemplate = async (releases, options) => {
  const { template, handlebarsSetup } = options
  if (handlebarsSetup) {
    const path = /^\//.test(handlebarsSetup) ? handlebarsSetup : join(process.cwd(), handlebarsSetup)
    const setup = require(path)
    if (typeof setup === 'function') {
      setup(Handlebars)
    }
  }
  const compile = Handlebars.compile(await getTemplate(template), COMPILE_OPTIONS)
  if (template === 'json') {
    return compile({ releases, options })
  }
  return cleanTemplate(compile({ releases, options }))
}

module.exports = {
  compileTemplate
}