// Input checks
package ic

import (
	"context"
	"fmt"

	account "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/account"
	"repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/bservice"
	"repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/compute"
	"repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/disks"
	"repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/dpdknet"
	extnet "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/extnet"
	image "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/image"
	k8ci "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/k8ci"
	k8s "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/k8s"
	lb "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/lb"
	location "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/locations"
	rg "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/rg"
	stack "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/stack"
	"repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/vfpool"
	vins "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/vins"
	"repository.basistech.ru/BASIS/terraform-provider-dynamix/internal/client"
)

func ExistRG(ctx context.Context, rgId uint64, c *client.Client) error {
	req := rg.ListRequest{
		ByID:           rgId,
		IncludeDeleted: false,
	}

	rgList, err := c.CloudAPI().RG().List(ctx, req)
	if err != nil {
		return err
	}

	if len(rgList.Data) == 0 {
		return fmt.Errorf("RG with id %v not found", rgId)
	}

	return nil
}

func ExistImage(ctx context.Context, imageId uint64, c *client.Client) error {
	req := image.ListRequest{
		ByID: imageId,
	}

	listImages, err := c.CloudAPI().Image().List(ctx, req)
	if err != nil {
		return err
	}

	if len(listImages.Data) == 0 {
		return fmt.Errorf("image with id %v not found", imageId)
	}

	return nil
}

func ExistVins(ctx context.Context, vinsId uint64, c *client.Client) error {
	req := vins.ListRequest{
		ByID:           vinsId,
		IncludeDeleted: false,
	}

	vinsList, err := c.CloudAPI().VINS().List(ctx, req)
	if err != nil {
		return err
	}

	if len(vinsList.Data) == 0 {
		return fmt.Errorf("vins with ID %v not found", vinsId)
	}

	return nil
}

func ExistVinses(ctx context.Context, vinsIds []uint64, c *client.Client) []error {
	var errs []error

	req := vins.ListRequest{
		IncludeDeleted: false,
	}

	vinsList, err := c.CloudAPI().VINS().List(ctx, req)
	if err != nil {
		errs = append(errs, err)
		return errs
	}

	for _, vinsId := range vinsIds {
		found := false

		for _, vins := range vinsList.Data {
			if vinsId == vins.ID {
				found = true
				break
			}
		}

		if !found {
			errs = append(errs, fmt.Errorf("VINS with ID %v not found", vinsId))
		}
	}

	return errs
}

func ExistExtNets(ctx context.Context, extNetIds []uint64, c *client.Client) []error {
	var errs []error

	req := extnet.ListRequest{}

	extNetList, err := c.CloudAPI().ExtNet().List(ctx, req)
	if err != nil {
		errs = append(errs, err)
		return errs
	}

	for _, extNetId := range extNetIds {
		found := false

		for _, extNet := range extNetList.Data {
			if extNetId == extNet.ID {
				found = true
				break
			}
		}

		if !found {
			errs = append(errs, fmt.Errorf("EXTNET with ID %v not found", extNetId))
		}
	}

	return errs
}

func ExistExtNetInLb(ctx context.Context, extNetId uint64, c *client.Client) error {
	if extNetId == 0 {
		return nil
	}
	req := extnet.ListRequest{
		ByID: extNetId,
	}

	extNetList, err := c.CloudAPI().ExtNet().List(ctx, req)
	if err != nil {
		return err
	}

	if len(extNetList.Data) == 0 {
		return fmt.Errorf("EXTNET with ID %v not found", extNetId)
	}

	return nil
}

func ExistExtNetInRG(ctx context.Context, extNetId, accountId uint64, c *client.Client) error {
	req := extnet.ListRequest{
		AccountID: accountId,
		ByID:      extNetId,
	}

	listExtNet, err := c.CloudAPI().ExtNet().List(ctx, req)
	if err != nil {
		return err
	}

	if len(listExtNet.Data) == 0 {
		return fmt.Errorf("EXTNET with ID %v not found for account with id %d", extNetId, accountId)
	}

	return nil
}

func ExistExtNetInVins(ctx context.Context, extNetId int, c *client.Client) error {
	if extNetId == 0 || extNetId == -1 {
		return nil
	}
	req := extnet.ListRequest{
		ByID: uint64(extNetId),
	}

	extNetList, err := c.CloudAPI().ExtNet().List(ctx, req)
	if err != nil {
		return err
	}

	if len(extNetList.Data) == 0 {
		return fmt.Errorf("EXTNET with ID %v not found", extNetId)
	}

	return nil
}

