// Package cli implements the ALT operator CLI dispatch. It is a thin command
// layer: argument parsing and exit-code/output contracts live here, while the
// scenario schema, validation, and run execution live in the operator package.
package cli

import (
	"context"
	"flag"
	"fmt"
	"io"

	"git.toki-labs.com/toki/alt/apps/cli/internal/operator"
)

// Exit codes form the CLI contract consumed by scripts and tests.
const (
	exitOK         = 0 // success
	exitUsage      = 1 // usage or unknown-command error
	exitParseError = 2 // scenario parse/validation/flag failure
)

// Run dispatches the operator CLI and returns a process exit code. stdout
// carries machine-readable status lines; stderr carries human-readable
// usage and error detail.
func Run(args []string, stdout, stderr io.Writer) int {
	if len(args) == 0 {
		usage(stderr)
		return exitUsage
	}

	switch args[0] {
	case "version":
		fmt.Fprintln(stdout, "alt dev")
		return exitOK
	case "operator":
		return runOperator(args[1:], stdout, stderr)
	default:
		fmt.Fprintf(stderr, "unknown command %q\n", args[0])
		usage(stderr)
		return exitUsage
	}
}

// runOperator routes the `operator scenario <validate|run>` subcommands.
func runOperator(args []string, stdout, stderr io.Writer) int {
	if len(args) < 1 || args[0] != "scenario" {
		usageOperator(stderr)
		return exitUsage
	}
	if len(args) < 2 {
		usageOperator(stderr)
		return exitUsage
	}

	switch args[1] {
	case "validate":
		return runScenarioValidate(args[2:], stdout, stderr)
	case "run":
		return runScenarioRun(args[2:], stdout, stderr)
	default:
		usageOperator(stderr)
		return exitUsage
	}
}

// runScenarioValidate handles `operator scenario validate --file <path>`.
func runScenarioValidate(args []string, stdout, stderr io.Writer) int {
	fs := flag.NewFlagSet("operator scenario validate", flag.ContinueOnError)
	fs.SetOutput(stderr)
	file := fs.String("file", "", "path to operator scenario YAML file")
	if err := fs.Parse(args); err != nil {
		return exitUsage
	}
	if *file == "" {
		fmt.Fprintln(stderr, "scenario file is required: --file <path>")
		return exitUsage
	}

	sc, err := operator.LoadScenario(*file)
	if err != nil {
		fmt.Fprintln(stdout, "scenario=unknown status=parse_error")
		fmt.Fprintf(stderr, "validate failed: %v\n", err)
		return exitParseError
	}

	fmt.Fprintf(stdout, "scenario=%s status=valid steps=%d\n", sc.Name, len(sc.Steps))
	return exitOK
}

// runScenarioRun handles `operator scenario run --file <path> --api-url <ws-url>`.
// It returns the runner's exit code (0 ok, 1 typed/expectation failure, 2
// parse/flag error, 3 transport failure).
func runScenarioRun(args []string, stdout, stderr io.Writer) int {
	fs := flag.NewFlagSet("operator scenario run", flag.ContinueOnError)
	fs.SetOutput(stderr)
	file := fs.String("file", "", "path to operator scenario YAML file")
	apiURL := fs.String("api-url", "", "API socket URL, e.g. ws://127.0.0.1:8080/socket")
	timeout := fs.Duration("timeout", 0, "per-step request timeout; overrides the scenario timeout")
	output := fs.String("output", string(operator.OutputText), "output format: text or jsonl")
	if err := fs.Parse(args); err != nil {
		return exitParseError
	}
	if *file == "" {
		fmt.Fprintln(stderr, "scenario file is required: --file <path>")
		return exitParseError
	}
	if *apiURL == "" {
		fmt.Fprintln(stderr, "api url is required: --api-url <ws-url>")
		return exitParseError
	}

	format := operator.OutputFormat(*output)
	if format != operator.OutputText && format != operator.OutputJSONL {
		fmt.Fprintf(stderr, "unknown output format %q (want text or jsonl)\n", *output)
		return exitParseError
	}

	sc, err := operator.LoadScenario(*file)
	if err != nil {
		fmt.Fprintln(stdout, "scenario=unknown status=parse_error")
		fmt.Fprintf(stderr, "run failed: %v\n", err)
		return exitParseError
	}

	return operator.RunScenario(context.Background(), sc, operator.RunOptions{
		APIURL:  *apiURL,
		Timeout: *timeout,
		Format:  format,
	}, stdout)
}

// usage prints the top-level command summary.
func usage(w io.Writer) {
	fmt.Fprintln(w, "usage: alt <command>")
	fmt.Fprintln(w, "commands:")
	fmt.Fprintln(w, "  version")
	fmt.Fprintln(w, "  operator scenario validate --file <path>")
	fmt.Fprintln(w, "  operator scenario run --file <path> --api-url <ws-url> [--timeout <dur>] [--output text|jsonl]")
}

// usageOperator prints the operator subcommand summary.
func usageOperator(w io.Writer) {
	fmt.Fprintln(w, "usage:")
	fmt.Fprintln(w, "  alt operator scenario validate --file <path>")
	fmt.Fprintln(w, "  alt operator scenario run --file <path> --api-url <ws-url> [--timeout <dur>] [--output text|jsonl]")
}
