package flattens

import (
	"context"
	"encoding/json"
	"fmt"

	"github.com/google/uuid"
	"github.com/hashicorp/terraform-plugin-framework/diag"
	"github.com/hashicorp/terraform-plugin-framework/types"
	"github.com/hashicorp/terraform-plugin-log/tflog"
	"repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/compute"
	"repository.basistech.ru/BASIS/terraform-provider-dynamix/internal/client"
	"repository.basistech.ru/BASIS/terraform-provider-dynamix/internal/flattens"
	"repository.basistech.ru/BASIS/terraform-provider-dynamix/internal/service/cloudapi/kvmvm/models"
	"repository.basistech.ru/BASIS/terraform-provider-dynamix/internal/service/cloudapi/kvmvm/utilities"
)

func DataSourceComputeListDeleted(ctx context.Context, state *models.ListDeletedComputesModel, c *client.Client) diag.Diagnostics {
	tflog.Info(ctx, "Start FlattenDataSourceComputeListDeleted")

	diags := diag.Diagnostics{}

	listDeleted, err := utilities.ComputeListDeletedCheckPresence(ctx, state, c)
	if err != nil {
		diags.AddError("Error get compute list deleted info", err.Error())
		return diags
	}

	id := uuid.New()

	*state = models.ListDeletedComputesModel{
		ByID:       state.ByID,
		Name:       state.Name,
		AccountID:  state.AccountID,
		RGName:     state.RGName,
		RGID:       state.RGID,
		TechStatus: state.TechStatus,
		IPAddress:  state.IPAddress,
		ExtNetName: state.ExtNetName,
		ExtNetID:   state.ExtNetID,
		SortBy:     state.SortBy,
		Page:       state.Page,
		Size:       state.Size,
		IgnoreK8s:  state.IgnoreK8s,
		Timeouts:   state.Timeouts,
		Id:         types.StringValue(id.String()),
		Items:      flattenItemsListDeleted(ctx, listDeleted),
		EntryCount: types.Int64Value(int64(listDeleted.EntryCount)),
	}

	tflog.Info(ctx, "End FlattenDataSourceComputeListDeleted")
	return nil
}

