package main

import (
	"context"
	"errors"
	"flag"
	"fmt"
	"os"
	"strings"
)

func main() {
	if err := run(); err != nil && !errors.Is(err, flag.ErrHelp) {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
}
func run() error {
	mode, args, done, err := helpCommand(os.Args[1:])
	if err != nil || done {
		return err
	}
	command := commands[mode]
	all := flag.NewFlagSet(mode, flag.ContinueOnError)
	dsn := all.String("db", databaseURL(os.Getenv("DATABASE_URL")), "dedicated assignment_harness_* connection string; overrides DATABASE_URL")
	url := all.String("url", "http://127.0.0.1:18000", "target HTTP URL")
	dir := all.String("golden", "../fixtures/contract", "reviewed reference captures")
	output := all.String("output", "results.json", "output file (directory for export-errors)")
	baseline := all.String("baseline", "", "baseline benchmark JSON")
	candidate := all.String("candidate", "", "candidate benchmark JSON")
	referenceDSN := all.String("reference-db", "", "reference database for full equivalence")
	referenceURL := all.String("reference-url", "http://127.0.0.1:18000", "reference HTTP URL")
	input := all.String("input", "", "input artifact path")
	n := all.Int("requests", 100, "requests per workload and repetition")
	concurrency := all.Int("concurrency", 1, "in-flight requests")
	repeats := all.Int("repeats", 5, "independent workload repetitions")
	pid := all.Int("pid", 0, "server master PID for Linux process-tree resource measurements")
	filter := all.String("workload", "", "posts, search, tag, detail, user, email, create, or comment (default: all)")
	full := all.Bool("full", false, "use full-scale fixture instead of contract fixture")
	f := flag.NewFlagSet(mode, flag.ContinueOnError)
	for _, name := range strings.Fields(command.flags) {
		option := all.Lookup(name)
		f.Var(option.Value, name, option.Usage)
		f.Lookup(name).DefValue = option.DefValue
	}
	// Never include the current connection string or credentials in help output.
	if option := f.Lookup("db"); option != nil {
		option.DefValue = databaseURL("")
	}
	f.Usage = func() { printCommandHelp(f.Output(), mode, command, f) }
	for _, arg := range args {
		if arg == "--help" || arg == "-h" {
			f.SetOutput(os.Stdout)
			f.Usage()
			return nil
		}
	}
	if err := f.Parse(args); err != nil {
		return err
	}
	if f.NArg() != 0 {
		return fmt.Errorf("unexpected argument %q; use harness %s --help", f.Arg(0), mode)
	}
	ctx := context.Background()
	switch mode {
	case "operations":
		return checkOperations(ctx, *dsn, *input, *output)
	case "plans":
		return queryPlans(ctx, *dsn, *output)
	case "waits":
		return diagnoseWaits(ctx, *dsn, *url, *output, *n, *concurrency)
	case "init-db":
		return initializeDatabase(ctx, *dsn)
	case "export-transcript":
		return exportTranscript(*input, *output)
	case "equivalence":
		return equivalence(ctx, *referenceDSN, *dsn, *referenceURL, *url, *output)
	case "compare":
		return compareFiles(*baseline, *candidate, *output, *filter)
	case "export-errors":
		return exportErrors(*dir, *output)
	case "seed":
		c, err := openDB(ctx, *dsn)
		if err != nil {
			return err
		}
		defer c.Close(ctx)
		return seed(ctx, c)
	case "bench":
		return benchmark(ctx, *dsn, *url, *output, *n, *concurrency, *repeats, *pid, *filter, *full)
	case "capture", "verify":
		return runContract(ctx, *dsn, *url, *dir, mode == "capture")
	case "claim", "fixture":
		c, err := openDB(ctx, *dsn)
		if err != nil {
			return err
		}
		defer c.Close(ctx)
		if mode == "claim" {
			return claim(ctx, c)
		}
		return fixture(ctx, c)
	}
	return fmt.Errorf("unknown command %q", mode)
}
