package apply

import (
	"context"
	"fmt"

	"edge-infra.dev/pkg/f8n/warehouse/cluster"
	"edge-infra.dev/pkg/f8n/warehouse/lift"
	"edge-infra.dev/pkg/f8n/warehouse/lift/cmd/internal"
	"edge-infra.dev/pkg/f8n/warehouse/lift/render"
	"edge-infra.dev/pkg/f8n/warehouse/pallet"
	"edge-infra.dev/pkg/lib/cli/sink"
)

// TODO: dry-run

func New(cfg lift.Config) *sink.Command {
	var (
		packer   = internal.NewPacker(cfg)
		unpacker = internal.NewUnpacker(cfg.Parameters)
		applier  = internal.NewApplier()
	)

	cmd := &sink.Command{
		Use:        "apply [flags] <pallets>",
		Short:      "schedule Warehouse packages to a cluster",
		Extensions: []sink.Extension{packer, unpacker, applier},
		Exec: func(ctx context.Context, r sink.Run) error {
			if len(r.Args()) == 0 {
				return fmt.Errorf("at least one pallet is required")
			}
			applier.Info(r)
			unpacker.Info(r)

			for _, a := range r.Args() {
				artifact, err := internal.ResolveArtifact(packer, a)
				if err != nil {
					return err
				}
				p, err := pallet.New(artifact)
				if err != nil {
					return err
				}
				parameters := p.Parameters()
				_, err = render.HandleParams(parameters, unpacker.RenderingParams)
				if err != nil {
					return err
				}

				err = applier.Apply(ctx, artifact, unpacker.Options()...)
				if err == cluster.ErrNoProviders {
					return fmt.Errorf("failed to apply %s: %w, pass via --cluster-provider or CLUSTER_PROVIDER environment variable", a, err)
				}
				if err != nil {
					return fmt.Errorf("failed to apply %s: %w", a, err)
				}
			}

			return nil
		},
	}
	return cmd
}