func ExistExtNet(ctx context.Context, extNetId uint64, c *client.Client) error {

	req := extnet.ListRequest{
		ByID:   extNetId,
		Status: "Enabled",
	}

	extNetList, err := c.CloudAPI().ExtNet().List(ctx, req)
	if err != nil {
		return err
	}

	if len(extNetList.Data) == 0 {
		return fmt.Errorf("EXTNET with ID %v not found", extNetId)
	}

	return nil
}

func ExistVinsInLb(ctx context.Context, vinsId uint64, c *client.Client) error {
	if vinsId == 0 {
		return nil
	}

	req := vins.ListRequest{
		ByID: vinsId,
	}

	vinsList, err := c.CloudAPI().VINS().List(ctx, req)
	if err != nil {
		return err
	}

	if len(vinsList.Data) == 0 {
		return fmt.Errorf("VINS with ID %v not found", vinsId)
	}

	return nil
}

func ExistGID(ctx context.Context, gid uint64, c *client.Client) error {
	req := location.ListRequest{}

	gridList, err := c.CloudAPI().Locations().List(ctx, req)
	if err != nil {
		return err
	}

	for _, grid := range gridList.Data {
		if grid.GID == gid {
			return nil
		}
	}

	return fmt.Errorf("GID with id %v not found", gid)
}

func ExistStack(ctx context.Context, stackId uint64, c *client.Client) error {
	req := stack.ListRequest{
		ByID: stackId,
	}

	stackList, err := c.CloudAPI().Stack().List(ctx, req)
	if err != nil {
		return err
	}

	if len(stackList.Data) == 0 {
		return fmt.Errorf("stack with id %v not found", stackList)
	}

	return nil
}

// // ExistStackInPcidevice checks if compute exists with specified stackId and specified non-deleted rgId.
// func ExistStackInPcidevice(ctx context.Context, stackId, rgId uint64, c *client.Client) error {
// 	req := rg.ListRequest{
// 		ByID:           rgId,
// 		IncludeDeleted: false,
// 	}

// 	rgList, err := c.CloudAPI().RG().List(ctx, req)
// 	if err != nil {
// 		return err
// 	}

// 	for _, v := range rgList.Data {
// 		for _, idVM := range v.VMs {
// 			req := compute.GetRequest{
// 				ComputeID: idVM,
// 			}
// 			computeRec, err := c.CloudAPI().Compute().Get(ctx, req)
// 			if err != nil {
// 				return err
// 			}
// 			if computeRec.StackID == stackId {
// 				return nil
// 			}
// 		}
// 	}

// 	return fmt.Errorf("no compute found with stack_id %v and rg_id %v", stackId, rgId)
// }

func ExistLB(ctx context.Context, lbId uint64, c *client.Client) error {

	req := lb.ListRequest{
		ByID: lbId,
	}

	lbList, err := c.CloudAPI().LB().List(ctx, req)
	if err != nil {
		return err
	}

	if len(lbList.Data) == 0 {
		return fmt.Errorf("LB with ID %v not found", lbId)
	}

	return nil

}

func ExistDiskID(ctx context.Context, diskId uint64, c *client.Client) error {

	req := disks.ListRequest{
		ByID: diskId,
	}

	diskList, err := c.CloudAPI().Disks().List(ctx, req)
	if err != nil {
		return err
	}

	if len(diskList.Data) == 0 {
		return fmt.Errorf("resourceDiskReplication: can't create or update Disk replication because DiskID %d is not allowed or does not exist", diskId)
	}

	if diskList.Data[0].SepType != "TATLIN" {
		return fmt.Errorf("resourceDiskReplication: can't create or update Disk replication because DiskID %d is not TATLIN SEP Type", diskId)
	}

	return nil
}

func ExistAccount(ctx context.Context, accountId uint64, c *client.Client) error {
	req := account.ListRequest{
		ByID: accountId,
	}

	accountList, err := c.CloudAPI().Account().List(ctx, req)
	if err != nil {
		return err
	}

	if len(accountList.Data) == 0 {
		return fmt.Errorf("account with id %d not found", accountId)
	}

	return nil
}

func ExistK8CI(ctx context.Context, k8ciId uint64, c *client.Client) error {
	req := k8ci.ListRequest{
		ByID: k8ciId,
	}

	k8ciList, err := c.CloudAPI().K8CI().List(ctx, req)
	if err != nil {
		return err
	}

	if len(k8ciList.Data) == 0 {
		return fmt.Errorf("k8ci with id %d not found", k8ciId)
	}

	return nil
}

