package cmd

import (
	"context"
	"fmt"
	"strings"
	"time"

	ntypes "github.com/rancher/norman/types"
	"github.com/sirupsen/logrus"
	"github.com/urfave/cli/v3"
)

var (
	waitTypes = []string{"cluster", "project"}
)

func WaitCommand() *cli.Command {
	return &cli.Command{
		Name:      "wait",
		Usage:     "Wait for resources " + strings.Join(waitTypes, ", "),
		ArgsUsage: "[ID/NAME]",
		Action:    defaultAction(wait),
		Flags: []cli.Flag{
			&cli.IntFlag{
				Name:  "timeout",
				Usage: "Time in seconds to wait for a resource",
				Value: 120,
			},
		},
	}
}

func wait(ctx context.Context, cmd *cli.Command) error {
	if cmd.NArg() == 0 {
		return cli.ShowCommandHelp(ctx, cmd, "wait")
	}

	c, err := GetClient(cmd)
	if err != nil {
		return err
	}

	resource, err := Lookup(c, cmd.Args().First(), waitTypes...)
	if err != nil {
		return err
	}

	mapResource := map[string]interface{}{}

	// Initial check shortcut
	err = c.ByID(resource, &mapResource)
	if err != nil {
		return err
	}

	ok, err := checkDone(resource, mapResource)
	if err != nil {
		return err
	}
	if ok {
		return nil
	}

	timeout := time.After(time.Duration(cmd.Int("timeout")) * time.Second)
	ticker := time.NewTicker(time.Second)

	for {
		select {
		case <-timeout:
			return fmt.Errorf("timeout reached %v:%v transitioningMessage: %v", resource.Type, resource.ID, mapResource["transitioningMessage"])
		case <-ticker.C:
			err = c.ByID(resource, &mapResource)
			if err != nil {
				return err
			}

			ok, err := checkDone(resource, mapResource)
			if err != nil {
				return err
			}
			if ok {
				return nil
			}
		}
	}
}

func checkDone(resource *ntypes.Resource, data map[string]interface{}) (bool, error) {
	transitioning := fmt.Sprint(data["transitioning"])
	logrus.Debugf("%s:%s transitioning=%s state=%v", resource.Type, resource.ID, transitioning,
		data["state"])

	switch transitioning {
	case "yes":
		return false, nil
	case "error":
		if data["state"] == "provisioning" {
			break
		}
		return false, fmt.Errorf("%v:%v failed, transitioningMessage: %v", resource.Type, resource.ID, data["transitioningMessage"])
	}

	return data["state"] == "active", nil
}
