package schemas

import (
	"github.com/hashicorp/terraform-plugin-framework-validators/listvalidator"
	"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
	"github.com/hashicorp/terraform-plugin-framework/resource/schema"
	"github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
	"github.com/hashicorp/terraform-plugin-framework/resource/schema/int64default"
	"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
	"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
	"github.com/hashicorp/terraform-plugin-framework/schema/validator"
	"github.com/hashicorp/terraform-plugin-framework/types"
)

func MakeSchemaResourceRG() map[string]schema.Attribute {
	return map[string]schema.Attribute{
		// required attributes
		"account_id": schema.Int64Attribute{
			Required:    true,
			Description: "account, which will own this resource group",
		},
		"gid": schema.Int64Attribute{
			Required:    true,
			Description: "grid id",
		},
		"rg_name": schema.StringAttribute{
			Required:    true,
			Description: "name of this RG. Must be unique within the account.",
		},

		// optional attributes
		"def_net_type": schema.StringAttribute{
			// attribute is only Optional (not Computed) on purpose. If Computed is added, errors occur during Create and
			// Update of the resource in case "def_net"."net_type" is different from "def_net_type". Terraform framework
			// produces "Error: Provider produced inconsistent results after apply" if plan values and resulting values
			// are different, and this is exactly what happens if Computed and Optional field can be updated indirectly
			// (via "def_net","net_type" in our case).
			Optional:    true,
			Description: "type of the default network for this RG. VMs created in this RG will be by default connected to this network. Allowed values are PRIVATE, PUBLIC, NONE.",
			Validators: []validator.String{
				stringvalidator.OneOf("PRIVATE", "PUBLIC", "NONE"), // case is not ignored
			},
			// default value is "PRIVATE".
		},
		"ipcidr": schema.StringAttribute{
			Optional:    true,
			Description: "private network IP CIDR if default network PRIVATE",
		},
		"ext_net_id": schema.Int64Attribute{
			Optional:    true,
			Computed:    true,
			Description: "external network id",
			Default:     int64default.StaticInt64(0),
			// default value is 0.
		},
		"ext_ip": schema.StringAttribute{
			Optional:    true,
			Description: "IP address on the external network to request when def_net_type=PRIVATE and ext_net_id is not 0.",
		},
		"owner": schema.StringAttribute{
			Optional:    true,
			Description: "username - owner of this RG. Leave blank to set current user as owner",
		},
		"resource_limits": schema.SingleNestedAttribute{
			Optional:    true,
			Computed:    true,
			Description: "Quota settings for this resource group.",
			Attributes: map[string]schema.Attribute{
				"cu_c": schema.Float64Attribute{
					Optional:    true,
					Computed:    true,
					Description: "Limit on the total number of CPUs in this resource group.",
				},
				"cu_d": schema.Float64Attribute{
					Computed: true,
				},
				"cu_dm": schema.Float64Attribute{
					Optional:    true,
					Computed:    true,
					Description: "Limit on the total volume of storage resources in this resource group, specified in GB.",
				},
				"cu_i": schema.Float64Attribute{
					Optional:    true,
					Computed:    true,
					Description: "Limit on the total number of external IP addresses this resource group can use.",
				},
				"cu_m": schema.Float64Attribute{
					Optional:    true,
					Computed:    true,
					Description: "Limit on the total amount of RAM in this resource group, specified in MB.",
				},
				"cu_np": schema.Float64Attribute{
					Optional:    true,
					Computed:    true,
					Description: "Limit on the total ingress network traffic for this resource group, specified in GB.",
				},
				"gpu_units": schema.Float64Attribute{
					Computed: true,
				},
			},
		},
		"access": schema.ListNestedAttribute{
			Optional:    true,
			Description: "Grant/revoke user or group access to the Resource group as specified",
			NestedObject: schema.NestedAttributeObject{
				Attributes: map[string]schema.Attribute{
					"user": schema.StringAttribute{
						Required:    true,
						Description: "User or group name to grant access",
					},
					"right": schema.StringAttribute{
						Required:    true,
						Description: "Access rights to set, one of 'R', 'RCX' or 'ARCXDU'",
					},
				},
			},
		},
		"def_net": schema.SingleNestedAttribute{
			Optional:    true,
			Description: "Set default network for attach associated VMs",
			Attributes: map[string]schema.Attribute{
				"net_type": schema.StringAttribute{
					Required: true,
					Validators: []validator.String{
						stringvalidator.OneOf("PRIVATE", "PUBLIC"), // case is not ignored
					},
					Description: "Network type to set. Must be on of 'PRIVATE' or 'PUBLIC'.",
				},
				"net_id": schema.Int64Attribute{
					Optional:    true,
					Description: "Network segment ID. If netType is PUBLIC and netId is 0 then default external network segment will be selected. If netType is PRIVATE and netId=0, the first ViNS defined for this RG will be selected. Otherwise, netId identifies either existing external network segment or ViNS.",
					// default value is 0
				},
			},
		},
		"description": schema.StringAttribute{
			Optional:    true,
			Description: "User-defined text description of this resource group.",
		},
		"force": schema.BoolAttribute{
			Optional:    true,
			Computed:    true,
			Description: "Set to True if you want force delete non-empty RG",
			Default:     booldefault.StaticBool(true),
			// default value is true
		},
		"permanently": schema.BoolAttribute{
			Optional:    true,
			Computed:    true,
			Description: "Set to True if you want force delete non-empty RG",
			Default:     booldefault.StaticBool(true),
			// default value is true
		},
		"register_computes": schema.BoolAttribute{
			Optional:    true,
			Computed:    true,
			Description: "Register computes in registration system",
			Default:     booldefault.StaticBool(false),
			// default value is false
		},
		"restore": schema.BoolAttribute{
			Optional: true,
			Computed: true,
			Default:  booldefault.StaticBool(true),
			// default value is true
		},
		"enable": schema.BoolAttribute{
			Optional:    true,
			Computed:    true,
			Description: "flag for enable/disable RG",
			Default:     booldefault.StaticBool(true),
			// default value is true
		},
		"uniq_pools": schema.ListAttribute{
			Optional:    true,
			ElementType: types.StringType,
			Description: "List of strings with pools i.e.: [\"sep1_poolName1\", \"sep2_poolName2\"]",
		},
		"cpu_allocation_parameter": schema.StringAttribute{
			Computed:    true,
			Optional:    true,
			Description: "set cpu allocation parameter",
			Validators: []validator.String{
				stringvalidator.OneOf("strict", "loose"), // case is not ignored
			},
		},
		"cpu_allocation_ratio": schema.Float64Attribute{
			Computed:    true,
			Optional:    true,
			Description: "set cpu allocation ratio",
		},
		"compute_features": schema.ListAttribute{
			Optional:    true,
			ElementType: types.StringType,
			Validators: []validator.List{
				listvalidator.ValueStringsAre(stringvalidator.OneOf("hugepages", "numa", "cpupin", "vfnic")),
			},
		},

		// computed attributes
		"rg_id": schema.Int64Attribute{
			Computed: true,
		},
		"last_updated": schema.StringAttribute{
			Computed: true,
		},
		"account_name": schema.StringAttribute{
			Computed: true,
		},
		"acl": schema.ListNestedAttribute{
			Computed: true,
			NestedObject: schema.NestedAttributeObject{
				Attributes: map[string]schema.Attribute{
					"explicit": schema.BoolAttribute{
						Computed: true,
					},
					"guid": schema.StringAttribute{
						Computed: true,
					},
					"right": schema.StringAttribute{
						Computed: true,
					},
					"status": schema.StringAttribute{
						Computed: true,
					},
					"type": schema.StringAttribute{
						Computed: true,
					},
					"user_group_id": schema.StringAttribute{
						Computed: true,
					},
				},
			},
		},
		"created_by": schema.StringAttribute{
			Computed: true,
		},
		"created_time": schema.Int64Attribute{
			Computed: true,
		},
		"def_net_id": schema.Int64Attribute{
			Computed: true,
		},
		"deleted_by": schema.StringAttribute{
			Computed: true,
		},
		"deleted_time": schema.Int64Attribute{
			Computed: true,
		},
		"guid": schema.Int64Attribute{
			Computed: true,
		},
		"id": schema.StringAttribute{
			Computed: true,
			PlanModifiers: []planmodifier.String{
				stringplanmodifier.UseStateForUnknown(),
			},
		},
		"lock_status": schema.StringAttribute{
			Computed: true,
		},
		"milestones": schema.Int64Attribute{
			Computed: true,
		},
		"secret": schema.StringAttribute{
			Computed: true,
		},
		"status": schema.StringAttribute{
			Computed: true,
		},
		"updated_by": schema.StringAttribute{
			Computed: true,
		},
		"updated_time": schema.Int64Attribute{
			Computed: true,
		},
		"resource_types": schema.ListAttribute{
			Computed:    true,
			ElementType: types.StringType,
		},
		"vins": schema.ListAttribute{
			Computed:    true,
			ElementType: types.Int64Type,
		},
		"vms": schema.ListAttribute{
			Computed:    true,
			ElementType: types.Int64Type,
		},
	}
}