func flattenItemsListDeleted(ctx context.Context, computes *compute.ListComputes) []models.ItemListDeletedComputeModel {
	tflog.Info(ctx, "Start flattenItemsListDeleted")

	var diags diag.Diagnostics

	res := make([]models.ItemListDeletedComputeModel, 0, len(computes.Data))
	for _, item := range computes.Data {
		customFields, _ := json.Marshal(item.CustomFields)
		devices, _ := json.Marshal(item.Devices)
		temp := models.ItemListDeletedComputeModel{
			ACL:                    flattenACLInListDeleted(ctx, &item.ACL),
			AccountID:              types.Int64Value(int64(item.AccountID)),
			AccountName:            types.StringValue(item.AccountName),
			AffinityLabel:          types.StringValue(item.AffinityLabel),
			AffinityRules:          flattenAffinityRuleInListDeleted(ctx, &item.AffinityRules),
			AffinityWeight:         types.Int64Value(int64(item.AffinityWeight)),
			AntiAffinityRules:      flattenAffinityRuleInListDeleted(ctx, &item.AntiAffinityRules),
			Architecture:           types.StringValue(item.Architecture),
			AutoStartWithNode:      types.BoolValue(item.AutoStart),
			BootDiskSize:           types.Int64Value(int64(item.BootDiskSize)),
			BootOrder:              flattens.FlattenSimpleTypeToList(ctx, types.StringType, &item.BootOrder),
			BootType:               types.StringValue(item.BootType),
			CdImageId:              types.Int64Value(int64(item.CdImageId)),
			Clones:                 flattens.FlattenSimpleTypeToList(ctx, types.Int64Type, &item.Clones),
			Chipset:                types.StringValue(item.Chipset),
			CloneReference:         types.Int64Value(int64(item.CloneReference)),
			ComputeCIID:            types.Int64Value(int64(item.ComputeCIID)),
			CPU:                    types.Int64Value(int64(item.CPU)),
			CPUPin:                 types.BoolValue(item.CPUPin),
			CreatedBy:              types.StringValue(item.CreatedBy),
			CreatedTime:            types.Int64Value(int64(item.CreatedTime)),
			CustomFields:           types.StringValue(string(customFields)),
			DeletedBy:              types.StringValue(item.DeletedBy),
			DeletedTime:            types.Int64Value(int64(item.DeletedTime)),
			Description:            types.StringValue(item.Description),
			Devices:                types.StringValue(string(devices)),
			Disks:                  flattenDisksInListDeleted(ctx, &item.Disks),
			Driver:                 types.StringValue(item.Driver),
			GID:                    types.Int64Value(int64(item.GID)),
			GUID:                   types.Int64Value(int64(item.GUID)),
			HPBacked:               types.BoolValue(item.HPBacked),
			HotResize:              types.BoolValue(item.HotResize),
			ComputeId:              types.Int64Value(int64(item.ID)),
			ImageID:                types.Int64Value(int64(item.ImageID)),
			Interfaces:             flattenInterfaceInListDeleted(ctx, &item.Interfaces),
			LockStatus:             types.StringValue(item.LockStatus),
			LoaderType:             types.StringValue(item.LoaderType),
			ManagerID:              types.Int64Value(int64(item.ManagerID)),
			ManagerType:            types.StringValue(item.ManagerType),
			MigrationJob:           types.Int64Value(int64(item.MigrationJob)),
			Milestones:             types.Int64Value(int64(item.Milestones)),
			Name:                   types.StringValue(item.Name),
			NeedReboot:             types.BoolValue(item.NeedReboot),
			NetworkInterfaceNaming: types.StringValue(item.NetworkInterfaceNaming),
			NumaAffinity:           types.StringValue(item.NumaAffinity),
			NumaNodeId:             types.Int64Value(int64(item.NumaNodeId)),
			//Pinned:            types.BoolValue(item.Pinned),
			PreferredCPU:     flattens.FlattenSimpleTypeToList(ctx, types.Int64Type, &item.PreferredCPU),
			RAM:              types.Int64Value(int64(item.RAM)),
			ReferenceID:      types.StringValue(item.ReferenceID),
			Registered:       types.BoolValue(item.Registered),
			ResName:          types.StringValue(item.ResName),
			ReservedNodeCpus: flattens.FlattenSimpleTypeToList(ctx, types.Int64Type, &item.ReservedNodeCpus),
			RGID:             types.Int64Value(int64(item.RGID)),
			RGName:           types.StringValue(item.RGName),
			SnapSets:         flattenSnapSetInListDeleted(ctx, &item.SnapSets),
			StatelessSepID:   types.Int64Value(int64(item.StatelessSepID)),
			StatelessSepType: types.StringValue(item.StatelessSepType),
			Status:           types.StringValue(item.Status),
			TechStatus:       types.StringValue(item.TechStatus),
			TotalDiskSize:    types.Int64Value(int64(item.TotalDiskSize)),
			UpdatedBy:        types.StringValue(item.UpdatedBy),
			UpdatedTime:      types.Int64Value(int64(item.UpdatedTime)),
			UserManaged:      types.BoolValue(item.UserManaged),
			VINSConnected:    types.Int64Value(int64(item.VINSConnected)),
			VirtualImageID:   types.Int64Value(int64(item.VirtualImageID)),
			VGPUs:            flattens.FlattenSimpleTypeToList(ctx, types.Int64Type, &item.VGPUs),
		}

		temp.Tags, diags = types.MapValueFrom(ctx, types.StringType, item.Tags)
		if diags != nil {
			tflog.Error(ctx, fmt.Sprint("Error flattenItemsListDeleted", diags))
		}
		res = append(res, temp)
	}

	tflog.Info(ctx, "End flattenItemsListDeleted")
	return res
}

func flattenACLInListDeleted(ctx context.Context, acl *compute.ListACL) []models.ItemACLInListDeletedModel {
	tflog.Info(ctx, "Start flattenACLInListDeleted")

	res := make([]models.ItemACLInListDeletedModel, 0, len(*acl))
	for _, item := range *acl {
		temp := models.ItemACLInListDeletedModel{
			Explicit:    types.BoolValue(bool(item.Explicit)),
			GUID:        types.StringValue(item.GUID),
			Right:       types.StringValue(item.Right),
			Status:      types.StringValue(item.Status),
			Type:        types.StringValue(item.Type),
			UserGroupID: types.StringValue(item.UserGroupID),
		}
		res = append(res, temp)
	}

	tflog.Info(ctx, "End flattenACLInListDeleted")
	return res
}

func flattenAffinityRuleInListDeleted(ctx context.Context, rules *compute.ListRules) []models.ItemRuleInListDeletedModel {
	tflog.Info(ctx, "Start flattenAffinityRuleInListDeleted")

	res := make([]models.ItemRuleInListDeletedModel, 0, len(*rules))
	for _, item := range *rules {
		temp := models.ItemRuleInListDeletedModel{
			GUID:     types.StringValue(item.GUID),
			Key:      types.StringValue(item.Key),
			Mode:     types.StringValue(item.Mode),
			Policy:   types.StringValue(item.Policy),
			Topology: types.StringValue(item.Topology),
			Value:    types.StringValue(item.Value),
		}
		res = append(res, temp)
	}

	tflog.Info(ctx, "End flattenAffinityRuleInListDeleted")
	return res
}

