package modify

import (
	"context"
	"fmt"

	"edge-infra.dev/pkg/edge/api/graph/model"
	"edge-infra.dev/pkg/edge/edgecli"
	"edge-infra.dev/pkg/edge/edgecli/constructors"
	"edge-infra.dev/pkg/edge/edgecli/flagutil"
	"edge-infra.dev/pkg/lib/cli/command"
	"edge-infra.dev/pkg/lib/cli/rags"
)

func NewCmd(cfg *edgecli.Config) *command.Command {
	var cmd *command.Command
	flagsets := flagutil.GetConnectionFlags(cfg)

	cmd = &command.Command{
		ShortUsage: "edge terminal modify",
		ShortHelp:  "Modify a Terminal belonging to a Cluster",
		Flags: append(
			flagsets,
			&rags.Rag{
				Name:     flagutil.StoreFlag,
				Value:    &rags.String{},
				Usage:    "Name of the Store - Must be unique",
				Required: true,
			},
			&rags.Rag{
				Name:     flagutil.BannerFlag,
				Value:    &rags.String{},
				Usage:    "Banner name",
				Required: true,
			},
			// A terminal is comprised of some atomic data fields, and a list of
			// network interfaces. Simple to support all atomic fields. But to modify an
			// interface, need to be able to say _which_ to modify.
			&rags.Rag{
				Name:     flagutil.TerminalID,
				Value:    &rags.String{},
				Usage:    "ID of Terminal",
				Required: true,
			},
			// Atomic data fields. All flags optional, so only have to specify the ones you want
			// to change
			&rags.Rag{
				Name:     flagutil.LaneFlag,
				Usage:    "Lane number",
				Value:    &rags.String{},
				Required: false,
			},
			&rags.Rag{
				Name:     flagutil.RoleFlag,
				Usage:    "Role of the Terminal, e.g. worker",
				Value:    &rags.String{},
				Required: false,
			},
			&rags.Rag{
				Name:     flagutil.ClassFlag,
				Usage:    "Class of the Terminal: 'server' or 'touchpoint'",
				Value:    &rags.String{},
				Required: false,
			},
			&rags.Rag{
				Name:     flagutil.DiscoverDisksFlag,
				Usage:    "Disk discovery option",
				Value:    &rags.String{},
				Required: false,
			},
			&rags.Rag{
				Name:     flagutil.BootDiskFlag,
				Usage:    "Boot disk option",
				Value:    &rags.String{},
				Required: false,
			},
			&rags.Rag{
				Name:     flagutil.PrimaryInterfaceFlag,
				Usage:    "UUID of existing interface on terminal",
				Value:    &rags.String{},
				Required: false,
			},
			&rags.Rag{
				Name:     flagutil.ExistingEfiFlag,
				Usage:    "Disk path of existing EFI partition on terminal",
				Value:    &rags.String{},
				Required: false,
			},
		),
		Exec: func(_ context.Context, _ []string) error {
			if err := flagutil.ValidateRequiredFlags(cmd.Rags); err != nil {
				return err
			}

			registrar, err := constructors.BuildRegistrar(cmd.Rags)
			if err != nil {
				return err
			}

			terminalID := flagutil.GetStringFlag(cmd.Rags, flagutil.TerminalID)

			role := flagutil.GetOptionalFlagValue[string](cmd.Rags, flagutil.RoleFlag)
			class := flagutil.GetOptionalFlagValue[string](cmd.Rags, flagutil.ClassFlag)
			discoverDisks := flagutil.GetOptionalFlagValue[string](cmd.Rags, flagutil.DiscoverDisksFlag)
			updatedTerminal := model.TerminalUpdateInput{
				Lane:             flagutil.GetOptionalFlagValue[string](cmd.Rags, flagutil.LaneFlag),
				Role:             (*model.TerminalRoleType)(role),
				Class:            (*model.TerminalClassType)(class),
				DiscoverDisks:    (*model.TerminalDiscoverDisksType)(discoverDisks),
				BootDisk:         flagutil.GetOptionalFlagValue[string](cmd.Rags, flagutil.BootDiskFlag),
				ExistingEfiPart:  flagutil.GetOptionalFlagValue[string](cmd.Rags, flagutil.ExistingEfiFlag),
				PrimaryInterface: flagutil.GetOptionalFlagValue[string](cmd.Rags, flagutil.PrimaryInterfaceFlag),
			}

			reqCtx, cancelReq := context.WithTimeout(context.Background(), flagutil.BffReqTimeout)
			defer cancelReq()

			if _, err := registrar.ModifyTerminal(reqCtx, terminalID, &updatedTerminal); err != nil {
				fmt.Println("an error occurred whilst modifying the terminal")
				return err
			}

			fmt.Println("Terminal modified successfully!")

			return nil
		},
	}
	return cmd
}