// Package ui contains the user info dashboard ui.
package ui

import (
	"bytes"
	"html/template"
	"io"
	"io/fs"
	"net/http"
	"path/filepath"
	"sync"
	"time"

	"github.com/pomerium/csrf"
)

// ServeFile serves a file.
func ServeFile(w http.ResponseWriter, r *http.Request, filePath string) error {
	f, etag, err := openFile(filepath.Join("dist", filePath))
	if err != nil {
		return err
	}
	defer f.Close()

	w.Header().Set("ETag", `"`+etag+`"`)
	http.ServeContent(w, r, filepath.Base(filePath), time.Time{}, f.(io.ReadSeeker))
	return nil
}

// RenderPage rends the index.html page.
func RenderPage(page, title string, data map[string]any) ([]byte, error) {
	if data == nil {
		data = make(map[string]any)
	}
	data["page"] = page

	return renderIndex(map[string]any{
		"Title": title,
		"Data":  data,
	})
}

// ServePage serves the index.html page.
func ServePage(w http.ResponseWriter, r *http.Request, page, title string, data map[string]any) error {
	if data == nil {
		data = make(map[string]any)
	}
	data["csrfToken"] = csrf.Token(r)

	bs, err := RenderPage(page, title, data)
	if err != nil {
		return err
	}

	w.Header().Set("Cache-Control", "no-cache, must-revalidate")
	http.ServeContent(w, r, "index.html", time.Time{}, bytes.NewReader(bs))
	return nil
}

var startTime = time.Now()

func renderIndex(data any) ([]byte, error) {
	tpl, err := parseIndex()
	if err != nil {
		return nil, err
	}

	var buf bytes.Buffer
	err = tpl.Execute(&buf, data)
	return buf.Bytes(), err
}

var (
	parseIndexOnce     sync.Once
	parseIndexTemplate *template.Template
	parseIndexError    error
)

func parseIndex() (*template.Template, error) {
	parseIndexOnce.Do(func() {
		var f fs.File
		f, _, parseIndexError = openFile("dist/index.gohtml")
		if parseIndexError != nil {
			return
		}
		var bs []byte
		bs, parseIndexError = io.ReadAll(f)
		_ = f.Close()
		if parseIndexError != nil {
			return
		}

		parseIndexTemplate, parseIndexError = template.New("").Parse(string(bs))
	})
	return parseIndexTemplate, parseIndexError
}