package disks

import (
	"encoding/json"

	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
	"repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/disks"
	"repository.basistech.ru/BASIS/terraform-provider-decort/internal/flattens"
)

func flattenDiskSnapshot(d *schema.ResourceData, snapshot disks.ItemSnapshot) {
	d.Set("timestamp", snapshot.TimeStamp)
	d.Set("guid", snapshot.GUID)
	d.Set("res_id", snapshot.ResID)
	d.Set("snap_set_guid", snapshot.SnapSetGUID)
	d.Set("snap_set_time", snapshot.SnapSetTime)
}

func flattenDiskListUnattached(ul *disks.ListDisksUnattached) []map[string]interface{} {
	res := make([]map[string]interface{}, 0, len(ul.Data))
	for _, unattachedDisk := range ul.Data {
		unattachedDiskAcl, _ := json.Marshal(unattachedDisk.ACL)
		tmp := map[string]interface{}{
			"_meta":                 flattens.FlattenMeta(unattachedDisk.Meta),
			"account_id":            unattachedDisk.AccountID,
			"account_name":          unattachedDisk.AccountName,
			"acl":                   string(unattachedDiskAcl),
			"blk_discard":           unattachedDisk.BLKDiscard,
			"block_size":            unattachedDisk.BlockSize,
			"boot_partition":        unattachedDisk.BootPartition,
			"created_time":          unattachedDisk.CreatedTime,
			"deleted_time":          unattachedDisk.DeletedTime,
			"desc":                  unattachedDisk.Description,
			"destruction_time":      unattachedDisk.DestructionTime,
			"disk_path":             unattachedDisk.DiskPath,
			"gid":                   unattachedDisk.GID,
			"guid":                  unattachedDisk.GUID,
			"disk_id":               unattachedDisk.ID,
			"image_id":              unattachedDisk.ImageID,
			"images":                unattachedDisk.Images,
			"iotune":                flattenIOTune(unattachedDisk.IOTune),
			"iqn":                   unattachedDisk.IQN,
			"login":                 unattachedDisk.Login,
			"milestones":            unattachedDisk.Milestones,
			"disk_name":             unattachedDisk.Name,
			"order":                 unattachedDisk.Order,
			"params":                unattachedDisk.Params,
			"parent_id":             unattachedDisk.ParentID,
			"passwd":                unattachedDisk.Password,
			"pci_slot":              unattachedDisk.PCISlot,
			"pool":                  unattachedDisk.Pool,
			"present_to":            unattachedDisk.PresentTo,
			"provision":             unattachedDisk.Provision,
			"purge_attempts":        unattachedDisk.PurgeAttempts,
			"purge_time":            unattachedDisk.PurgeTime,
			"reality_device_number": unattachedDisk.RealityDeviceNumber,
			"reference_id":          unattachedDisk.ReferenceID,
			"res_id":                unattachedDisk.ResID,
			"res_name":              unattachedDisk.ResName,
			"role":                  unattachedDisk.Role,
			"sep_id":                unattachedDisk.SEPID,
			"shareable":             unattachedDisk.Shareable,
			"cache":                 unattachedDisk.Cache,
			"size_max":              unattachedDisk.SizeMax,
			"size_used":             unattachedDisk.SizeUsed,
			"snapshots":             flattenDiskSnapshotList(unattachedDisk.Snapshots),
			"status":                unattachedDisk.Status,
			"to_clean":              unattachedDisk.ToClean,
			"tech_status":           unattachedDisk.TechStatus,
			"vmid":                  unattachedDisk.VMID,
		}
		res = append(res, tmp)
	}
	return res
}

