package server

import (
	"context"

	"coopcloud.tech/abra/cli/internal"
	"coopcloud.tech/abra/pkg/autocomplete"
	"coopcloud.tech/abra/pkg/client"
	"coopcloud.tech/abra/pkg/formatter"
	"coopcloud.tech/abra/pkg/log"
	"github.com/docker/docker/api/types/filters"
	"github.com/urfave/cli/v3"
)

var allFilter bool

var allFilterFlag = &cli.BoolFlag{
	Name:        "all",
	Aliases:     []string{"a"},
	Usage:       "Remove all unused images not just dangling ones",
	Destination: &allFilter,
}

var volumesFilter bool

var volumesFilterFlag = &cli.BoolFlag{
	Name:        "volumes",
	Aliases:     []string{"v"},
	Usage:       "Prune volumes. This will remove app data, Be Careful!",
	Destination: &volumesFilter,
}

var serverPruneCommand = cli.Command{
	Name:      "prune",
	Aliases:   []string{"p"},
	Usage:     "Prune resources on a server",
	UsageText: "abra server prune <server> [options]",
	Description: `Prunes unused containers, networks, and dangling images.

Use "-v/--volumes" to remove volumes that are not associated with a deployed
app. This can result in unwanted data loss if not used carefully.`,
	Flags: []cli.Flag{
		allFilterFlag,
		volumesFilterFlag,
	},
	Before:        internal.SubCommandBefore,
	ShellComplete: autocomplete.ServerNameComplete,
	HideHelp:      true,
	Action: func(ctx context.Context, cmd *cli.Command) error {
		serverName := internal.ValidateServer(cmd)

		cl, err := client.New(serverName)
		if err != nil {
			log.Fatal(err)
		}

		var args filters.Args

		cr, err := cl.ContainersPrune(ctx, args)
		if err != nil {
			log.Fatal(err)
		}

		cntSpaceReclaimed := formatter.ByteCountSI(cr.SpaceReclaimed)
		log.Infof("containers pruned: %d; space reclaimed: %s", len(cr.ContainersDeleted), cntSpaceReclaimed)

		nr, err := cl.NetworksPrune(ctx, args)
		if err != nil {
			log.Fatal(err)
		}

		log.Infof("networks pruned: %d", len(nr.NetworksDeleted))

		pruneFilters := filters.NewArgs()
		if allFilter {
			log.Debugf("removing all images, not only dangling ones")
			pruneFilters.Add("dangling", "false")
		}

		ir, err := cl.ImagesPrune(ctx, pruneFilters)
		if err != nil {
			log.Fatal(err)
		}

		imgSpaceReclaimed := formatter.ByteCountSI(ir.SpaceReclaimed)
		log.Infof("images pruned: %d; space reclaimed: %s", len(ir.ImagesDeleted), imgSpaceReclaimed)

		if volumesFilter {
			vr, err := cl.VolumesPrune(ctx, args)
			if err != nil {
				log.Fatal(err)
			}

			volSpaceReclaimed := formatter.ByteCountSI(vr.SpaceReclaimed)
			log.Infof("volumes pruned: %d; space reclaimed: %s", len(vr.VolumesDeleted), volSpaceReclaimed)
		}

		return nil
	},
}
