package account

import (
	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
	"repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker/account"
)

func flattenResourceAccount(d *schema.ResourceData, acc *account.RecordAccount) {
	d.Set("dc_location", acc.DCLocation)
	d.Set("acl", flattenAccAcl(acc.ACL))
	d.Set("company", acc.Company)
	d.Set("companyurl", acc.CompanyURL)
	d.Set("cpu_allocation_parameter", acc.CPUAllocationParameter)
	d.Set("cpu_allocation_ratio", acc.CPUAllocationRatio)
	d.Set("created_by", acc.CreatedBy)
	d.Set("created_time", acc.CreatedTime)
	d.Set("deactivation_time", acc.DeactivationTime)
	d.Set("desc", acc.Description)
	d.Set("deleted_by", acc.DeletedBy)
	d.Set("deleted_time", acc.DeletedTime)
	d.Set("displayname", acc.DisplayName)
	d.Set("enable", flattenEnabled(acc.Status))
	d.Set("guid", acc.GUID)
	d.Set("account_id", acc.ID)
	d.Set("account_name", acc.Name)
	d.Set("resource_limits", flattenRgResourceLimits(acc.ResourceLimits))
	d.Set("storage_policy", flattenSTPolicy(acc.ResourceLimits.StoragePolicies))
	d.Set("resource_types", acc.ResTypes)
	d.Set("send_access_emails", acc.SendAccessEmails)
	d.Set("status", acc.Status)
	d.Set("uniq_pools", acc.UniqPools)
	d.Set("updated_by", acc.UpdatedBy)
	d.Set("updated_time", acc.UpdatedTime)
	d.Set("version", acc.Version)
	d.Set("vins", acc.VINS)
	d.Set("zone_ids", flattenZonesInResource(acc.ZoneIDs))
}

func flattenDataAccount(d *schema.ResourceData, acc *account.RecordAccount) {
	d.Set("dc_location", acc.DCLocation)
	d.Set("acl", flattenAccAcl(acc.ACL))
	d.Set("company", acc.Company)
	d.Set("companyurl", acc.CompanyURL)
	d.Set("compute_features", acc.ComputeFeatures)
	d.Set("cpu_allocation_parameter", acc.CPUAllocationParameter)
	d.Set("cpu_allocation_ratio", acc.CPUAllocationRatio)
	d.Set("created_by", acc.CreatedBy)
	d.Set("created_time", acc.CreatedTime)
	d.Set("deactivation_time", acc.DeactivationTime)
	d.Set("desc", acc.Description)
	d.Set("deleted_by", acc.DeletedBy)
	d.Set("deleted_time", acc.DeletedTime)
	d.Set("displayname", acc.DisplayName)
	d.Set("guid", acc.GUID)
	d.Set("account_id", acc.ID)
	d.Set("default_zone_id", acc.DefaultZoneID)
	d.Set("account_name", acc.Name)
	d.Set("resource_limits", flattenRgResourceLimits(acc.ResourceLimits))
	d.Set("resource_types", acc.ResTypes)
	d.Set("send_access_emails", acc.SendAccessEmails)
	d.Set("status", acc.Status)
	d.Set("storage_policy_ids", acc.StoragePolicyIDs)
	d.Set("uniq_pools", acc.UniqPools)
	d.Set("zone_ids", flattenZones(acc.ZoneIDs))
	d.Set("updated_by", acc.UpdatedBy)
	d.Set("updated_time", acc.UpdatedTime)
	d.Set("version", acc.Version)
	d.Set("vins", acc.VINS)

}

func flattenAccountRGList(argl *account.ListRG) []map[string]interface{} {
	res := make([]map[string]interface{}, 0, len(argl.Data))
	for _, arg := range argl.Data {
		temp := map[string]interface{}{
			"computes":     flattenAccRGComputes(arg.Computes),
			"resources":    flattenAccRGResources(arg.Resources),
			"created_by":   arg.CreatedBy,
			"created_time": arg.CreatedTime,
			"desc":         arg.Description,
			"deleted_by":   arg.DeletedBy,
			"deleted_time": arg.DeletedTime,
			"rg_id":        arg.ID,
			"milestones":   arg.Milestones,
			"rg_name":      arg.Name,
			"status":       arg.Status,
			"updated_by":   arg.UpdatedBy,
			"updated_time": arg.UpdatedTime,
			"vinses":       arg.VINSes,
		}
		res = append(res, temp)
	}
	return res

}

func flattenAccRGComputes(argc account.Computes) []map[string]interface{} {
	res := make([]map[string]interface{}, 0)
	temp := map[string]interface{}{
		"started": argc.Started,
		"stopped": argc.Stopped,
	}
	res = append(res, temp)
	return res
}

