package client

import (
	"context"
	"errors"
	"time"

	"coopcloud.tech/abra/pkg/i18n"
	"coopcloud.tech/abra/pkg/log"
	"github.com/docker/docker/api/types/filters"
	"github.com/docker/docker/api/types/volume"
	"github.com/docker/docker/client"
)

func GetVolumes(cl *client.Client, ctx context.Context, server string, fs filters.Args) ([]*volume.Volume, error) {
	volumeListOKBody, err := cl.VolumeList(ctx, volume.ListOptions{Filters: fs})
	volumeList := volumeListOKBody.Volumes
	if err != nil {
		return volumeList, err
	}

	return volumeList, nil
}

func GetVolumeNames(volumes []*volume.Volume) []string {
	var volumeNames []string

	for _, vol := range volumes {
		volumeNames = append(volumeNames, vol.Name)
	}

	return volumeNames
}

func RemoveVolumes(cl *client.Client, ctx context.Context, volumeNames []string, force bool, retries int) error {
	for _, volName := range volumeNames {
		err := retryFunc(5, func() error {
			return cl.VolumeRemove(context.Background(), volName, force)
		})
		if err != nil {
			return errors.New(i18n.G("volume %s: %s", volName, err))
		}
	}
	return nil
}

// retryFunc retries the given function for the given retries. After the nth
// retry it waits (n + 1)^2 seconds before the next retry (starting with n=0).
// It returns an error if the function still failed after the last retry.
func retryFunc(retries int, fn func() error) error {
	for i := 0; i < retries; i++ {
		err := fn()
		if err == nil {
			return nil
		}
		if i+1 < retries {
			sleep := time.Duration(i+1) * time.Duration(i+1)
			log.Info(i18n.G("%s: waiting %d seconds before next retry", err, sleep))
			time.Sleep(sleep * time.Second)
		}
	}
	return errors.New(i18n.G("%d retries failed", retries))
}
