package main

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

//go:embed templates/*.tmpl account.css favicon.svg
var embedded embed.FS

var devMode bool
var basePath string

type PageData struct {
	Page      string
	Title     string
	Desc      string
	ActiveNav string
	Base      string
	Data      any
}

func main() {
	port := os.Getenv("PORT")
	if port == "" {
		port = "8098"
	}

	devMode = os.Getenv("DEV") == "1"
	basePath = strings.TrimRight(os.Getenv("BASE_PATH"), "/")

	dbPath := os.Getenv("DB_PATH")
	if dbPath == "" {
		dbPath = "account.db"
	}
	initDB(dbPath)

	mux := http.NewServeMux()

	// Pages
	mux.HandleFunc("/", handleIndex)
	mux.HandleFunc("/login", handleLogin)
	mux.HandleFunc("/verify", handleVerify)
	mux.HandleFunc("/dashboard", handleDashboard)
	mux.HandleFunc("/checkout", handleCheckout)
	mux.HandleFunc("/regions", handleRegions)
	mux.HandleFunc("/settings", handleSettings)

	// API
	mux.HandleFunc("/api/auth/email", apiAuthEmail)
	mux.HandleFunc("/api/auth/verify", apiAuthVerify)
	mux.HandleFunc("/api/auth/logout", apiAuthLogout)
	mux.HandleFunc("/api/checkout", apiCheckout)
	mux.HandleFunc("/api/vaults", apiVaults)
	mux.HandleFunc("/api/vault/create", apiVaultCreate)
	mux.HandleFunc("/api/vault/", apiVaultDelete) // /api/vault/{id}/delete
	mux.HandleFunc("/api/account", apiAccount)

	// Static assets
	mux.HandleFunc("/account.css", serveStatic("account.css", "text/css"))
	mux.HandleFunc("/favicon.svg", serveStatic("favicon.svg", "image/svg+xml"))

	// Strip .html extensions
	handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if strings.HasSuffix(r.URL.Path, ".html") {
			http.Redirect(w, r, strings.TrimSuffix(r.URL.Path, ".html"), http.StatusMovedPermanently)
			return
		}
		mux.ServeHTTP(w, r)
	})

	log.Printf("vault1984 account · :%s", port)
	if devMode {
		log.Println("  dev mode: templates reload from disk")
	}
	log.Fatal(http.ListenAndServe(":"+port, handler))
}

func loadTemplates(page string) (*template.Template, error) {
	if devMode {
		base := filepath.Join("templates", "base.tmpl")
		pg := filepath.Join("templates", page+".tmpl")
		return template.ParseFiles(base, pg)
	}
	return template.ParseFS(embedded, "templates/base.tmpl", "templates/"+page+".tmpl")
}

func render(w http.ResponseWriter, page string, data PageData) {
	data.Base = basePath
	tmpl, err := loadTemplates(page)
	if err != nil {
		log.Printf("template error: %v", err)
		http.Error(w, "internal error", 500)
		return
	}
	w.Header().Set("Content-Type", "text/html; charset=utf-8")
	if err := tmpl.Execute(w, data); err != nil {
		log.Printf("render error: %v", err)
	}
}

func serveStatic(name, contentType string) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		var data []byte
		var err error
		if devMode {
			data, err = os.ReadFile(name)
		} else {
			data, err = fs.ReadFile(embedded, name)
		}
		if err != nil {
			http.NotFound(w, r)
			return
		}
		w.Header().Set("Content-Type", contentType)
		w.Header().Set("Cache-Control", "public, max-age=3600")
		w.Write(data)
	}
}

func handleIndex(w http.ResponseWriter, r *http.Request) {
	if r.URL.Path != "/" {
		http.NotFound(w, r)
		return
	}
	http.Redirect(w, r, basePath+"/login", http.StatusTemporaryRedirect)
}

func handleLogin(w http.ResponseWriter, r *http.Request) {
	// Already logged in? Go to dashboard
	if authEmail(r) != "" {
		http.Redirect(w, r, basePath+"/dashboard", http.StatusTemporaryRedirect)
		return
	}
	render(w, "login", PageData{
		Page:  "login",
		Title: "Sign in — vault1984",
		Desc:  "Sign in to your vault1984 account",
	})
}

func handleVerify(w http.ResponseWriter, r *http.Request) {
	render(w, "verify", PageData{
		Page:  "verify",
		Title: "Enter code — vault1984",
		Desc:  "Verify your login code",
		Data:  r.URL.Query().Get("email"),
	})
}

func handleDashboard(w http.ResponseWriter, r *http.Request) {
	if authEmail(r) == "" {
		http.Redirect(w, r, basePath+"/login", http.StatusTemporaryRedirect)
		return
	}
	render(w, "dashboard", PageData{
		Page:      "dashboard",
		Title:     "Dashboard — vault1984",
		Desc:      "Manage your vaults",
		ActiveNav: "dashboard",
	})
}

func handleCheckout(w http.ResponseWriter, r *http.Request) {
	render(w, "checkout", PageData{
		Page:  "checkout",
		Title: "Get started — vault1984",
		Desc:  "Create your vault1984 account",
	})
}

func handleRegions(w http.ResponseWriter, r *http.Request) {
	if authEmail(r) == "" {
		http.Redirect(w, r, basePath+"/login", http.StatusTemporaryRedirect)
		return
	}
	render(w, "regions", PageData{
		Page:      "regions",
		Title:     "Choose your region — vault1984",
		Desc:      "Pick where your vault lives",
		ActiveNav: "dashboard",
	})
}

func handleSettings(w http.ResponseWriter, r *http.Request) {
	if authEmail(r) == "" {
		http.Redirect(w, r, basePath+"/login", http.StatusTemporaryRedirect)
		return
	}
	render(w, "settings", PageData{
		Page:      "settings",
		Title:     "Settings — vault1984",
		Desc:      "Account settings",
		ActiveNav: "settings",
	})
}