func flattenAccRGResources(argr account.RGResuorces) []map[string]interface{} {
	res := make([]map[string]interface{}, 0)
	temp := map[string]interface{}{
		"consumed": flattenAccResource(argr.Consumed),
		"limits":   flattenAccLimits(argr.Limits),
		"reserved": flattenAccResource(argr.Reserved),
	}
	res = append(res, temp)
	return res
}

func flattenAccLimits(l account.Limits) []map[string]interface{} {
	res := make([]map[string]interface{}, 0)
	temp := map[string]interface{}{
		"cpu":         l.CPU,
		"disksize":    l.DiskSize,
		"disksizemax": l.DiskSizeMax,
		"extips":      l.ExtIPs,
		"gpu":         l.GPU,
		"ram":         l.RAM,
		"seps":        l.SEPs,
	}
	res = append(res, temp)
	return res
}

func flattenAccResource(r account.Resource) []map[string]interface{} {
	res := make([]map[string]interface{}, 0)
	temp := map[string]interface{}{
		"cpu":         r.CPU,
		"disksize":    r.DiskSize,
		"disksizemax": r.DiskSizeMax,
		"extips":      r.ExtIPs,
		"gpu":         r.GPU,
		"ram":         r.RAM,
		"seps":        flattenAccountSeps(r.SEPs),
		"policies":    flattenAccountPolicies(r.Policies),
	}
	res = append(res, temp)
	return res
}

func flattenAccountPolicies(policies map[string]account.Policy) []map[string]interface{} {
	res := make([]map[string]interface{}, 0)
	for k, dataVal := range policies {
		temp := map[string]interface{}{
			"id":            k,
			"disk_size":     dataVal.DiskSize,
			"disk_size_max": dataVal.DiskSizeMax,
			"seps":          flattenAccountSeps(dataVal.SEPs),
		}
		res = append(res, temp)
	}
	return res
}

func flattenAccAcl(acls []account.ACLWithEmails) []map[string]interface{} {
	res := make([]map[string]interface{}, 0, len(acls))
	for _, acls := range acls {
		tempEmails := make([]string, 0, len(acls.Emails))
		for _, email := range acls.Emails {
			tempEmails = append(tempEmails, email)
		}

		temp := map[string]interface{}{
			"emails":        tempEmails,
			"explicit":      acls.Explicit,
			"guid":          acls.GUID,
			"right":         acls.Right,
			"status":        acls.Status,
			"type":          acls.Type,
			"user_group_id": acls.UserGroupID,
		}
		res = append(res, temp)
	}
	return res
}

func flattenRgResourceLimits(rl account.ResourceLimits) []map[string]interface{} {
	res := make([]map[string]interface{}, 0)
	temp := map[string]interface{}{
		"cu_c":           rl.CuC,
		"cu_d":           rl.CuD,
		"cu_dm":          rl.CuDM,
		"cu_i":           rl.CuI,
		"cu_m":           rl.CuM,
		"gpu_units":      rl.GPUUnits,
		"storage_policy": flattenSTPolicy(rl.StoragePolicies),
	}
	res = append(res, temp)

	return res
}

func flattenSTPolicy(ast []account.StoragePolicy) []map[string]interface{} {
	res := make([]map[string]interface{}, 0, len(ast))
	for _, item := range ast {
		temp := map[string]interface{}{
			"id":    item.ID,
			"limit": item.Limit,
		}
		res = append(res, temp)
	}
	return res
}

func flattenRgAcl(rgAcls []account.ACL) []map[string]interface{} {
	res := make([]map[string]interface{}, len(rgAcls))
	for _, rgAcl := range rgAcls {
		temp := map[string]interface{}{
			"explicit":      rgAcl.Explicit,
			"guid":          rgAcl.GUID,
			"right":         rgAcl.Right,
			"status":        rgAcl.Status,
			"type":          rgAcl.Type,
			"user_group_id": rgAcl.UserGroupID,
		}
		res = append(res, temp)
	}
	return res
}

