package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"io/fs"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"strconv"
	"strings"

	"code.ndumas.com/ndumas/badges"
	"github.com/go-chi/chi/v5"
	"github.com/go-chi/chi/v5/middleware"
)

var FONT_PATH = "fonts"

type BadgeRenderer struct {
	Fonts map[string]string
}

func NewBadgeRenderer(fontDir string) (*BadgeRenderer, error) {
	var br BadgeRenderer
	br.Fonts = make(map[string]string)

	root := os.DirFS(fontDir)
	err := fs.WalkDir(root, ".", func(path string, d fs.DirEntry, err error) error {
		if strings.HasSuffix(path, ".ttf") {
			absFont := filepath.Join(fontDir, path)
			br.Fonts[filepath.Base(path)] = absFont
		}
		return nil
	})

	if err != nil {
		return &br, fmt.Errorf("error walking for font files: %w", err)
	}

	return &br, nil
}

func (br *BadgeRenderer) listFonts(w http.ResponseWriter, r *http.Request) {
	style := chi.URLParam(r, "format")
	switch style {
	case "json":
		w.Header().Add("Content-Type", "application/json")
		enc := json.NewEncoder(w)
		err := enc.Encode(br.Fonts)
		if err != nil {
			w.WriteHeader(400)
			fmt.Fprintf(w, "couldn't encode font list to json: %s\n", err)
		}

	}
}

func (br *BadgeRenderer) renderBadge(w http.ResponseWriter, r *http.Request) {
	q := r.URL.Query()

	if len(q["label"]) < 1 {
		w.WriteHeader(400)
		fmt.Fprintf(w, "please provide a label")
	}
	label := q["label"][0]

	if len(q["message"]) < 1 {
		w.WriteHeader(400)
		fmt.Fprintf(w, "please provide a message")
	}
	message := q["message"][0]

	if len(q["color"]) < 1 {
		w.WriteHeader(400)
		fmt.Fprintf(w, "please provide a color")
	}
	color := q["color"][0]

	if len(q["size"]) < 1 {
		w.WriteHeader(400)
		fmt.Fprintf(w, "please provide a size")
	}

	size, err := strconv.ParseInt(q["size"][0], 10, 64)
	if err != nil {
		w.WriteHeader(400)
		fmt.Fprintf(w, "could not convert size to integer: %s\n", err)

		return
	}

	if len(q["font"]) < 1 {
		w.WriteHeader(400)
		fmt.Fprintf(w, "please provide a font name")
	}
	font, ok := br.Fonts[q["font"][0]]

	if !ok {
		w.WriteHeader(400)
		fmt.Fprintf(w, "unknown font selection\n")
	}

	bg, err := badge.NewGenerator(font, int(size))

	if err != nil {
		w.WriteHeader(400)
		fmt.Fprintf(w, "error instantitating generator: %s\n", err)

		return
	}

	w.Header().Add("Content-Type", "image/svg+xml")

	switch q["style"][0] {
	case "flat":
		fmt.Fprintf(w, "%s", bg.GenerateFlat(label, message, color))
	case "flatsimple":
		fmt.Fprintf(w, "%s", bg.GenerateFlatSimple(message, color))
	case "flatsquare":
		fmt.Fprintf(w, "%s", bg.GenerateFlatSquare(label, message, color))
	case "flatsquaresimple":
		fmt.Fprintf(w, "%s", bg.GenerateFlatSquareSimple(message, color))
	case "plastic":
		fmt.Fprintf(w, "%s", bg.GeneratePlastic(label, message, color))
	case "plasticsimple":
		fmt.Fprintf(w, "%s", bg.GeneratePlasticSimple(message, color))

	default:
		w.WriteHeader(400)
		fmt.Fprintf(w, "no matching style found\n")
	}
}

func main() {
	var (
		port     int
		fontsDir string
	)

	flag.IntVar(&port, "port", 8484, "http listening port")
	flag.StringVar(&fontsDir, "fonts", "fonts/", "directory containing ttf files")

	flag.Parse()

	absFontDir, err := filepath.Abs(fontsDir)
	if err != nil {
		log.Fatalf("error building absolute font dir path: %s\n", err)
	}
	log.Println("absFontDir:", absFontDir)
	br, err := NewBadgeRenderer(absFontDir)

	if err != nil {
		fmt.Println("couldn't create renderer", err)
		return
	}

	r := chi.NewRouter()
	r.Use(middleware.Logger)
	// r.Use(middleware.Recoverer)
	r.Use(middleware.Compress(5, "image/svg+xml"))
	r.Get("/badge", br.renderBadge)
	r.Get("/fonts/{format}", br.listFonts)

	http.ListenAndServe(fmt.Sprintf(":%d", port), r)
}
