package renderer

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

	"gogs.carducci-dante.gov.it/karmen/config"
)

var currRenderer Renderer

type Renderer interface {
	Render(http.ResponseWriter, string, string, interface{}) error
}

type JSONRenderer struct{}

func NewJSONRenderer() *JSONRenderer {
	return &JSONRenderer{}
}

func (r *JSONRenderer) Render(w http.ResponseWriter, layout string, name string, data interface{}) error {
	w.Header().Set("Content-Type", "application/json; charset=utf-8")
	j, err := json.Marshal(data)
	if err != nil {
		return err
	}
	w.Write(j)
	return nil
}

type HTMLRenderer struct {
	TemplatePath string

	templates map[string]*template.Template
}

func NewHTMLRenderer(templatePath string) (*HTMLRenderer, error) {
	r := &HTMLRenderer{
		TemplatePath: templatePath,
		templates:    make(map[string]*template.Template),
	}
	fns, err := filepath.Glob(filepath.Join(templatePath, "*.tpl"))
	if err != nil {
		return nil, err
	}
	lfns, err := filepath.Glob(filepath.Join(templatePath, "layout", "*.tpl"))
	if err != nil {
		return nil, err
	}

	for _, fn := range fns {
		if config.Config.LogLevel > config.LOG_LEVEL_OFF {
			log.Printf("Load %s template", fn)
		}

		tplName := filepath.Base(fn)
		tplName = strings.TrimSuffix(tplName, path.Ext(tplName))
		tplName = strings.TrimSuffix(tplName, path.Ext(tplName))

		files := append(lfns, fn)
		if err != nil {
			return nil, err
		}
		r.templates[tplName] = template.Must(r.templates[tplName].ParseFiles(files...))
		if err != nil {
			return nil, err
		}

	}

	return r, nil
}

func Use(r Renderer) {
	currRenderer = r
}

func (r *HTMLRenderer) Render(w http.ResponseWriter, layout string, name string, data interface{}) error {
	t, ok := r.templates[name]
	if !ok {
		return fmt.Errorf("Template %s not found", name)
	}
	w.Header().Set("Content-Type", "text/html; charset=utf-8")
	err := t.ExecuteTemplate(w, layout, data)
	if err != nil {
		return err
	}
	return nil
}

func Render(w http.ResponseWriter, layout string, name string, data interface{}) error {
	if currRenderer != nil {
		return currRenderer.Render(w, layout, name, data)
	}
	return errors.New("You should set a renderer with Use() first if you want to use Renderer() package function.")
}
