package cmd

import (
	"context"
	"fmt"
	"net/http"
	"os"
	"strings"

	"github.com/modelcontextprotocol/go-sdk/mcp"
	"github.com/spf13/cobra"
)

var (
	cfgFile    string
	serverFlag string
	tokenFlag  string
	outputFlag string
	verbose    bool
	cfg        Config
)

const cliUserAgent = "amcs-cli/0.0.1"

var rootCmd = &cobra.Command{
	Use:           "amcs-cli",
	Short:         "CLI for connecting to a remote AMCS MCP server",
	SilenceUsage:  true,
	SilenceErrors: true,
	PersistentPreRunE: func(cmd *cobra.Command, _ []string) error {
		return loadConfig()
	},
}

func Execute() {
	if err := rootCmd.Execute(); err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
}

func init() {
	rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "Path to config file")
	rootCmd.PersistentFlags().StringVar(&serverFlag, "server", "", "AMCS server URL")
	rootCmd.PersistentFlags().StringVar(&tokenFlag, "token", "", "AMCS bearer token")
	rootCmd.PersistentFlags().StringVar(&outputFlag, "output", "json", "Output format: json or yaml")
	rootCmd.PersistentFlags().BoolVar(&verbose, "verbose", false, "Enable verbose logging to stderr")
}

func loadConfig() error {
	path, err := resolveConfigPath(cfgFile)
	if err != nil {
		return err
	}
	loaded, err := loadConfigFile(path)
	if err != nil {
		return err
	}
	cfg = loaded
	if v := strings.TrimSpace(os.Getenv("AMCS_SERVER")); v != "" {
		cfg.Server = v
	}
	if v := strings.TrimSpace(os.Getenv("AMCS_URL")); v != "" {
		cfg.Server = v
	}
	if v := strings.TrimSpace(os.Getenv("AMCS_TOKEN")); v != "" {
		cfg.Token = v
	}
	if v := strings.TrimSpace(serverFlag); v != "" {
		cfg.Server = v
	}
	if v := strings.TrimSpace(tokenFlag); v != "" {
		cfg.Token = v
	}
	outputFlag = strings.ToLower(strings.TrimSpace(outputFlag))
	if outputFlag != "json" && outputFlag != "yaml" {
		return fmt.Errorf("invalid --output %q: must be json or yaml", outputFlag)
	}
	return nil
}

func requireServer() error {
	if strings.TrimSpace(cfg.Server) == "" {
		return fmt.Errorf("server URL is required; set --server, AMCS_SERVER, AMCS_URL, or config server")
	}
	return nil
}

func endpointURL() string {
	base := strings.TrimRight(strings.TrimSpace(cfg.Server), "/")
	if strings.HasSuffix(base, "/mcp") {
		return base
	}
	return base + "/mcp"
}

func newHTTPClient() *http.Client {
	return &http.Client{
		Timeout: 0,
		Transport: &bearerTransport{
			base:  http.DefaultTransport,
			token: cfg.Token,
		},
	}
}

type bearerTransport struct {
	base  http.RoundTripper
	token string
}

func (t *bearerTransport) RoundTrip(req *http.Request) (*http.Response, error) {
	base := t.base
	if base == nil {
		base = http.DefaultTransport
	}
	clone := req.Clone(req.Context())
	if strings.TrimSpace(clone.Header.Get("User-Agent")) == "" {
		clone.Header.Set("User-Agent", cliUserAgent)
	}
	if strings.TrimSpace(t.token) != "" {
		clone.Header.Set("Authorization", "Bearer "+t.token)
	}
	return base.RoundTrip(clone)
}

func connectRemote(ctx context.Context) (*mcp.ClientSession, error) {
	if err := requireServer(); err != nil {
		return nil, err
	}
	verboseLogf("connecting to %s", endpointURL())
	client := mcp.NewClient(&mcp.Implementation{Name: "amcs-cli", Version: "0.0.1"}, nil)
	transport := &mcp.StreamableClientTransport{
		Endpoint:             endpointURL(),
		HTTPClient:           newHTTPClient(),
		DisableStandaloneSSE: true,
	}
	session, err := client.Connect(ctx, transport, nil)
	if err != nil {
		return nil, fmt.Errorf("connect to AMCS server: %w", err)
	}
	verboseLogf("connected to %s", endpointURL())
	return session, nil
}

func verboseLogf(format string, args ...any) {
	if !verbose {
		return
	}
	_, _ = fmt.Fprintf(os.Stderr, "[amcs-cli] "+format+"\n", args...)
}