func flattenDisk(d *schema.ResourceData, disk *disks.RecordDisk) {
	diskAcl, _ := json.Marshal(disk.ACL)
	d.Set("account_id", disk.AccountID)
	d.Set("account_name", disk.AccountName)
	d.Set("acl", string(diskAcl))
	d.Set("blk_discard", disk.BLKDiscard)
	d.Set("block_size", disk.BlockSize)
	// d.Set("boot_partition", disk.BootPartition)
	d.Set("computes", flattenDiskComputes(disk.Computes))
	d.Set("created_by", disk.CreatedBy)
	d.Set("created_time", disk.CreatedTime)
	d.Set("deleted_by", disk.DeletedBy)
	d.Set("deleted_time", disk.DeletedTime)
	d.Set("desc", disk.Description)
	d.Set("destruction_time", disk.DestructionTime)
	d.Set("devicename", disk.DeviceName)
	// d.Set("disk_path", disk.DiskPath)
	d.Set("gid", disk.GID)
	// d.Set("guid", disk.GUID)
	d.Set("disk_id", disk.ID)
	d.Set("image_id", disk.ImageID)
	d.Set("images", disk.Images)
	d.Set("iotune", flattenIOTune(disk.IOTune))
	// d.Set("iqn", disk.IQN)
	// d.Set("login", disk.Login)
	d.Set("independent", disk.Independent)
	d.Set("machine_id", disk.MachineID)
	d.Set("machine_name", disk.MachineName)
	d.Set("disk_name", disk.Name)
	d.Set("order", disk.Order)
	d.Set("params", disk.Params)
	d.Set("parent_id", disk.ParentID)
	// d.Set("passwd", disk.Passwd)
	d.Set("pci_slot", disk.PCISlot)
	d.Set("pool", disk.Pool)
	d.Set("present_to", disk.PresentTo)
	d.Set("provision", disk.Provision)
	// d.Set("purge_attempts", disk.PurgeAttempts)
	d.Set("purge_time", disk.PurgeTime)
	d.Set("replication", flattenDiskReplication(disk.Replication))
	// d.Set("reality_device_number", disk.RealityDeviceNumber)
	// d.Set("reference_id", disk.ReferenceID)
	d.Set("res_id", disk.ResID)
	d.Set("res_name", disk.ResName)
	d.Set("role", disk.Role)
	d.Set("sep_id", disk.SepID)
	d.Set("sep_type", disk.SepType)
	d.Set("size_max", disk.SizeMax)
	d.Set("size_used", disk.SizeUsed)
	d.Set("shareable", disk.Shareable)
	d.Set("cache", disk.Cache)
	d.Set("snapshots", flattenDiskSnapshotList(disk.Snapshots))
	d.Set("status", disk.Status)
	d.Set("storage_policy_id", disk.StoragePolicyID)
	d.Set("tech_status", disk.TechStatus)
	d.Set("vmid", disk.VMID)
	d.Set("updated_by", disk.UpdatedBy)
	d.Set("updated_time", disk.UpdatedTime)
	d.Set("to_clean", disk.ToClean)
}

func flattenDiskReplication(rep disks.ItemReplication) []map[string]interface{} {
	res := []map[string]interface{}{
		{
			"disk_id":        rep.DiskID,
			"pool_id":        rep.PoolID,
			"role":           rep.Role,
			"self_volume_id": rep.SelfVolumeID,
			"storage_id":     rep.StorageID,
			"volume_id":      rep.VolumeID,
		},
	}
	return res
}

func flattenDiskReplica(d *schema.ResourceData, disk *disks.RecordDisk, statusReplication string) {
	diskAcl, _ := json.Marshal(disk.ACL)
	d.Set("account_id", disk.AccountID)
	d.Set("account_name", disk.AccountName)
	d.Set("acl", string(diskAcl))
	// d.Set("boot_partition", disk.BootPartition)
	d.Set("computes", flattenDiskComputes(disk.Computes))
	d.Set("created_time", disk.CreatedTime)
	d.Set("deleted_time", disk.DeletedTime)
	d.Set("desc", disk.Description)
	d.Set("destruction_time", disk.DestructionTime)
	d.Set("devicename", disk.DeviceName)
	// d.Set("disk_path", disk.DiskPath)
	d.Set("gid", disk.GID)
	// d.Set("guid", disk.GUID)
	d.Set("replica_disk_id", disk.ID)
	d.Set("image_id", disk.ImageID)
	d.Set("images", disk.Images)
	d.Set("iotune", flattenIOTune(disk.IOTune))
	// d.Set("iqn", disk.IQN)
	// d.Set("login", disk.Login)
	// d.Set("milestones", disk.Milestones)
	d.Set("disk_name", disk.Name)
	d.Set("order", disk.Order)
	d.Set("params", disk.Params)
	d.Set("parent_id", disk.ParentID)
	// d.Set("passwd", disk.Passwd)
	d.Set("pci_slot", disk.PCISlot)
	d.Set("pool", disk.Pool)
	d.Set("present_to", disk.PresentTo)
	// d.Set("purge_attempts", disk.PurgeAttempts)
	d.Set("purge_time", disk.PurgeTime)
	d.Set("replication", flattenDiskReplication(disk.Replication))
	// d.Set("reality_device_number", disk.RealityDeviceNumber)
	// d.Set("reference_id", disk.ReferenceID)
	d.Set("res_id", disk.ResID)
	d.Set("res_name", disk.ResName)
	d.Set("role", disk.Role)
	d.Set("sep_id", disk.SepID)
	d.Set("sep_type", disk.SepType)
	d.Set("size_max", disk.SizeMax)
	d.Set("size_used", disk.SizeUsed)
	d.Set("shareable", disk.Shareable)
	d.Set("cache", disk.Cache)
	d.Set("snapshots", flattenDiskSnapshotList(disk.Snapshots))
	d.Set("status", disk.Status)
	d.Set("status_replication", statusReplication)
	d.Set("tech_status", disk.TechStatus)
	d.Set("vmid", disk.VMID)
}

