package flattens

import (
	"context"
	"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/cloudbroker/rg"
	"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/cloudbroker/rg/models"
	"repository.basistech.ru/BASIS/terraform-provider-dynamix/internal/service/cloudbroker/rg/utilities"
)

// RGDataSource flattens data source for rg (resource group).
// Return error in case data source is not found on the platform.
// Flatten errors are added to tflog.
func RGDataSource(ctx context.Context, state *models.DataSourceRGModel, c *client.Client) diag.Diagnostics {
	tflog.Info(ctx, "Start flattens.RGDataSource")

	diags := diag.Diagnostics{}

	rgId := uint64(state.RGID.ValueInt64())

	recordRG, err := utilities.RGCheckPresence(ctx, rgId, c)
	if err != nil {
		diags.AddError(fmt.Sprintf("Cannot get info about resource group with ID %v", rgId), err.Error())
		return diags
	}

	tflog.Info(ctx, "flattens.RGDataSource: before flatten", map[string]any{"rg_id": rgId, "recordRG": recordRG})

	id := uuid.New()
	*state = models.DataSourceRGModel{
		RGID: state.RGID,

		Timeouts: state.Timeouts,

		Id:                     types.StringValue(id.String()),
		AccountID:              types.Int64Value(int64(recordRG.AccountID)),
		AccountName:            types.StringValue(recordRG.AccountName),
		ACL:                    flattenACL(ctx, &recordRG.ACL),
		ComputeFeatures:        flattens.FlattenSimpleTypeToList(ctx, types.StringType, &recordRG.ComputeFeatures),
		Computes:               flattens.FlattenSimpleTypeToList(ctx, types.Int64Type, &recordRG.VMs),
		CPUAllocationParameter: types.StringValue(recordRG.CPUAllocationParameter),
		CPUAllocationRatio:     types.Float64Value(recordRG.CPUAllocationRatio),
		CreatedBy:              types.StringValue(recordRG.CreatedBy),
		CreatedTime:            types.Int64Value(int64(recordRG.CreatedTime)),
		DefNetID:               types.Int64Value(recordRG.DefNetID),
		DefNetType:             types.StringValue(recordRG.DefNetType),
		DeletedBy:              types.StringValue(recordRG.DeletedBy),
		DeletedTime:            types.Int64Value(int64(recordRG.DeletedTime)),
		Description:            types.StringValue(recordRG.Description),
		Dirty:                  types.BoolValue(recordRG.Dirty),
		GID:                    types.Int64Value(int64(recordRG.GID)),
		GUID:                   types.Int64Value(int64(recordRG.GUID)),
		LockStatus:             types.StringValue(recordRG.LockStatus),
		Milestones:             types.Int64Value(int64(recordRG.Milestones)),
		Name:                   types.StringValue(recordRG.Name),
		ResourceLimits:         flattenResourceLimits(ctx, &recordRG.ResourceLimits),
		ResourceTypes:          flattens.FlattenSimpleTypeToList(ctx, types.StringType, &recordRG.ResTypes),
		Secret:                 types.StringValue(recordRG.Secret),
		Status:                 types.StringValue(recordRG.Status),
		UniqPools:              flattens.FlattenSimpleTypeToList(ctx, types.StringType, &recordRG.UniqPools),
		UpdatedBy:              types.StringValue(recordRG.UpdatedBy),
		UpdatedTime:            types.Int64Value(int64(recordRG.UpdatedTime)),
		VINS:                   flattens.FlattenSimpleTypeToList(ctx, types.Int64Type, &recordRG.VINS),
	}

	tflog.Info(ctx, "flattens.RGDataSource: after flatten", map[string]any{"rg_id": state.Id.ValueString()})

	tflog.Info(ctx, "End flattens.RGDataSource", map[string]any{"rg_id": state.Id.ValueString()})
	return nil
}

func flattenACL(ctx context.Context, item *rg.ListACL) types.List {
	tflog.Info(ctx, "Start flattenACLItems")
	tempSlice := make([]types.Object, 0, len(*item))
	for _, aclItem := range *item {
		temp := models.ItemACLModel{
			Explicit:    types.BoolValue(aclItem.Explicit),
			GUID:        types.StringValue(aclItem.GUID),
			Right:       types.StringValue(aclItem.Right),
			Status:      types.StringValue(aclItem.Status),
			Type:        types.StringValue(aclItem.Type),
			UserGroupID: types.StringValue(aclItem.UserGroupID),
		}
		obj, diags := types.ObjectValueFrom(ctx, models.ItemACL, temp)
		if diags != nil {
			tflog.Error(ctx, fmt.Sprint("Error flattenACLItems struct to obj", diags))
		}
		tempSlice = append(tempSlice, obj)
	}

	res, diags := types.ListValueFrom(ctx, types.ObjectType{AttrTypes: models.ItemACL}, tempSlice)
	if diags != nil {
		tflog.Error(ctx, fmt.Sprint("Error flattenACLItems", diags))
	}

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

func flattenResourceLimits(ctx context.Context, item *rg.ResourceLimits) types.Object {
	tflog.Info(ctx, "Start flattenResourceLimits")
	temp := models.ResourceLimitsModel{
		CUC:      types.Float64Value(item.CUC),
		CUD:      types.Float64Value(item.CuD),
		CUDM:     types.Float64Value(item.CUDM),
		CUI:      types.Float64Value(item.CUI),
		CUM:      types.Float64Value(item.CUM),
		CUNP:     types.Float64Value(item.CUNP),
		GPUUnits: types.Float64Value(item.GPUUnits),
	}
	res, diags := types.ObjectValueFrom(ctx, models.ItemResourseModel, temp)
	if diags != nil {
		tflog.Error(ctx, fmt.Sprint("Error flattenResourceLimits struct to obj", diags))
	}

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