package flattens

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

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

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

	diags := diag.Diagnostics{}

	recordDisk, diags := utilities.DataSourceDiskCheckPresence(ctx, state, c)
	if diags.HasError() {
		return diags
	}

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

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

	*state = models.DiskModel{
		DiskID:              state.DiskID,
		Timeouts:            state.Timeouts,
		AccountID:           types.Int64Value(int64(recordDisk.AccountID)),
		AccountName:         types.StringValue(recordDisk.AccountName),
		SEPType:             types.StringValue(recordDisk.SEPType),
		ACL:                 types.StringValue(string(diskAcl)),
		BootPartition:       types.Int64Value(int64(recordDisk.BootPartition)),
		Computes:            flattenComputeList(ctx, recordDisk.Computes),
		CreatedTime:         types.Int64Value(int64(recordDisk.CreatedTime)),
		DeletedTime:         types.Int64Value(int64(recordDisk.DeletedTime)),
		Description:         types.StringValue(recordDisk.Description),
		DestructionTime:     types.Int64Value(int64(recordDisk.DestructionTime)),
		DiskPath:            types.StringValue(recordDisk.DiskPath),
		DeviceName:          types.StringValue(recordDisk.DeviceName),
		GID:                 types.Int64Value(int64(recordDisk.GID)),
		GUID:                types.Int64Value(int64(recordDisk.GUID)),
		ImageID:             types.Int64Value(int64(recordDisk.ImageID)),
		IQN:                 types.StringValue(recordDisk.IQN),
		Login:               types.StringValue(recordDisk.Login),
		Milestones:          types.Int64Value(int64(recordDisk.Milestones)),
		Name:                types.StringValue(recordDisk.Name),
		Order:               types.Int64Value(int64(recordDisk.Order)),
		Params:              types.StringValue(recordDisk.Params),
		ParentID:            types.Int64Value(int64(recordDisk.ParentID)),
		Password:            types.StringValue(recordDisk.Password),
		PCISlot:             types.Int64Value(int64(recordDisk.PCISlot)),
		Pool:                types.StringValue(recordDisk.Pool),
		PurgeTime:           types.Int64Value(int64(recordDisk.PurgeTime)),
		PurgeAttempts:       types.Int64Value(int64(recordDisk.PurgeAttempts)),
		RealityDeviceNumber: types.Int64Value(int64(recordDisk.RealityDeviceNumber)),
		ReferenceID:         types.StringValue(recordDisk.ReferenceID),
		ResID:               types.StringValue(recordDisk.ResID),
		ResName:             types.StringValue(recordDisk.ResName),
		Role:                types.StringValue(recordDisk.Role),
		SEPID:               types.Int64Value(int64(recordDisk.SEPID)),
		Shareable:           types.BoolValue(recordDisk.Shareable),
		SizeMax:             types.Int64Value(int64(recordDisk.SizeMax)),
		SizeUsed:            types.Float64Value(recordDisk.SizeUsed),
		Snapshots:           flattenSnapshotList(ctx, recordDisk.Snapshots),
		Status:              types.StringValue(recordDisk.Status),
		TechStatus:          types.StringValue(recordDisk.TechStatus),
		Type:                types.StringValue(recordDisk.Type),
		VMID:                types.Int64Value(int64(recordDisk.VMID)),
	}

	state.Images, diags = types.ListValueFrom(ctx, types.Int64Type, recordDisk.Images)
	if diags != nil {
		tflog.Error(ctx, fmt.Sprint("flattens.DiskDataSource: cannot flatten recordDisk.Images to state.Images", diags))
	}
	state.PresentTo, diags = types.ListValueFrom(ctx, types.Int64Type, recordDisk.PresentTo)
	if diags != nil {
		tflog.Error(ctx, fmt.Sprint("flattens.DiskDataSource: cannot flatten recordDisk.PresentTo to state.PresentTo", diags))
	}

	iotune := models.IOModel{
		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)),
	}

	state.IOTune = &iotune

	repl := models.ItemReplModel{
		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),
	}

	state.Replication = &repl

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