package cmd

import (
	"errors"
	"io"

	"github.com/spf13/cobra"
	"github.com/tidbcloud/clinic-cli/internal/config"
)

type switchResponse struct {
	ActiveEnv     string `json:"active_env"`
	ActiveProfile string `json:"active_profile,omitempty"`
}

func switchCommandHandler(ctx *RuntimeContext, args []string, stdout io.Writer) error {
	command := newSwitchCommand(staticRuntime(ctx), stdout)
	if err := executeCobraCommand(command, args); err != nil {
		return normalizeFamilyCommandError(err, "switch")
	}
	return nil
}

func newSwitchCommand(runtime runtimeResolver, stdout io.Writer) *cobra.Command {
	command := newCommand(commandMetadata{
		Use:   "switch <prod|staging|dev> [profile-name]",
		Short: "Switch active environment and optionally active profile in one command.",
		Long: `Switch active environment and optionally active profile in one command.

Arguments:
  <prod|staging|dev>  Environment to make active.
  <profile-name>      Optional profile in the target environment to make active.

Behavior:
  When profile is omitted, behavior matches "clinic env use <env>".
  When profile is provided, the command validates the profile exists in the target env
  before persisting any config changes.

Output:
  JSON with active_env and optional active_profile.`,
		Example: `  clinic switch staging
  clinic switch staging blue`,
	}, stdout)
	command.Args = cobra.RangeArgs(1, 2)
	command.RunE = func(_ *cobra.Command, args []string) error {
		ctx, err := runtime()
		if err != nil {
			return err
		}
		return runSwitch(ctx, args, stdout)
	}
	return command
}

func runSwitch(ctx *RuntimeContext, args []string, stdout io.Writer) error {
	if ctx == nil || ctx.Config == nil {
		return errors.New("switch config not loaded")
	}

	targetEnv := args[0]
	if _, err := ctx.Config.ResolveEnv(targetEnv); err != nil {
		return err
	}

	response := switchResponse{ActiveEnv: targetEnv}
	if len(args) == 2 {
		profileName := args[1]
		if _, _, err := loadProfileForEnv(ctx.Config, targetEnv, profileName); err != nil {
			return err
		}

		container := envProfileContainerForSwitch(ctx.Config, targetEnv)
		container.ActiveProfile = profileName
		saveEnvProfileContainer(ctx.Config, targetEnv, container)
		response.ActiveProfile = profileName
	}

	ctx.Config.ActiveEnv = targetEnv
	if err := ctx.Config.Save(); err != nil {
		return err
	}

	return writeJSON(stdout, response)
}

func envProfileContainerForSwitch(cfg *config.Config, env string) config.EnvProfileContainer {
	container, ok := cfg.EnvProfiles[env]
	if !ok {
		container = config.EnvProfileContainer{}
	}
	if container.Profiles == nil {
		container.Profiles = map[string]config.ProfileRecord{}
	}
	return container
}
