// Command swagger-gen regenerates the three drive9 OpenAPI documents under
// docs/api/ from the endpoint registry in pkg/server.
//
// Usage:
//
//	go run ./cmd/swagger-gen            # write docs/api/*.openapi.json
//	go run ./cmd/swagger-gen --check    # exit non-zero if docs are stale
package main

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

	"github.com/mem9-ai/drive9/pkg/openapi"
	"github.com/mem9-ai/drive9/pkg/server"
)

var outputFiles = map[openapi.DocKind]string{
	openapi.ControlPlaneAKSK: "control-plane-aksk.openapi.json",
	openapi.ControlPlaneJWT:  "control-plane-jwt.openapi.json",
	openapi.DataPlane:        "data-plane.openapi.json",
}

func main() {
	checkOnly := flag.Bool("check", false, "verify generated files are up to date and exit non-zero otherwise")
	serverURL := flag.String("server", "", "base URL advertised in the documents' servers block")
	flag.Parse()

	docs, err := server.OpenAPIDocuments(*serverURL)
	if err != nil {
		fmt.Fprintf(os.Stderr, "swagger-gen: %v\n", err)
		os.Exit(1)
	}

	dir := "docs/api"
	if flag.NArg() > 0 {
		dir = flag.Arg(0)
	}

	stale := false
	for kind, name := range outputFiles {
		path := filepath.Join(dir, name)
		content, ok := docs[kind]
		if !ok {
			fmt.Fprintf(os.Stderr, "swagger-gen: missing document %s\n", kind)
			os.Exit(1)
		}
		content = append(bytes.TrimRight(content, "\n"), '\n')
		if *checkOnly {
			existing, err := os.ReadFile(path)
			if err != nil {
				fmt.Fprintf(os.Stderr, "swagger-gen: %s: %v (run `go run ./cmd/swagger-gen` to regenerate)\n", path, err)
				stale = true
				continue
			}
			if !bytes.Equal(existing, content) {
				fmt.Fprintf(os.Stderr, "swagger-gen: %s is stale (run `go run ./cmd/swagger-gen` to regenerate)\n", path)
				stale = true
			}
			continue
		}
		if err := os.WriteFile(path, content, 0o644); err != nil {
			fmt.Fprintf(os.Stderr, "swagger-gen: write %s: %v\n", path, err)
			os.Exit(1)
		}
		fmt.Printf("wrote %s (%d endpoints)\n", path, countEndpoints(content))
	}

	if stale {
		os.Exit(1)
	}
}

// countEndpoints counts "operationId" occurrences as a rough endpoint count
// for the write log.
func countEndpoints(content []byte) int {
	count := 0
	for _, line := range bytes.Split(content, []byte("\n")) {
		if bytes.Contains(line, []byte(`"operationId"`)) {
			count++
		}
	}
	return count
}
