package main

import (
	"fmt"
	"os"
	"path/filepath"

	"github.com/evanw/esbuild/pkg/api"
)

func main() {
	// Determine repo root.
	// When invoked via `go generate` from web/, cwd is web/ so we look for go.mod
	// to find the actual module root.
	root, err := findModuleRoot()
	if err != nil {
		panic(err)
	}

	// Verify vendor files exist
	vendorFiles := []string{
		filepath.Join(root, "web", "vendor", "preact.mjs"),
		filepath.Join(root, "web", "vendor", "preact-hooks.mjs"),
		filepath.Join(root, "web", "vendor", "uplot.esm.js"),
		filepath.Join(root, "web", "vendor", "uplot.css"),
		filepath.Join(root, "web", "vendor", "echarts.esm.js"),
	}
	for _, f := range vendorFiles {
		if _, err := os.Stat(f); os.IsNotExist(err) {
			fmt.Fprintf(os.Stderr, "error: vendor file missing: %s\n", f)
			fmt.Fprintf(os.Stderr, "Run the following to download vendor files:\n")
			fmt.Fprintf(os.Stderr, "  mkdir -p web/vendor\n")
			fmt.Fprintf(os.Stderr, "  curl -sL https://cdn.jsdelivr.net/npm/preact@10.24.3/dist/preact.module.js -o web/vendor/preact.mjs\n")
			fmt.Fprintf(os.Stderr, "  curl -sL https://cdn.jsdelivr.net/npm/preact@10.24.3/hooks/dist/hooks.module.js -o web/vendor/preact-hooks.mjs\n")
			fmt.Fprintf(os.Stderr, "  curl -sL https://cdn.jsdelivr.net/npm/uplot@1.6.32/dist/uPlot.esm.js -o web/vendor/uplot.esm.js\n")
			fmt.Fprintf(os.Stderr, "  curl -sL https://cdn.jsdelivr.net/npm/uplot@1.6.32/dist/uPlot.min.css -o web/vendor/uplot.css\n")
			fmt.Fprintf(os.Stderr, "  curl -sL https://cdn.jsdelivr.net/npm/echarts@5.5.1/dist/echarts.esm.min.js -o web/vendor/echarts.esm.js\n")
			os.Exit(1)
		}
	}

	// Clean + create dist
	distDir := filepath.Join(root, "web", "dist")
	os.RemoveAll(distDir)
	os.MkdirAll(distDir, 0o755)

	result := api.Build(api.BuildOptions{
		EntryPoints:       []string{filepath.Join(root, "web", "src", "main.tsx")},
		Bundle:            true,
		Outdir:            distDir,
		Format:            api.FormatESModule,
		Target:            api.ES2020,
		JSX:               api.JSXTransform,
		JSXFactory:        "h",
		JSXFragment:       "Fragment",
		MinifyWhitespace:  true,
		MinifyIdentifiers: true,
		MinifySyntax:      true,
		Alias: map[string]string{
			"preact":       filepath.Join(root, "web", "vendor", "preact.mjs"),
			"preact/hooks": filepath.Join(root, "web", "vendor", "preact-hooks.mjs"),
			"uplot":        filepath.Join(root, "web", "vendor", "uplot.esm.js"),
			"echarts":      filepath.Join(root, "web", "vendor", "echarts.esm.js"),
		},
		Loader: map[string]api.Loader{
			".css": api.LoaderCSS,
		},
		Splitting: false,
		Write:     true,
		LogLevel:  api.LogLevelInfo,
	})

	if len(result.Errors) > 0 {
		for _, e := range result.Errors {
			fmt.Fprintf(os.Stderr, "error: %s\n", e.Text)
		}
		os.Exit(1)
	}

	// Copy uPlot CSS and favicon
	copyFile(filepath.Join(root, "web", "vendor", "uplot.css"), filepath.Join(distDir, "uplot.css"))
	copyFile(filepath.Join(root, "web", "public", "favicon.svg"), filepath.Join(distDir, "favicon.svg"))
	copyFile(filepath.Join(root, "web", "public", "favicon.svg"), filepath.Join(distDir, "favicon.ico"))

	// Write index.html
	html := `<!doctype html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>uopi</title>
  <link rel="icon" href="/favicon.ico" sizes="any" />
  <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
  <link rel="stylesheet" href="/uplot.css" />
  <link rel="stylesheet" href="/main.css" />
</head>
<body>
  <div id="app"></div>
  <script type="module" src="/main.js"></script>
</body>
</html>`
	os.WriteFile(filepath.Join(distDir, "index.html"), []byte(html), 0o644)

	fmt.Println("Frontend built successfully →", distDir)
}

func copyFile(src, dst string) {
	data, err := os.ReadFile(src)
	if err != nil {
		return // Skip if missing
	}
	os.WriteFile(dst, data, 0o644)
}

// findModuleRoot walks up from cwd until it finds a go.mod file.
func findModuleRoot() (string, error) {
	dir, err := os.Getwd()
	if err != nil {
		return "", err
	}
	for {
		if _, err := os.Stat(filepath.Join(dir, "go.mod")); err == nil {
			return dir, nil
		}
		parent := filepath.Dir(dir)
		if parent == dir {
			return "", fmt.Errorf("go.mod not found in any parent directory")
		}
		dir = parent
	}
}
