package amber

import (
	"html/template"

	"fmt"
	"io"
	"path/filepath"
	"sync"

	"github.com/eknkc/amber"
	"github.com/kataras/iris/config"
)

// Engine the amber template engine
type Engine struct {
	Config        *config.Template
	templateCache map[string]*template.Template
	mu            sync.Mutex
}

// New creates and returns a new amber engine
func New(cfg config.Template) *Engine {
	return &Engine{Config: &cfg}
}

// BuildTemplates builds the amber templates
func (e *Engine) BuildTemplates() error {
	opt := amber.DirOptions{}
	opt.Recursive = true
	if e.Config.Extensions == nil || len(e.Config.Extensions) == 0 {
		e.Config.Extensions = []string{".html"}
	}

	// prepare the global amber funcs
	funcs := template.FuncMap{}
	for k, v := range amber.FuncMap { // add the amber's default funcs
		funcs[k] = v
	}
	if e.Config.Amber.Funcs != nil { // add the config's funcs
		for k, v := range e.Config.Amber.Funcs {
			funcs[k] = v
		}
	}

	amber.FuncMap = funcs //set the funcs

	opt.Ext = e.Config.Extensions[0]
	templates, err := amber.CompileDir(e.Config.Directory, opt, amber.DefaultOptions) // this returns the map with stripped extension, we want extension so we copy the map
	if err == nil {
		e.templateCache = make(map[string]*template.Template)
		for k, v := range templates {
			name := filepath.ToSlash(k + opt.Ext)
			e.templateCache[name] = v
			delete(templates, k)
		}

	}
	return err

}
func (e *Engine) fromCache(relativeName string) *template.Template {
	e.mu.Lock()
	tmpl, ok := e.templateCache[relativeName]
	if ok {
		e.mu.Unlock()
		return tmpl
	}
	e.mu.Unlock()
	return nil
}

// ExecuteWriter executes a templates and write its results to the out writer
func (e *Engine) ExecuteWriter(out io.Writer, name string, binding interface{}, layout string) error {
	if tmpl := e.fromCache(name); tmpl != nil {
		return tmpl.ExecuteTemplate(out, name, binding)
	}

	return fmt.Errorf("[IRIS TEMPLATES] Template with name %s doesn't exists in the dir %s", name, e.Config.Directory)
}