package flattens

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

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

// ReplicationDiskresource flattens resource for disk.
// Return error in case resource is not found on the platform.
// Flatten errors are added to tflog.
func DiskReplicationResource(ctx context.Context, state *models.ResourceRecordDiskReplicationModel, c *decort.DecortClient) diag.Diagnostics {
	tflog.Info(ctx, "Start flattens.DiskReplicationresource")

	diags := diag.Diagnostics{}

	recordDisk, status, err := utilities.ResourceDiskReplicationCheckPresence(ctx, state, c)
	if err != nil {
		diags.AddError("Cannot get info about disk", err.Error())
		return diags
	}

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

	diskAcl, _ := json.Marshal(recordDisk.ACL)

	*state = models.ResourceRecordDiskReplicationModel{
		DiskId:            state.DiskId,
		Name:              state.Name,
		SepID:             state.SepID,
		ReplicationId:     state.ReplicationId,
		Timeouts:          state.Timeouts,
		PoolName:          state.PoolName,
		Pause:             state.Pause,
		Reverse:           state.Reverse,
		Start:             state.Start,
		Detach:            state.Detach,
		Permanently:       state.Permanently,
		Reason:            state.Reason,
		Id:                types.StringValue(strconv.Itoa(int(recordDisk.Replication.DiskID))),
		ACL:               types.StringValue(string(diskAcl)),
		AccountID:         types.Int64Value(int64(recordDisk.AccountID)),
		AccountName:       types.StringValue(recordDisk.AccountName),
		Computes:          flattenRComputes(ctx, recordDisk.Computes),
		CreatedTime:       types.Int64Value(int64(recordDisk.CreatedTime)),
		DeletedTime:       types.Int64Value(int64(recordDisk.DeletedTime)),
		DeviceName:        types.StringValue(recordDisk.DeviceName),
		Description:       types.StringValue(recordDisk.Description),
		DestructionTime:   types.Int64Value(int64(recordDisk.DestructionTime)),
		GID:               types.Int64Value(int64(recordDisk.GID)),
		ImageID:           types.Int64Value(int64(recordDisk.ImageID)),
		Images:            flattens.FlattenSimpleTypeToList(ctx, types.StringType, recordDisk.Images),
		Order:             types.Int64Value(int64(recordDisk.Order)),
		Params:            types.StringValue(recordDisk.Params),
		ParentID:          types.Int64Value(int64(recordDisk.ParentID)),
		PCISlot:           types.Int64Value(int64(recordDisk.PCISlot)),
		Pool:              types.StringValue(recordDisk.Pool),
		PresentTo:         flattens.FlattenSimpleTypeToList(ctx, types.StringType, recordDisk.PresentTo),
		PurgeTime:         types.Int64Value(int64(recordDisk.PurgeTime)),
		ResID:             types.StringValue(recordDisk.ResID),
		ResName:           types.StringValue(recordDisk.ResName),
		Role:              types.StringValue(recordDisk.Role),
		SepType:           types.StringValue(recordDisk.SepType),
		Shareable:         types.BoolValue(recordDisk.Shareable),
		SizeMax:           types.Int64Value(int64(recordDisk.SizeMax)),
		SizeUsed:          types.Float64Value(recordDisk.SizeUsed),
		Snapshots:         flattenSnapshots(ctx, recordDisk.Snapshots),
		Status:            types.StringValue(recordDisk.Status),
		StatusReplication: types.StringValue(*status),
		TechStatus:        types.StringValue(recordDisk.TechStatus),
		Type:              types.StringValue(recordDisk.Type),
		VMID:              types.Int64Value(int64(recordDisk.VMID)),
	}

	iotune := models.ResourceDiskReplicationIOTuneModel{
		ReadBytesSec:     types.Int64Value(int64(recordDisk.IOTune.ReadBytesSec)),
		ReadBytesSecMax:  types.Int64Value(int64(recordDisk.IOTune.ReadBytesSecMax)),
		ReadIOPSSec:      types.Int64Value(int64(recordDisk.IOTune.ReadIOPSSec)),
		ReadIOPSSecMax:   types.Int64Value(int64(recordDisk.IOTune.ReadIOPSSecMax)),
		SizeIOPSSec:      types.Int64Value(int64(recordDisk.IOTune.SizeIOPSSec)),
		TotalBytesSec:    types.Int64Value(int64(recordDisk.IOTune.TotalBytesSec)),
		TotalBytesSecMax: types.Int64Value(int64(recordDisk.IOTune.TotalBytesSecMax)),
		TotalIOPSSec:     types.Int64Value(int64(recordDisk.IOTune.TotalIOPSSec)),
		TotalIOPSSecMax:  types.Int64Value(int64(recordDisk.IOTune.TotalIOPSSecMax)),
		WriteBytesSec:    types.Int64Value(int64(recordDisk.IOTune.WriteBytesSec)),
		WriteBytesSecMax: types.Int64Value(int64(recordDisk.IOTune.WriteBytesSecMax)),
		WriteIOPSSec:     types.Int64Value(int64(recordDisk.IOTune.WriteIOPSSec)),
		WriteIOPSSecMax:  types.Int64Value(int64(recordDisk.IOTune.WriteIOPSSecMax)),
	}
	obj, diags := types.ObjectValueFrom(ctx, models.ResourceDiskReplicationIOTune, iotune)
	if diags != nil {
		tflog.Error(ctx, fmt.Sprint("Error flattens.ReplicationDiskresource iotune struct to obj", diags))
	}
	state.IOTune = obj

	itemReplication := models.ResourceItemReplicationModel{
		DiskID:       types.Int64Value(int64(recordDisk.Replication.DiskID)),
		PoolID:       types.StringValue(recordDisk.Replication.PoolID),
		Role:         types.StringValue(recordDisk.Replication.Role),
		SelfVolumeID: types.StringValue(recordDisk.Replication.SelfVolumeID),
		StorageID:    types.StringValue(recordDisk.Replication.StorageID),
		VolumeID:     types.StringValue(recordDisk.Replication.VolumeID),
	}

	obj, diags = types.ObjectValueFrom(ctx, models.ResourceItemReplication, itemReplication)
	if diags != nil {
		tflog.Error(ctx, fmt.Sprint("Error flattens.ReplicationDiskresource Replication struct to obj", diags))
	}
	state.Replication = obj

	tflog.Info(ctx, "flattens.ReplicationDiskresource: end flatten")
	return nil
}

func flattenRComputes(ctx context.Context, items map[string]string) types.List {
	tflog.Info(ctx, "Start flattenRComputes")
	tempSlice := make([]types.Object, 0, len(items))
	for id, name := range items {
		temp := models.ItemComputeModel{
			ComputeId:   types.StringValue(id),
			ComputeName: types.StringValue(name),
		}
		obj, diags := types.ObjectValueFrom(ctx, models.ItemCompute, temp)
		if diags != nil {
			tflog.Error(ctx, fmt.Sprint("Error flattenRComputes struct to obj", diags))
		}
		tempSlice = append(tempSlice, obj)
	}

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

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