package templates

import (
	"errors"
	"html/template"
	"log"
	"net/http"
	"path"
	"path/filepath"
	"strings"

	"github.com/shurcooL/httpfs/html/vfstemplate"
	"github.com/shurcooL/httpfs/path/vfspath"
)

// Templates contains a map of filenames to parsed and prepared templates
type Templates map[string]*template.Template

// LoadTemplatesFS takes a filesystem and a location, and returns a Templates
// map
func LoadTemplatesFS(fs http.FileSystem, dir string) Templates {
	var templates = make(map[string]*template.Template)

	layouts, err := vfspath.Glob(fs, dir+"/layouts/*.tmpl")
	if err != nil {
		log.Fatal(err)
	}

	//log.Printf("Loaded %d layouts", len(layouts))

	includes, err := vfspath.Glob(fs, dir+"/includes/*.tmpl")
	if err != nil {
		log.Fatal(err)
	}

	//log.Printf("Loaded %d includes", len(includes))

	funcs := getFuncMap() // generate function map

	// Generate our templates map from our layouts/ and includes/ directories
	for _, layout := range layouts {
		files := append(includes, layout)
		t := template.New(filepath.Base(layout)).Funcs(funcs)
		t, err := vfstemplate.ParseFiles(fs, t, files...)
		if err != nil {
			log.Fatalf("Error parsing template %s: %s",
				filepath.Base(layout), err)
		}
		templates[filepath.Base(layout)] = t
	}

	return templates
}

func (templates Templates) Get(name string) *template.Template {
	t, ok := templates[name]
	if !ok {
		log.Printf("Error loading template %s", name)
		return template.Must(template.New("empty").Parse("ERROR: Template missing"))
	}
	return t
}

func getFuncMap() template.FuncMap {
	return template.FuncMap{
		"istrue": func(value bool) bool {
			return value
		},
		"join": func(sep string, a []string) string {
			return strings.Join(a, sep)
		},
		"dict": func(values ...interface{}) (map[string]interface{}, error) {
			if len(values)%2 != 0 {
				return nil, errors.New("invalid dict call")
			}
			dict := make(map[string]interface{}, len(values)/2)
			for i := 0; i < len(values); i += 2 {
				key, ok := values[i].(string)
				if !ok {
					return nil, errors.New("dict keys must be strings")
				}
				dict[key] = values[i+1]
			}
			return dict, nil
		},
		"url": func(rel ...string) string {
			params := []string{"/"}
			params = append(params, rel...)
			return path.Join(params...)
		},
		"static": func(rel ...string) string {
			params := []string{"/static"}
			params = append(params, rel...)
			return path.Join(params...)
		},
		"i18n": func(locale, key string) string {
			switch locale {
			case "de":
				return "Hallo Welt!"
			case "en":
				return "Hello World!"
			default:
				log.Printf("I18n: '%s' has no key '%s'", locale, key)
				return key
			}
		},
	}
}