func ExistExtNetInK8s(ctx context.Context, extNetId uint64, c *client.Client) error {
	if extNetId == 0 {
		return nil
	}
	req := extnet.ListRequest{
		ByID: extNetId,
	}

	extNetList, err := c.CloudAPI().ExtNet().List(ctx, req)
	if err != nil {
		return err
	}

	if len(extNetList.Data) == 0 {
		return fmt.Errorf("EXTNET with ID %v not found", extNetId)
	}

	return nil
}

func ExistVinsInK8s(ctx context.Context, vinsId uint64, c *client.Client) error {
	if vinsId == 0 {
		return nil
	}

	req := vins.ListRequest{
		ByID: vinsId,
	}

	vinsList, err := c.CloudAPI().VINS().List(ctx, req)
	if err != nil {
		return err
	}

	if len(vinsList.Data) == 0 {
		return fmt.Errorf("VINS with ID %v not found", vinsId)
	}

	return nil
}

func ExistK8s(ctx context.Context, k8sId uint64, c *client.Client) error {
	req := k8s.ListRequest{
		ByID: k8sId,
	}

	k8sList, err := c.CloudAPI().K8S().List(ctx, req)
	if err != nil {
		return err
	}

	if len(k8sList.Data) == 0 {
		return fmt.Errorf("k8s with id %d not found", k8sId)
	}

	return nil
}

func ExistVFPool(ctx context.Context, vfpoolId uint64, c *client.Client) error {

	req := vfpool.ListRequest{
		ByID:   vfpoolId,
		Status: "Enabled",
	}

	vfpoolList, err := c.CloudAPI().VFPool().List(ctx, req)
	if err != nil {
		return err
	}

	if len(vfpoolList.Data) == 0 {
		return fmt.Errorf("VFPOOL with ID %v not found", vfpoolId)
	}

	return nil
}

func ExistDPDK(ctx context.Context, dpdkId uint64, c *client.Client) error {

	req := dpdknet.ListRequest{
		ByID: dpdkId,
	}

	dpdkList, err := c.CloudAPI().DPDKNet().List(ctx, req)
	if err != nil {
		return err
	}

	if len(dpdkList.Data) == 0 {
		return fmt.Errorf("DPDK net with ID %v not found", dpdkId)
	}

	for _, item := range dpdkList.Data {
		if item.Status != "ENABLED" {
			return fmt.Errorf("DPDK net with ID %v must be enabled", dpdkId)
		}
	}

	return nil
}

func ExistSnapshotInCompute(ctx context.Context, computeID uint64, label string, c *client.Client) error {
	req := compute.SnapshotListRequest{
		ComputeID: computeID,
	}

	snapShotList, err := c.CloudAPI().Compute().SnapshotList(ctx, req)
	if err != nil {
		return err
	}

	for _, snapShot := range snapShotList.Data {
		if label == snapShot.Label {
			return nil
		}
	}

	return fmt.Errorf("snapshot with label %v for compute with id %d not found", label, computeID)
}

func ExistLBBackend(ctx context.Context, lbId uint64, bName string, c *client.Client) error {
	lb, err := c.CloudAPI().LB().Get(ctx, lb.GetRequest{LBID: lbId})
	if err != nil {
		return err
	}

	backends := lb.Backends
	for _, b := range backends {
		if b.Name == bName {
			return nil
		}
	}

	return fmt.Errorf("backend with name %v not found", bName)
}

func ExistLBFrontend(ctx context.Context, lbId uint64, fName string, c *client.Client) error {
	lb, err := c.CloudAPI().LB().Get(ctx, lb.GetRequest{LBID: lbId})
	if err != nil {
		return err
	}

	frontends := lb.Frontends
	for _, f := range frontends {
		if f.Name == fName {
			return nil
		}
	}

	return fmt.Errorf("frontend with name %v not found", fName)
}

func ExistBservise(ctx context.Context, serviceID uint64, c *client.Client) error {
	req := bservice.ListRequest{
		ByID: serviceID,
	}

	rgList, err := c.CloudAPI().BService().List(ctx, req)
	if err != nil {
		return err
	}

	if len(rgList.Data) == 0 {
		return fmt.Errorf("Bservice with id %v not found", serviceID)
	}

	for _, v := range rgList.Data {
		if v.Status != "ENABLED" {
			return fmt.Errorf("Bservice with id %v should be enabled", serviceID)
		}
	}

	return nil
}

func ExistBserviseGroup(ctx context.Context, serviseID uint64, compGroupID uint64, c *client.Client) error {
	req := bservice.GroupGetRequest{
		ServiceID:   serviseID,
		CompGroupID: compGroupID,
	}

	_, err := c.CloudAPI().BService().GroupGet(ctx, req)
	if err != nil {
		return err
	}

	return nil
}