func flattenDisksInListDeleted(ctx context.Context, disks *compute.ListInfoDisks) []models.DiskInListDeletedModel {
	tflog.Info(ctx, "Start flattenDisksInListDeleted")

	res := make([]models.DiskInListDeletedModel, 0, len(*disks))
	for _, item := range *disks {
		temp := models.DiskInListDeletedModel{
			//BusNumber: types.Int64Value(int64(item.BusNumber)),
			DiskId: types.Int64Value(int64(item.ID)),
			//PCISlot:   types.Int64Value(item.PCISlot),
		}
		res = append(res, temp)
	}

	tflog.Info(ctx, "End flattenDisksInListDeleted")
	return res
}

func flattenInterfaceInListDeleted(ctx context.Context, interfaces *compute.ListInterfaces) []models.ItemVNFInterfaceInListDeletedModel {
	tflog.Info(ctx, "Start flattenInterfaceInListDeleted")

	var diags diag.Diagnostics

	res := make([]models.ItemVNFInterfaceInListDeletedModel, 0, len(*interfaces))
	for _, item := range *interfaces {
		temp := models.ItemVNFInterfaceInListDeletedModel{
			BusNumber:   types.Int64Value(int64(item.BusNumber)),
			ConnID:      types.Int64Value(int64(item.ConnID)),
			ConnType:    types.StringValue(item.ConnType),
			DefGW:       types.StringValue(item.DefGW),
			Enabled:     types.BoolValue(item.Enabled),
			FLIPGroupID: types.Int64Value(int64(item.FLIPGroupID)),
			GUID:        types.StringValue(item.GUID),
			IPAddress:   types.StringValue(item.IPAddress),
			LibvirtSettings: &models.LibvirtModel{
				GUID:        types.StringValue(item.LibvirtSettings.GUID),
				TXMode:      types.StringValue(item.LibvirtSettings.TXMode),
				IOEventFD:   types.StringValue(item.LibvirtSettings.IOEventFD),
				EventIDx:    types.StringValue(item.LibvirtSettings.EventIDx),
				Queues:      types.Int64Value(int64(item.LibvirtSettings.Queues)),
				RXQueueSize: types.Int64Value(int64(item.LibvirtSettings.RXQueueSize)),
				TXQueueSize: types.Int64Value(int64(item.LibvirtSettings.TXQueueSize)),
			},
			ListenSSH: types.BoolValue(item.ListenSSH),
			MAC:       types.StringValue(item.MAC),
			Name:      types.StringValue(item.Name),
			NetID:     types.Int64Value(int64(item.NetID)),
			NetMask:   types.Int64Value(int64(item.NetMask)),
			NetType:   types.StringValue(item.NetType),
			NodeID:    types.Int64Value(int64(item.NodeID)),
			PCISlot:   types.Int64Value(item.PCISlot),
			QOS: &models.QOSInListModel{
				ERate:   types.Int64Value(int64(item.QOS.ERate)),
				GUID:    types.StringValue(item.QOS.GUID),
				InBurst: types.Int64Value(int64(item.QOS.InBurst)),
				InRate:  types.Int64Value(int64(item.QOS.InRate)),
			},
			Target: types.StringValue(item.Target),
			Type:   types.StringValue(item.Type),
		}
		temp.VNFs, diags = types.ListValueFrom(ctx, types.Int64Type, item.VNFs)
		if diags != nil {
			tflog.Error(ctx, fmt.Sprint("Error flattenInterfaceInListDeleted", diags))
		}
		res = append(res, temp)
	}

	tflog.Info(ctx, "End flattenInterfaceInListDeleted")
	return res
}

func flattenSnapSetInListDeleted(ctx context.Context, snapSet *compute.ListSnapSets) []models.ItemSnapSetInListDeletedModel {
	tflog.Info(ctx, "Start flattenSnapSetInListDeleted")

	var diags diag.Diagnostics

	res := make([]models.ItemSnapSetInListDeletedModel, 0, len(*snapSet))
	for _, item := range *snapSet {
		temp := models.ItemSnapSetInListDeletedModel{
			GUID:      types.StringValue(item.GUID),
			Label:     types.StringValue(item.Label),
			Timestamp: types.Int64Value(int64(item.Timestamp)),
		}
		temp.Disks, diags = types.ListValueFrom(ctx, types.Int64Type, item.Disks)
		if diags != nil {
			tflog.Error(ctx, fmt.Sprint("Error flattenSnapSetInListDeleted", diags))
		}
		res = append(res, temp)
	}

	tflog.Info(ctx, "End flattenSnapSetInListDeleted")
	return res
}
