package blog

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

//go:embed templates/*.html
var templateFS embed.FS

type pageData struct {
	Title      string
	Posts      []Post
	Post       Post
	PostList   bool
	ActiveSlug string
}

func safehtml(s string) template.HTML {
	return template.HTML(s)
}

var tmpl *template.Template

func init() {
	var err error
	tmpl, err = template.New("").Funcs(template.FuncMap{"safehtml": safehtml}).ParseFS(templateFS, "templates/*.html")
	if err != nil {
		panic(err)
	}
}

func render(w http.ResponseWriter, r *http.Request, data pageData) {
	w.Header().Set("Content-Type", "text/html; charset=utf-8")
	if r.Header.Get("HX-Request") == "true" {
		tmpl.ExecuteTemplate(w, "main-content", data)
		return
	}
	tmpl.ExecuteTemplate(w, "base.html", data)
}

func RegisterRoutes(mux *http.ServeMux, contentDir string) error {
	ogDir := filepath.Join(contentDir, "..", "og")
	store := NewStore()
	if err := store.Load(contentDir); err != nil {
		log.Printf("blog: warning: could not load posts from %s: %v", contentDir, err)
	}
	store.GenerateOGImages(ogDir)

	mux.Handle("/blog/og/", http.StripPrefix("/blog/og/", http.FileServer(http.Dir(ogDir))))

	mux.HandleFunc("/blog/admin/reload", func(w http.ResponseWriter, r *http.Request) {
		if r.Method != http.MethodPost {
			http.Error(w, "POST only", http.StatusMethodNotAllowed)
			return
		}
		if err := store.Load(contentDir); err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		store.GenerateOGImages(ogDir)
		w.Write([]byte("reloaded\n"))
	})

	mux.HandleFunc("/blog/posts/", func(w http.ResponseWriter, r *http.Request) {
		slug := strings.TrimPrefix(r.URL.Path, "/blog/posts/")
		if slug == "" || strings.Contains(slug, "/") {
			http.NotFound(w, r)
			return
		}
		p, ok := store.Get(slug)
		if !ok {
			http.NotFound(w, r)
			return
		}
		render(w, r, pageData{
			Title: p.Title + " — Chaosmith Systems",
			Posts: store.All(),
			Post:  p,
		})
	})

	mux.HandleFunc("/blog/", func(w http.ResponseWriter, r *http.Request) {
		if r.URL.Path != "/blog/" {
			http.NotFound(w, r)
			return
		}
		render(w, r, pageData{
			Title:    "Chaosmith Systems — Field Notes",
			Posts:    store.All(),
			PostList: true,
		})
	})

	mux.HandleFunc("/blog/feed.xml", func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/rss+xml; charset=utf-8")
		w.Write([]byte(generateRSS(store)))
	})

	mux.HandleFunc("/blog/feed.json", func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/feed+json; charset=utf-8")
		w.Write([]byte(generateJSONFeed(store)))
	})

	mux.HandleFunc("/sitemap.xml", func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/xml; charset=utf-8")
		w.Write([]byte(generateSitemap(store)))
	})

	mux.HandleFunc("/robots.txt", func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "text/plain")
		w.Write([]byte("User-agent: *\nAllow: /\n\nSitemap: https://chaosmith.systems/sitemap.xml\n"))
	})

	log.Printf("blog: loaded %d post(s) from %s, mounted at /blog/", store.Count(), contentDir)
	return nil
}

func ServeLanding(w http.ResponseWriter, r *http.Request) {
	if r.URL.Path != "/" {
		http.NotFound(w, r)
		return
	}
	data := pageData{Title: "Chaosmith Systems"}
	if r.Header.Get("HX-Request") == "true" {
		tmpl.ExecuteTemplate(w, "main-content", data)
		return
	}
	tmpl.ExecuteTemplate(w, "base.html", data)
}