func flattenListDeleted(al *account.ListAccounts) []map[string]interface{} {
	res := make([]map[string]interface{}, 0, len(al.Data))
	for _, acc := range al.Data {
		temp := map[string]interface{}{
			"dc_location":              acc.DCLocation,
			"acl":                      flattenRgAcl(acc.ACL),
			"company":                  acc.Company,
			"companyurl":               acc.CompanyURL,
			"compute_features":         acc.ComputeFeatures,
			"cpu_allocation_parameter": acc.CPUAllocationParameter,
			"cpu_allocation_ratio":     acc.CPUAllocationRatio,
			"created_by":               acc.CreatedBy,
			"created_time":             acc.CreatedTime,
			"deactivation_time":        acc.DeactivationTime,
			"desc":                     acc.Description,
			"deleted_by":               acc.DeletedBy,
			"deleted_time":             acc.DeletedTime,
			"displayname":              acc.DisplayName,
			"guid":                     acc.GUID,
			"account_id":               acc.ID,
			"account_name":             acc.Name,
			"resource_limits":          flattenRgResourceLimits(acc.ResourceLimits),
			"resource_types":           acc.ResTypes,
			"send_access_emails":       acc.SendAccessEmails,
			"status":                   acc.Status,
			"storage_policy_ids":       acc.StoragePolicyIDs,
			"uniq_pools":               acc.UniqPools,
			"default_zone_id":          acc.DefaultZoneID,
			"zone_ids":                 acc.ZoneIDs,
			"updated_by":              acc.UpdatedBy,
			"updated_time":             acc.UpdatedTime,
			"version":                  acc.Version,
			"vins":                     acc.VINS,
		}
		res = append(res, temp)
	}
	return res
}

func flattenAccountList(al *account.ListAccounts) []map[string]interface{} {
	res := make([]map[string]interface{}, 0, len(al.Data))
	for _, acc := range al.Data {
		temp := map[string]interface{}{
			"dc_location":              acc.DCLocation,
			"acl":                      flattenRgAcl(acc.ACL),
			"company":                  acc.Company,
			"companyurl":               acc.CompanyURL,
			"compute_features":         acc.ComputeFeatures,
			"cpu_allocation_parameter": acc.CPUAllocationParameter,
			"cpu_allocation_ratio":     acc.CPUAllocationRatio,
			"created_by":               acc.CreatedBy,
			"created_time":             acc.CreatedTime,
			"deactivation_time":        acc.DeactivationTime,
			"desc":                     acc.Description,
			"deleted_by":               acc.DeletedBy,
			"deleted_time":             acc.DeletedTime,
			"displayname":              acc.DisplayName,
			"guid":                     acc.GUID,
			"account_id":               acc.ID,
			"account_name":             acc.Name,
			"resource_limits":          flattenRgResourceLimits(acc.ResourceLimits),
			"resource_types":           acc.ResTypes,
			"send_access_emails":       acc.SendAccessEmails,
			"status":                   acc.Status,
			"storage_policy_ids":       acc.StoragePolicyIDs,
			"uniq_pools":               acc.UniqPools,
			"default_zone_id":          acc.DefaultZoneID,
			"zone_ids":                 acc.ZoneIDs,
			"updated_by":              acc.UpdatedBy,
			"updated_time":             acc.UpdatedTime,
			"version":                  acc.Version,
			"vins":                     acc.VINS,
		}
		res = append(res, temp)
	}
	return res
}

func flattenAccountAuditsList(aal account.ListAudits) []map[string]interface{} {
	res := make([]map[string]interface{}, 0, len(aal))
	for _, aa := range aal {
		temp := map[string]interface{}{
			"call":         aa.Call,
			"responsetime": aa.ResponseTime,
			"statuscode":   aa.StatusCode,
			"timestamp":    aa.Timestamp,
			"user":         aa.User,
		}
		res = append(res, temp)
	}
	return res
}

func flattenAccountComputesList(acl *account.ListComputes) []map[string]interface{} {
	res := make([]map[string]interface{}, 0, len(acl.Data))
	for _, acc := range acl.Data {
		temp := map[string]interface{}{
			"account_id":       acc.AccountID,
			"account_name":     acc.AccountName,
			"cpus":             acc.CPUs,
			"created_by":       acc.CreatedBy,
			"created_time":     acc.CreatedTime,
			"deleted_by":       acc.DeletedBy,
			"deleted_time":     acc.DeletedTime,
			"compute_id":       acc.ID,
			"compute_name":     acc.Name,
			"ram":              acc.RAM,
			"registered":       acc.Registered,
			"rg_id":            acc.RGID,
			"rg_name":          acc.RgName,
			"status":           acc.Status,
			"tech_status":      acc.TechStatus,
			"total_disks_size": acc.TotalDisksSize,
			"updated_by":       acc.UpdatedBy,
			"updated_time":     acc.UpdatedTime,
			"user_managed":     acc.UserManaged,
			"vins_connected":   acc.VINSConnected,
		}
		res = append(res, temp)
	}
	return res
}

