package main

import (
	"fmt"
	"html/template"
	"log"
	"net/http"
	"time"
)

type handler = func(http.ResponseWriter, *http.Request)

func generateHandler(file string, handler func(), data func() any) handler {
	tmpl := template.Must(template.ParseFiles(fmt.Sprintf("templates/%s", file)))
	return func(w http.ResponseWriter, r *http.Request) {
		handler()
		w.Header().Set("Content-Type", "text/html; charset=utf-8")
		tmpl.Execute(w, data())
	}
}

func generateClick() handler {
	var clicks uint = 0
	return generateHandler(
		"click.html",
		func() { clicks++ },
		func() any { return clicks },
	)
}

func generateSseHandler(handler func(http.ResponseWriter, *http.Request)) handler {
	return func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "text/event-stream")
		w.Header().Set("Cache-Control", "no-cache")
		w.Header().Set("Connection", "keep-alive")
		w.WriteHeader(http.StatusOK)
		handler(w, r)
	}
}

func generateCounter() handler {
	return generateSseHandler(func(w http.ResponseWriter, r *http.Request) {
		tick := time.Tick(500 * time.Millisecond)
		ctx := r.Context()
	outer:
		for i := 0; ; i++ {
			select {
			case <-ctx.Done():
				break outer
			case <-tick:
				fmt.Fprintf(w, "event: count\ndata: %d\n\n", i)
				w.(http.Flusher).Flush()
			}
		}
	})
}

func main() {
	http.Handle("/", http.FileServer(http.Dir("static")))
	http.HandleFunc("/api/click1", generateClick())
	http.HandleFunc("/api/click2", generateClick())
	http.HandleFunc("/api/click3", generateClick())
	http.HandleFunc("/api/counter", generateCounter())
	log.Fatal(http.ListenAndServe(":3333", nil))
}