package main

import (
	"context"
	"embed"
	"fmt"
	"io/fs"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"strings"

	originclient "git.warky.dev/wdevs/origin_client/go"
	"wedding-server/internal/api"
	"wedding-server/internal/config"
	"wedding-server/internal/mail"
	"wedding-server/internal/store"
	"wedding-server/internal/webhook"
)

//go:embed all:web/dist
var embeddedWeb embed.FS

func main() {
	cfgPath := config.Path()
	cfg, err := config.Load(cfgPath)
	if err != nil {
		log.Fatalf("config: %v", err)
	}

	if err := os.MkdirAll(cfg.Storage.DataDir, 0o755); err != nil {
		log.Fatalf("data dir: %v", err)
	}

	st, err := store.Open(cfg.Storage.DataDir)
	if err != nil {
		log.Fatalf("store: %v", err)
	}
	defer st.Close()

	mailer := mail.New(cfg.Email)
	wh := webhook.New(cfg.Webhook)
	if cfg.Origin.ServiceKey == "" {
		log.Printf("origin registration disabled: origin.service_key is not configured")
	} else {
		origin, err := originclient.New(originclient.Config{
			URL:         cfg.Origin.URL,
			ServiceKey:  cfg.Origin.ServiceKey,
			Type:        "generic",
			Version:     cfg.Origin.Version,
			Name:        "ZoeShaldon",
			AppType:     "go",
			Port:        cfg.Server.Port,
			BaseURL:     cfg.Site.URL,
			Description: "CronoCraft App - ZoeShaldon wedding site",
		})
		if err != nil {
			log.Fatalf("origin client: %v", err)
		}
		go origin.Run(context.Background())
	}

	mux := http.NewServeMux()
	api.New(cfg, st, mailer, wh).Routes(mux)

	uploadsDir := filepath.Join(cfg.Storage.DataDir, "photos")
	mux.Handle("/uploads/", http.StripPrefix("/uploads/", http.FileServer(http.Dir(uploadsDir))))

	webFS, err := fs.Sub(embeddedWeb, "web/dist")
	if err != nil {
		log.Fatalf("embedded web assets: %v", err)
	}
	mux.Handle("/", staticHandler(webFS))

	addr := fmt.Sprintf(":%d", cfg.Server.Port)
	log.Printf("listening on %s", addr)
	if err := http.ListenAndServe(addr, mux); err != nil {
		log.Fatal(err)
	}
}

// staticHandler serves the prerendered SvelteKit build, where routes are
// written as flat files (e.g. "rsvp.html") rather than "rsvp/index.html".
func staticHandler(fsys fs.FS) http.Handler {
	fileServer := http.FileServer(http.FS(fsys))
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		p := strings.TrimPrefix(r.URL.Path, "/")
		if p == "" {
			p = "index.html"
		}
		if _, err := fs.Stat(fsys, p); err != nil {
			if _, err := fs.Stat(fsys, p+".html"); err == nil {
				r2 := *r
				r2.URL.Path = "/" + p + ".html"
				fileServer.ServeHTTP(w, &r2)
				return
			}
		}
		fileServer.ServeHTTP(w, r)
	})
}