func flattenAccountDisksList(adl *account.ListDisks) []map[string]interface{} {
	res := make([]map[string]interface{}, 0, len(adl.Data))
	for _, ad := range adl.Data {
		temp := map[string]interface{}{
			"disk_id":   ad.ID,
			"disk_name": ad.Name,
			"pool_name": ad.Pool,
			"sep_id":    ad.SepID,
			"shareable": ad.Shareable,
			"size_max":  ad.SizeMax,
			"type":      ad.Type,
		}
		res = append(res, temp)
	}
	return res
}

func flattenAccountFlipGroupsList(afgl *account.ListFLIPGroups) []map[string]interface{} {
	res := make([]map[string]interface{}, 0, len(afgl.Data))
	for _, afg := range afgl.Data {
		temp := map[string]interface{}{
			"account_id":   afg.AccountID,
			"client_type":  afg.ClientType,
			"conn_type":    afg.ConnType,
			"created_by":   afg.CreatedBy,
			"created_time": afg.CreatedTime,
			"default_gw":   afg.DefaultGW,
			"deleted_by":   afg.DeletedBy,
			"deleted_time": afg.DeletedTime,
			"desc":         afg.Description,
			"gid":          afg.GID,
			"guid":         afg.GUID,
			"fg_id":        afg.ID,
			"ip":           afg.IP,
			"milestones":   afg.Milestones,
			"fg_name":      afg.Name,
			"net_id":       afg.NetID,
			"net_type":     afg.NetType,
			"netmask":      afg.Netmask,
			"status":       afg.Status,
			"updated_by":   afg.UpdatedBy,
			"updated_time": afg.UpdatedTime,
		}
		res = append(res, temp)
	}
	return res
}

func flattenAccountVinsList(avl *account.ListVINS) []map[string]interface{} {
	res := make([]map[string]interface{}, 0, len(avl.Data))
	for _, av := range avl.Data {
		temp := map[string]interface{}{
			"account_id":     av.AccountID,
			"account_name":   av.AccountName,
			"computes":       av.Computes,
			"created_by":     av.CreatedBy,
			"created_time":   av.CreatedTime,
			"deleted_by":     av.DeletedBy,
			"deleted_time":   av.DeletedTime,
			"external_ip":    av.ExternalIP,
			"extnet_id":      av.ExtnetId,
			"free_ips":       av.FreeIPs,
			"vin_id":         av.ID,
			"vin_name":       av.Name,
			"network":        av.Network,
			"pri_vnf_dev_id": av.PriVNFDevID,
			"rg_id":          av.RGID,
			"rg_name":        av.RGName,
			"status":         av.Status,
			"updated_by":     av.UpdatedBy,
			"updated_time":   av.UpdatedTime,
		}
		res = append(res, temp)
	}
	return res
}

func flattenResourceConsumption(d *schema.ResourceData, acc *account.RecordResourceConsumption) {
	d.Set("account_id", acc.AccountID)
	d.Set("consumed", flattenAccResource(acc.Consumed))
	d.Set("reserved", flattenAccResource(acc.Reserved))
	d.Set("resource_limits", flattenRgResourceLimits(acc.ResourceLimits))
}

func flattenAccountSeps(seps map[string]map[string]account.DiskUsage) []map[string]interface{} {
	res := make([]map[string]interface{}, 0, len(seps))
	for sepKey, sepVal := range seps {
		for dataKey, dataVal := range sepVal {
			temp := map[string]interface{}{
				"sep_id":        sepKey,
				"data_name":     dataKey,
				"disk_size":     dataVal.DiskSize,
				"disk_size_max": dataVal.DiskSizeMax,
			}
			res = append(res, temp)
		}
	}
	return res
}

func flattenAccResourceConsumption(lrc *account.ListResources) []map[string]interface{} {
	res := make([]map[string]interface{}, 0, len(lrc.Data))
	for _, rc := range lrc.Data {
		temp := map[string]interface{}{
			"consumed":   flattenAccResource(rc.Consumed),
			"reserved":   flattenAccResource(rc.Reserved),
			"account_id": rc.AccountID,
		}
		res = append(res, temp)
	}
	return res
}

func flattenEnabled(status string) bool {
	return status == "CONFIRMED"
}

func flattenZones(zones []account.ZoneID) []map[string]interface{} {
	res := make([]map[string]interface{}, 0)
	for _, zone := range zones {
		temp := map[string]interface{}{
			"id":   zone.ID,
			"name": zone.Name,
		}
		res = append(res, temp)
	}
	return res
}

func flattenZonesInResource(zones []account.ZoneID) []int64 {
	res := make([]int64, 0)
	for _, zone := range zones {
		res = append(res, zone.ID)
	}
	return res
}
