package flattens

import (
	"context"
	"fmt"

	"github.com/google/uuid"
	"github.com/hashicorp/terraform-plugin-framework/attr"
	"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/account"
	"repository.basistech.ru/BASIS/terraform-provider-dynamix/internal/client"
	"repository.basistech.ru/BASIS/terraform-provider-dynamix/internal/service/cloudbroker/account/models"
	"repository.basistech.ru/BASIS/terraform-provider-dynamix/internal/service/cloudbroker/account/utilities"
)

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

	diags := diag.Diagnostics{}

	accList, err := utilities.AccountListDataSourceCheckPresence(ctx, state, c)
	if err != nil {
		diags.AddError("Cannot get info about account list", err.Error())
		return diags
	}

	tflog.Info(ctx, "flattens.AccountListDataSource: before flatten")

	id := uuid.New()
	*state = models.DataSourceAccountListModel{
		ByID:     state.ByID,
		Name:     state.Name,
		ACL:      state.ACL,
		Page:     state.Page,
		Size:     state.Size,
		Timeouts: state.Timeouts,
		SortBy:   state.SortBy,

		Id:         types.StringValue(id.String()),
		EntryCount: types.Int64Value(int64(accList.EntryCount)),
	}

	items := make([]models.AccountListElementModel, 0, len(accList.Data))
	for _, item := range accList.Data {
		i := models.AccountListElementModel{
			DCLocation:             types.StringValue(item.DCLocation),
			CKey:                   types.StringValue(item.CKey),
			ACL:                    flattenACLInAccountList(ctx, item.ACL),
			Company:                types.StringValue(item.Company),
			CompanyURL:             types.StringValue(item.CompanyURL),
			CPUAllocationParameter: types.StringValue(item.CPUAllocationParameter),
			CPUAllocationRatio:     types.Float64Value(item.CPUAllocationRatio),
			CreatedBy:              types.StringValue(item.CreatedBy),
			CreatedTime:            types.Int64Value(int64(item.CreatedTime)),
			DeactivationTime:       types.Float64Value(item.DeactivationTime),
			DeletedBy:              types.StringValue(item.DeletedBy),
			DeletedTime:            types.Int64Value(int64(item.DeletedTime)),
			DisplayName:            types.StringValue(item.DisplayName),
			GUID:                   types.Int64Value(int64(item.GUID)),
			Name:                   types.StringValue(item.Name),
			ResourceLimits:         flattenAccountListResourceLimits(ctx, item.ResourceLimits),
			ResTypes:               flattenAccListSimpleType(ctx, types.StringType, item.ResTypes),
			SendAccessEmails:       types.BoolValue(item.SendAccessEmails),
			Status:                 types.StringValue(item.Status),
			UniqPools:              flattenAccListSimpleType(ctx, types.StringType, item.UniqPools),
			UpdatedTime:            types.Int64Value(int64(item.UpdatedTime)),
			Version:                types.Int64Value(int64(item.Version)),
			VINS:                   flattenAccListSimpleType(ctx, types.Int64Type, item.VINS),
		}
		i.ComputeFeatures, diags = types.ListValueFrom(ctx, types.StringType, item.ComputeFeatures)
		if diags.HasError() {
			tflog.Error(ctx, fmt.Sprint("flattens.AccountListDataSource: cannot flatten item.ComputeFeatures to i.ComputeFeatures", diags))
		}
		items = append(items, i)
	}
	state.Items = items

	tflog.Info(ctx, "flattens.AccountListDataSource: after flatten")

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

func flattenAccountListResourceLimits(ctx context.Context, limits account.ResourceLimits) *models.AccountListResourceLimitsModel {
	tflog.Info(ctx, "Start flattenAccountListResourceLimits")
	res := models.AccountListResourceLimitsModel{
		CuC:      types.Float64Value(limits.CuC),
		CuD:      types.Float64Value(limits.CuD),
		CuI:      types.Float64Value(limits.CuI),
		CuM:      types.Float64Value(limits.CuM),
		CuDM:     types.Float64Value(limits.CuDM),
		CuNP:     types.Float64Value(limits.CuNP),
		GPUUnits: types.Float64Value(limits.GPUUnits),
	}

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

func flattenACLInAccountList(ctx context.Context, aclList []account.ACL) []models.AccountListACLModel {
	tflog.Info(ctx, "Start flattenACLInAccountList")
	res := make([]models.AccountListACLModel, 0, len(aclList))
	for _, item := range aclList {
		temp := models.AccountListACLModel{
			Explicit:    types.BoolValue(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)
	}

	return res
}

func flattenAccListSimpleType(ctx context.Context, elementType attr.Type, elements any) types.List {
	res, diags := types.ListValueFrom(ctx, elementType, elements)
	if diags != nil {
		tflog.Error(ctx, fmt.Sprint("Error flattenAccListSimpleType", diags))
	}
	return res
}