func flattenDiskSnapshotList(sl disks.ListSnapshots) []interface{} {
	res := make([]interface{}, 0, len(sl))
	for _, snapshot := range sl {
		temp := map[string]interface{}{
			"guid":          snapshot.GUID,
			"label":         snapshot.Label,
			"res_id":        snapshot.ResID,
			"snap_set_guid": snapshot.SnapSetGUID,
			"snap_set_time": snapshot.SnapSetTime,
			"timestamp":     snapshot.TimeStamp,
		}
		res = append(res, temp)
	}

	return res
}

func flattenDiskList(dl *disks.ListDisks) []map[string]interface{} {
	res := make([]map[string]interface{}, 0, len(dl.Data))
	for _, disk := range dl.Data {
		diskAcl, _ := json.Marshal(disk.ACL)
		temp := map[string]interface{}{
			"account_id":        disk.AccountID,
			"account_name":      disk.AccountName,
			"acl":               string(diskAcl),
			"blk_discard":       disk.BLKDiscard,
			"block_size":        disk.BlockSize,
			"computes":          flattenDiskComputes(disk.Computes),
			"created_by":        disk.CreatedBy,
			"created_time":      disk.CreatedTime,
			"deleted_by":        disk.DeletedBy,
			"deleted_time":      disk.DeletedTime,
			"desc":              disk.Description,
			"destruction_time":  disk.DestructionTime,
			"devicename":        disk.DeviceName,
			"gid":               disk.GID,
			"disk_id":           disk.ID,
			"image_id":          disk.ImageID,
			"images":            disk.Images,
			"independent":       disk.Independent,
			"iotune":            flattenIOTune(disk.IOTune),
			"machine_id":        disk.MachineID,
			"machine_name":      disk.MachineName,
			"milestones":        disk.Milestones,
			"disk_name":         disk.Name,
			"order":             disk.Order,
			"params":            disk.Params,
			"parent_id":         disk.ParentID,
			"pci_slot":          disk.PCISlot,
			"pool":              disk.Pool,
			"present_to":        disk.PresentTo,
			"provision":         disk.Provision,
			"purge_time":        disk.PurgeTime,
			"replication":       flattenDiskReplication(disk.Replication),
			"res_id":            disk.ResID,
			"res_name":          disk.ResName,
			"role":              disk.Role,
			"sep_id":            disk.SepID,
			"sep_type":          disk.SepType,
			"shareable":         disk.Shareable,
			"cache":             disk.Cache,
			"size_available":    disk.SizeAvailable,
			"size_max":          disk.SizeMax,
			"size_used":         disk.SizeUsed,
			"snapshots":         flattenDiskSnapshotList(disk.Snapshots),
			"status":            disk.Status,
			"storage_policy_id": disk.StoragePolicyID,
			"tech_status":       disk.TechStatus,
			"vmid":              disk.VMID,
			"updated_by":        disk.UpdatedBy,
			"updated_time":      disk.UpdatedTime,
			"to_clean":          disk.ToClean,
		}
		res = append(res, temp)
	}
	return res
}

func flattenIOTune(iot disks.IOTune) []map[string]interface{} {
	res := make([]map[string]interface{}, 0)
	temp := map[string]interface{}{
		"read_bytes_sec":      iot.ReadBytesSec,
		"read_bytes_sec_max":  iot.ReadBytesSecMax,
		"read_iops_sec":       iot.ReadIOPSSec,
		"read_iops_sec_max":   iot.ReadIOPSSecMax,
		"size_iops_sec":       iot.SizeIOPSSec,
		"total_bytes_sec":     iot.TotalBytesSec,
		"total_bytes_sec_max": iot.TotalBytesSecMax,
		"total_iops_sec":      iot.TotalIOPSSec,
		"total_iops_sec_max":  iot.TotalIOPSSecMax,
		"write_bytes_sec":     iot.WriteBytesSec,
		"write_bytes_sec_max": iot.WriteBytesSecMax,
		"write_iops_sec":      iot.WriteIOPSSec,
		"write_iops_sec_max":  iot.WriteIOPSSecMax,
	}

	res = append(res, temp)
	return res
}

func flattenDiskComputes(computes map[string]string) []map[string]interface{} {
	res := make([]map[string]interface{}, 0)
	for computeKey, computeVal := range computes {
		temp := map[string]interface{}{
			"compute_id":   computeKey,
			"compute_name": computeVal,
		}
		res = append(res, temp)
	}
	return res
}
