// Code generated by "gen/generator.go"; DO NOT EDIT.
// In order to regenerate this file execute `go generate` from the repository root.
// More details can be found in the [README](https://github.com/CiscoDevNet/terraform-provider-aci/blob/master/README.md).

package provider

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

	"github.com/ciscoecosystem/aci-go-client/v2/client"
	"github.com/ciscoecosystem/aci-go-client/v2/container"
	"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
	"github.com/hashicorp/terraform-plugin-framework/attr"
	"github.com/hashicorp/terraform-plugin-framework/diag"
	"github.com/hashicorp/terraform-plugin-framework/path"
	"github.com/hashicorp/terraform-plugin-framework/resource"
	"github.com/hashicorp/terraform-plugin-framework/resource/schema"
	"github.com/hashicorp/terraform-plugin-framework/resource/schema/objectplanmodifier"
	"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
	"github.com/hashicorp/terraform-plugin-framework/resource/schema/setplanmodifier"
	"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault"
	"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
	"github.com/hashicorp/terraform-plugin-framework/schema/validator"
	"github.com/hashicorp/terraform-plugin-framework/types"
	"github.com/hashicorp/terraform-plugin-framework/types/basetypes"
	"github.com/hashicorp/terraform-plugin-log/tflog"
)

// Ensure provider defined types fully satisfy framework interfaces.
var _ resource.Resource = &FvTenantResource{}
var _ resource.ResourceWithImportState = &FvTenantResource{}

func NewFvTenantResource() resource.Resource {
	return &FvTenantResource{}
}

// FvTenantResource defines the resource implementation.
type FvTenantResource struct {
	client *client.Client
}

// FvTenantResourceModel describes the resource data model.
type FvTenantResourceModel struct {
	Id                                  types.String `tfsdk:"id"`
	Annotation                          types.String `tfsdk:"annotation"`
	Descr                               types.String `tfsdk:"description"`
	Name                                types.String `tfsdk:"name"`
	NameAlias                           types.String `tfsdk:"name_alias"`
	OwnerKey                            types.String `tfsdk:"owner_key"`
	OwnerTag                            types.String `tfsdk:"owner_tag"`
	FvRsTenantMonPol                    types.Object `tfsdk:"relation_to_monitoring_policy"`
	TagAnnotation                       types.Set    `tfsdk:"annotations"`
	TagTag                              types.Set    `tfsdk:"tags"`
	DeprecatedFvRsTenantMonPol          types.String `tfsdk:"relation_fv_rs_tenant_mon_pol"`
	Ignored_relation_fv_rs_tn_deny_rule types.Set    `tfsdk:"relation_fv_rs_tn_deny_rule"`
}

func getEmptyFvTenantResourceModel() *FvTenantResourceModel {
	return &FvTenantResourceModel{
		Id:         basetypes.NewStringNull(),
		Annotation: basetypes.NewStringNull(),
		Descr:      basetypes.NewStringNull(),
		Name:       basetypes.NewStringNull(),
		NameAlias:  basetypes.NewStringNull(),
		OwnerKey:   basetypes.NewStringNull(),
		OwnerTag:   basetypes.NewStringNull(),
		FvRsTenantMonPol: types.ObjectNull(map[string]attr.Type{
			"annotation":             types.StringType,
			"monitoring_policy_name": types.StringType,
			"annotations":            types.SetType{ElemType: TagAnnotationFvRsTenantMonPolFvTenantType},
			"tags":                   types.SetType{ElemType: TagTagFvRsTenantMonPolFvTenantType},
		}),
		TagAnnotation: types.SetNull(types.ObjectType{
			AttrTypes: map[string]attr.Type{
				"key":   types.StringType,
				"value": types.StringType,
			},
		}),
		TagTag: types.SetNull(types.ObjectType{
			AttrTypes: map[string]attr.Type{
				"key":   types.StringType,
				"value": types.StringType,
			},
		}),
		DeprecatedFvRsTenantMonPol:          types.String{},
		Ignored_relation_fv_rs_tn_deny_rule: types.SetNull(types.StringType),
	}
}

// FvRsTenantMonPolFvTenantResourceModel describes the resource data model for the children without relation ships.
type FvRsTenantMonPolFvTenantResourceModel struct {
	Annotation      types.String `tfsdk:"annotation"`
	TnMonEPGPolName types.String `tfsdk:"monitoring_policy_name"`
	TagAnnotation   types.Set    `tfsdk:"annotations"`
	TagTag          types.Set    `tfsdk:"tags"`
}

func getEmptyFvRsTenantMonPolFvTenantResourceModel() FvRsTenantMonPolFvTenantResourceModel {
	return FvRsTenantMonPolFvTenantResourceModel{
		Annotation:      basetypes.NewStringNull(),
		TnMonEPGPolName: basetypes.NewStringNull(),
		TagAnnotation: types.SetNull(types.ObjectType{
			AttrTypes: map[string]attr.Type{
				"key":   types.StringType,
				"value": types.StringType,
			},
		}),
		TagTag: types.SetNull(types.ObjectType{
			AttrTypes: map[string]attr.Type{
				"key":   types.StringType,
				"value": types.StringType,
			},
		}),
	}
}

var FvRsTenantMonPolFvTenantType = map[string]attr.Type{
	"annotation":             types.StringType,
	"monitoring_policy_name": types.StringType,
	"annotations":            types.SetType{ElemType: TagAnnotationFvRsTenantMonPolFvTenantType},
	"tags":                   types.SetType{ElemType: TagTagFvRsTenantMonPolFvTenantType},
}

// TagAnnotationFvRsTenantMonPolFvTenantResourceModel describes the resource data model for the children without relation ships.
type TagAnnotationFvRsTenantMonPolFvTenantResourceModel struct {
	Key   types.String `tfsdk:"key"`
	Value types.String `tfsdk:"value"`
}

func getEmptyTagAnnotationFvRsTenantMonPolFvTenantResourceModel() TagAnnotationFvRsTenantMonPolFvTenantResourceModel {
	return TagAnnotationFvRsTenantMonPolFvTenantResourceModel{
		Key:   basetypes.NewStringNull(),
		Value: basetypes.NewStringNull(),
	}
}

var TagAnnotationFvRsTenantMonPolFvTenantType = types.ObjectType{
	AttrTypes: map[string]attr.Type{
		"key":   types.StringType,
		"value": types.StringType,
	},
}

// TagTagFvRsTenantMonPolFvTenantResourceModel describes the resource data model for the children without relation ships.
type TagTagFvRsTenantMonPolFvTenantResourceModel struct {
	Key   types.String `tfsdk:"key"`
	Value types.String `tfsdk:"value"`
}

func getEmptyTagTagFvRsTenantMonPolFvTenantResourceModel() TagTagFvRsTenantMonPolFvTenantResourceModel {
	return TagTagFvRsTenantMonPolFvTenantResourceModel{
		Key:   basetypes.NewStringNull(),
		Value: basetypes.NewStringNull(),
	}
}

var TagTagFvRsTenantMonPolFvTenantType = types.ObjectType{
	AttrTypes: map[string]attr.Type{
		"key":   types.StringType,
		"value": types.StringType,
	},
}

// TagAnnotationFvTenantResourceModel describes the resource data model for the children without relation ships.
type TagAnnotationFvTenantResourceModel struct {
	Key   types.String `tfsdk:"key"`
	Value types.String `tfsdk:"value"`
}

func getEmptyTagAnnotationFvTenantResourceModel() TagAnnotationFvTenantResourceModel {
	return TagAnnotationFvTenantResourceModel{
		Key:   basetypes.NewStringNull(),
		Value: basetypes.NewStringNull(),
	}
}

var TagAnnotationFvTenantType = types.ObjectType{
	AttrTypes: map[string]attr.Type{
		"key":   types.StringType,
		"value": types.StringType,
	},
}

// TagTagFvTenantResourceModel describes the resource data model for the children without relation ships.
type TagTagFvTenantResourceModel struct {
	Key   types.String `tfsdk:"key"`
	Value types.String `tfsdk:"value"`
}

func getEmptyTagTagFvTenantResourceModel() TagTagFvTenantResourceModel {
	return TagTagFvTenantResourceModel{
		Key:   basetypes.NewStringNull(),
		Value: basetypes.NewStringNull(),
	}
}

var TagTagFvTenantType = types.ObjectType{
	AttrTypes: map[string]attr.Type{
		"key":   types.StringType,
		"value": types.StringType,
	},
}

type FvTenantIdentifier struct {
	Name types.String
}

type FvTenantResourceModelV1 struct {
	Annotation                          types.String `tfsdk:"annotation"`
	Descr                               types.String `tfsdk:"description"`
	Id                                  types.String `tfsdk:"id"`
	Name                                types.String `tfsdk:"name"`
	NameAlias                           types.String `tfsdk:"name_alias"`
	FvRsTenantMonPol                    types.String `tfsdk:"relation_fv_rs_tenant_mon_pol"`
	Ignored_relation_fv_rs_tn_deny_rule types.Set    `tfsdk:"relation_fv_rs_tn_deny_rule"`
}

func (r *FvTenantResource) UpgradeState(ctx context.Context) map[int64]resource.StateUpgrader {
	return map[int64]resource.StateUpgrader{
		1: {
			PriorSchema: &schema.Schema{
				Attributes: map[string]schema.Attribute{
					"annotation": schema.StringAttribute{
						Required: false,
						Optional: true,
						Computed: true,
					},
					"description": schema.StringAttribute{
						Required: false,
						Optional: true,
						Computed: true,
					},
					"id": schema.StringAttribute{
						Required: false,
						Optional: true,
						Computed: true,
					},
					"name": schema.StringAttribute{
						Required: true,
						Optional: false,
						Computed: false,
					},
					"name_alias": schema.StringAttribute{
						Required: false,
						Optional: true,
						Computed: true,
					},
					"relation_fv_rs_tenant_mon_pol": schema.StringAttribute{
						Required: false,
						Optional: true,
						Computed: true,
					},
					"relation_fv_rs_tn_deny_rule": schema.SetAttribute{
						Required:    false,
						Optional:    true,
						Computed:    false,
						ElementType: types.StringType,
					},
				},
				Blocks: map[string]schema.Block{},
			},
			StateUpgrader: func(ctx context.Context, req resource.UpgradeStateRequest, resp *resource.UpgradeStateResponse) {
				var priorStateData FvTenantResourceModelV1

				resp.Diagnostics.Append(req.State.Get(ctx, &priorStateData)...)

				if resp.Diagnostics.HasError() {
					return
				}

				upgradedStateData := FvTenantResourceModel{
					Id:                                  priorStateData.Id,
					Annotation:                          priorStateData.Annotation,
					Descr:                               priorStateData.Descr,
					Name:                                priorStateData.Name,
					NameAlias:                           priorStateData.NameAlias,
					OwnerKey:                            basetypes.NewStringNull(),
					OwnerTag:                            basetypes.NewStringNull(),
					DeprecatedFvRsTenantMonPol:          priorStateData.FvRsTenantMonPol,
					Ignored_relation_fv_rs_tn_deny_rule: priorStateData.Ignored_relation_fv_rs_tn_deny_rule,
				}

				FvRsTenantMonPolObject := FvRsTenantMonPolFvTenantResourceModel{
					Annotation:      basetypes.NewStringNull(),
					TnMonEPGPolName: basetypes.NewStringValue(GetMOName(priorStateData.FvRsTenantMonPol.ValueString())),
					TagAnnotation: basetypes.NewSetNull(types.ObjectType{
						AttrTypes: map[string]attr.Type{
							"key":   types.StringType,
							"value": types.StringType,
						},
					}),
					TagTag: basetypes.NewSetNull(types.ObjectType{
						AttrTypes: map[string]attr.Type{
							"key":   types.StringType,
							"value": types.StringType,
						},
					}),
				}
				fvRsTenantMonPolObject, _ := types.ObjectValueFrom(ctx, FvRsTenantMonPolFvTenantType, FvRsTenantMonPolObject)
				upgradedStateData.FvRsTenantMonPol = fvRsTenantMonPolObject

				upgradedStateData.TagAnnotation = types.SetNull(
					types.ObjectType{
						AttrTypes: map[string]attr.Type{
							"key":   basetypes.StringType{},
							"value": basetypes.StringType{},
						},
					},
				)

				upgradedStateData.TagTag = types.SetNull(
					types.ObjectType{
						AttrTypes: map[string]attr.Type{
							"key":   basetypes.StringType{},
							"value": basetypes.StringType{},
						},
					},
				)

				resp.Diagnostics.Append(resp.State.Set(ctx, upgradedStateData)...)
			},
		},
	}
}

func setFvTenantLegacyAttributes(ctx context.Context, diags *diag.Diagnostics, data, staticData *FvTenantResourceModel, classReadInfo []interface{}) {
	if !staticData.Ignored_relation_fv_rs_tn_deny_rule.IsUnknown() && !staticData.Ignored_relation_fv_rs_tn_deny_rule.IsNull() {
		data.Ignored_relation_fv_rs_tn_deny_rule = staticData.Ignored_relation_fv_rs_tn_deny_rule
	} else {
		Ignored_relation_fv_rs_tn_deny_ruleSet, _ := types.SetValueFrom(ctx, types.StringType, []string{})
		data.Ignored_relation_fv_rs_tn_deny_rule = Ignored_relation_fv_rs_tn_deny_ruleSet
	}
	data.DeprecatedFvRsTenantMonPol = basetypes.NewStringNull()

	_, ok := classReadInfo[0].(map[string]interface{})["children"]
	if ok {
		children := classReadInfo[0].(map[string]interface{})["children"].([]interface{})
		for _, child := range children {
			for childClassName, childClassDetails := range child.(map[string]interface{}) {
				childAttributes := childClassDetails.(map[string]interface{})["attributes"].(map[string]interface{})
				if childClassName == "fvRsTenantMonPol" {
					for childAttributeName, childAttributeValue := range childAttributes {
						if childAttributeName == "tDn" {
							data.DeprecatedFvRsTenantMonPol = basetypes.NewStringValue(childAttributeValue.(string))
						}
					}
				}
			}
		}
	}
}

func (r *FvTenantResource) ModifyPlan(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) {
	if !req.Plan.Raw.IsNull() {
		var planData, stateData, configData *FvTenantResourceModel
		resp.Diagnostics.Append(req.Plan.Get(ctx, &planData)...)
		resp.Diagnostics.Append(req.State.Get(ctx, &stateData)...)
		resp.Diagnostics.Append(req.Config.Get(ctx, &configData)...)

		if resp.Diagnostics.HasError() {
			return
		}

		if (planData.Id.IsUnknown() || planData.Id.IsNull()) && !planData.Name.IsUnknown() {
			setFvTenantId(ctx, planData)
		}

		if stateData == nil && !globalAllowExistingOnCreate && !planData.Id.IsUnknown() && !planData.Id.IsNull() {
			CheckDn(ctx, &resp.Diagnostics, r.client, "fvTenant", planData.Id.ValueString())
			if resp.Diagnostics.HasError() {
				return
			}
		}
		if !configData.FvRsTenantMonPol.IsNull() && stateData != nil {
			if IsEmptySingleNestedAttribute(configData.FvRsTenantMonPol.Attributes()) {
				FvRsTenantMonPolObject, _ := types.ObjectValueFrom(ctx, FvRsTenantMonPolFvTenantType, getEmptyFvRsTenantMonPolFvTenantResourceModel())
				planData.FvRsTenantMonPol = FvRsTenantMonPolObject
			}
		}

		if !configData.DeprecatedFvRsTenantMonPol.IsNull() {
			var newAttributeValues FvRsTenantMonPolFvTenantResourceModel
			tagAnnotationFvRsTenantMonPolFvTenantValue, _ := types.SetValueFrom(ctx, TagAnnotationFvRsTenantMonPolFvTenantType, make([]TagAnnotationFvRsTenantMonPolFvTenantResourceModel, 0))
			tagTagFvRsTenantMonPolFvTenantValue, _ := types.SetValueFrom(ctx, TagTagFvRsTenantMonPolFvTenantType, make([]TagTagFvRsTenantMonPolFvTenantResourceModel, 0))
			annotationValue := planData.Annotation
			if stateData != nil && !IsEmptySingleNestedAttribute(stateData.FvRsTenantMonPol.Attributes()) {
				stateData.FvRsTenantMonPol.As(ctx, &newAttributeValues, basetypes.ObjectAsOptions{})
				annotationValue = newAttributeValues.Annotation
				tagAnnotationFvRsTenantMonPolFvTenantValue = newAttributeValues.TagAnnotation
				tagTagFvRsTenantMonPolFvTenantValue = newAttributeValues.TagTag
			}
			tnMonEPGPolNameValue := basetypes.NewStringUnknown()
			if !configData.DeprecatedFvRsTenantMonPol.IsUnknown() {
				tnMonEPGPolNameValue = basetypes.NewStringValue(GetMOName(configData.DeprecatedFvRsTenantMonPol.ValueString()))
			}
			FvRsTenantMonPol := FvRsTenantMonPolFvTenantResourceModel{
				Annotation:      annotationValue,
				TnMonEPGPolName: tnMonEPGPolNameValue,
				TagAnnotation:   tagAnnotationFvRsTenantMonPolFvTenantValue,
				TagTag:          tagTagFvRsTenantMonPolFvTenantValue,
			}
			FvRsTenantMonPolObject, _ := types.ObjectValueFrom(ctx, FvRsTenantMonPolFvTenantType, FvRsTenantMonPol)
			planData.FvRsTenantMonPol = FvRsTenantMonPolObject
		}

		// Workaround to compare the state with plan to avoid plan changes with only known after apply
		if stateData != nil {
			avoidFvTenantPlanChangeForKnownAfterApplyOnly(ctx, planData, stateData, configData)
		}

		resp.Diagnostics.Append(resp.Plan.Set(ctx, &planData)...)
	}
}

func avoidFvTenantPlanChangeForKnownAfterApplyOnly(ctx context.Context, planData, stateData, configData *FvTenantResourceModel) {
	// Set read-only and deprecated attributes in planData from stateData
	if configData.DeprecatedFvRsTenantMonPol.IsNull() {
		planData.DeprecatedFvRsTenantMonPol = stateData.DeprecatedFvRsTenantMonPol
	}

	// Compare the string representation of the planData and stateData because structs cannot be compared directly
	if fmt.Sprintf("%s", planData) != fmt.Sprintf("%s", stateData) {
		if configData.DeprecatedFvRsTenantMonPol.IsNull() {
			planData.DeprecatedFvRsTenantMonPol = basetypes.NewStringUnknown()
		}
	}
}

func (r *FvTenantResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
	tflog.Debug(ctx, "Start metadata of resource: aci_tenant")
	resp.TypeName = req.ProviderTypeName + "_tenant"
	tflog.Debug(ctx, "End metadata of resource: aci_tenant")
}

func (r *FvTenantResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
	tflog.Debug(ctx, "Start schema of resource: aci_tenant")
	resp.Schema = schema.Schema{
		// This description is used by the documentation generator and the language server.
		MarkdownDescription: "The tenant resource for the 'fvTenant' class",
		Version:             2,

		Attributes: map[string]schema.Attribute{
			// Deprecated attributes
			"relation_fv_rs_tenant_mon_pol": schema.StringAttribute{
				Optional:           true,
				Computed:           true,
				DeprecationMessage: "Attribute 'relation_fv_rs_tenant_mon_pol' is deprecated, please refer to 'relation_to_monitoring_policy' instead. The attribute will be removed in the next major version of the provider.",
				Validators: []validator.String{
					stringvalidator.ConflictsWith(path.Expressions{
						path.MatchRoot("relation_to_monitoring_policy"),
					}...),
				},
			},
			"relation_fv_rs_tn_deny_rule": schema.SetAttribute{
				Optional:           true,
				Computed:           true,
				ElementType:        types.StringType,
				DeprecationMessage: "Attribute `relation_fv_rs_tn_deny_rule` is deprecated. The configuration was not functioning as intended because the Managed Object (MO) created by the pre-migrated resource was either configured incorrectly or exposed without any implemented functionality on the APIC. The MO for this attribute is no longer created on the APIC, but the existing MO will remain present until the resource is destroyed. This attribute will be removed in the next major version of the provider.",
				PlanModifiers: []planmodifier.Set{
					setplanmodifier.UseStateForUnknown(),
				},
			},
			// End of deprecated attributes
			"id": schema.StringAttribute{
				Computed:            true,
				MarkdownDescription: "The distinguished name (DN) of the Tenant object.",
				PlanModifiers: []planmodifier.String{
					stringplanmodifier.UseStateForUnknown(),
				},
			},
			"annotation": schema.StringAttribute{
				Optional: true,
				Computed: true,
				PlanModifiers: []planmodifier.String{
					stringplanmodifier.UseStateForUnknown(),
					SetToStringNullWhenStateIsNullPlanIsUnknownDuringUpdate(),
				},
				Default:             stringdefault.StaticString(globalAnnotation),
				MarkdownDescription: `The annotation of the Tenant object.`,
			},
			"description": schema.StringAttribute{
				Optional: true,
				Computed: true,
				PlanModifiers: []planmodifier.String{
					stringplanmodifier.UseStateForUnknown(),
					SetToStringNullWhenStateIsNullPlanIsUnknownDuringUpdate(),
				},
				MarkdownDescription: `The description of the Tenant object.`,
			},
			"name": schema.StringAttribute{
				Required: true,
				PlanModifiers: []planmodifier.String{
					stringplanmodifier.UseStateForUnknown(),
					SetToStringNullWhenStateIsNullPlanIsUnknownDuringUpdate(),
					stringplanmodifier.RequiresReplace(),
				},
				MarkdownDescription: `The name of the Tenant object.`,
			},
			"name_alias": schema.StringAttribute{
				Optional: true,
				Computed: true,
				PlanModifiers: []planmodifier.String{
					stringplanmodifier.UseStateForUnknown(),
					SetToStringNullWhenStateIsNullPlanIsUnknownDuringUpdate(),
				},
				MarkdownDescription: `The name alias of the Tenant object.`,
			},
			"owner_key": schema.StringAttribute{
				Optional: true,
				Computed: true,
				PlanModifiers: []planmodifier.String{
					stringplanmodifier.UseStateForUnknown(),
					SetToStringNullWhenStateIsNullPlanIsUnknownDuringUpdate(),
				},
				MarkdownDescription: `The key for enabling clients to own their data for entity correlation.`,
			},
			"owner_tag": schema.StringAttribute{
				Optional: true,
				Computed: true,
				PlanModifiers: []planmodifier.String{
					stringplanmodifier.UseStateForUnknown(),
					SetToStringNullWhenStateIsNullPlanIsUnknownDuringUpdate(),
				},
				MarkdownDescription: `A tag for enabling clients to add their own data. For example, to indicate who created this object.`,
			},
			"relation_to_monitoring_policy": schema.SingleNestedAttribute{
				MarkdownDescription: `A source relation to the monitoring policy model for the endpoint group semantic scope. This is an internal object.`,
				Optional:            true,
				Computed:            true,
				PlanModifiers: []planmodifier.Object{
					objectplanmodifier.UseStateForUnknown(),
				},
				Attributes: map[string]schema.Attribute{
					"annotation": schema.StringAttribute{
						Optional: true,
						Computed: true,
						PlanModifiers: []planmodifier.String{
							stringplanmodifier.UseStateForUnknown(),
						},
						MarkdownDescription: `The annotation of the Relation From Tenant To Monitoring Policy object.`,
					},
					"monitoring_policy_name": schema.StringAttribute{
						Optional: true,
						Computed: true,
						PlanModifiers: []planmodifier.String{
							stringplanmodifier.UseStateForUnknown(),
						},
						MarkdownDescription: `The name of the monitoring policy.`,
					},
					"annotations": schema.SetNestedAttribute{
						MarkdownDescription: ``,
						Optional:            true,
						Computed:            true,
						PlanModifiers: []planmodifier.Set{
							setplanmodifier.UseStateForUnknown(),
						},
						NestedObject: schema.NestedAttributeObject{
							Attributes: map[string]schema.Attribute{
								"key": schema.StringAttribute{
									Required: true,
									PlanModifiers: []planmodifier.String{
										stringplanmodifier.UseStateForUnknown(),
									},
									MarkdownDescription: `The key used to uniquely identify this configuration object.`,
								},
								"value": schema.StringAttribute{
									Required: true,
									PlanModifiers: []planmodifier.String{
										stringplanmodifier.UseStateForUnknown(),
									},
									MarkdownDescription: `The value of the property.`,
								},
							},
						},
					},
					"tags": schema.SetNestedAttribute{
						MarkdownDescription: ``,
						Optional:            true,
						Computed:            true,
						PlanModifiers: []planmodifier.Set{
							setplanmodifier.UseStateForUnknown(),
						},
						NestedObject: schema.NestedAttributeObject{
							Attributes: map[string]schema.Attribute{
								"key": schema.StringAttribute{
									Required: true,
									PlanModifiers: []planmodifier.String{
										stringplanmodifier.UseStateForUnknown(),
									},
									MarkdownDescription: `The key used to uniquely identify this configuration object.`,
								},
								"value": schema.StringAttribute{
									Required: true,
									PlanModifiers: []planmodifier.String{
										stringplanmodifier.UseStateForUnknown(),
									},
									MarkdownDescription: `The value of the property.`,
								},
							},
						},
					},
				},
			},
			"annotations": schema.SetNestedAttribute{
				MarkdownDescription: ``,
				Optional:            true,
				Computed:            true,
				PlanModifiers: []planmodifier.Set{
					setplanmodifier.UseStateForUnknown(),
				},
				NestedObject: schema.NestedAttributeObject{
					Attributes: map[string]schema.Attribute{
						"key": schema.StringAttribute{
							Required: true,
							PlanModifiers: []planmodifier.String{
								stringplanmodifier.UseStateForUnknown(),
							},
							MarkdownDescription: `The key used to uniquely identify this configuration object.`,
						},
						"value": schema.StringAttribute{
							Required: true,
							PlanModifiers: []planmodifier.String{
								stringplanmodifier.UseStateForUnknown(),
							},
							MarkdownDescription: `The value of the property.`,
						},
					},
				},
			},
			"tags": schema.SetNestedAttribute{
				MarkdownDescription: ``,
				Optional:            true,
				Computed:            true,
				PlanModifiers: []planmodifier.Set{
					setplanmodifier.UseStateForUnknown(),
				},
				NestedObject: schema.NestedAttributeObject{
					Attributes: map[string]schema.Attribute{
						"key": schema.StringAttribute{
							Required: true,
							PlanModifiers: []planmodifier.String{
								stringplanmodifier.UseStateForUnknown(),
							},
							MarkdownDescription: `The key used to uniquely identify this configuration object.`,
						},
						"value": schema.StringAttribute{
							Required: true,
							PlanModifiers: []planmodifier.String{
								stringplanmodifier.UseStateForUnknown(),
							},
							MarkdownDescription: `The value of the property.`,
						},
					},
				},
			},
		},
		Blocks: map[string]schema.Block{},
	}
	tflog.Debug(ctx, "End schema of resource: aci_tenant")
}

func (r *FvTenantResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
	tflog.Debug(ctx, "Start configure of resource: aci_tenant")
	// Prevent panic if the provider has not been configured.
	if req.ProviderData == nil {
		return
	}

	client, ok := req.ProviderData.(*client.Client)

	if !ok {
		resp.Diagnostics.AddError(
			"Unexpected Resource Configure Type",
			fmt.Sprintf("Expected *client.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData),
		)

		return
	}

	r.client = client
	tflog.Debug(ctx, "End configure of resource: aci_tenant")
}

func (r *FvTenantResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
	tflog.Debug(ctx, "Start create of resource: aci_tenant")
	// On create retrieve information on current state prior to making any changes in order to determine child delete operations
	var stateData *FvTenantResourceModel
	resp.Diagnostics.Append(req.Plan.Get(ctx, &stateData)...)
	if stateData.Id.IsUnknown() || stateData.Id.IsNull() {
		setFvTenantId(ctx, stateData)
	}
	getAndSetFvTenantAttributes(ctx, &resp.Diagnostics, r.client, stateData)
	if !globalAllowExistingOnCreate && !stateData.Id.IsNull() {
		resp.Diagnostics.AddError(
			"Object Already Exists",
			fmt.Sprintf("The fvTenant object with DN '%s' already exists.", stateData.Id.ValueString()),
		)
		return
	}

	var data *FvTenantResourceModel

	// Read Terraform plan data into the model
	resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)

	if resp.Diagnostics.HasError() {
		return
	}

	if data.Id.IsUnknown() || data.Id.IsNull() {
		setFvTenantId(ctx, data)
	}

	tflog.Debug(ctx, fmt.Sprintf("Create of resource aci_tenant with id '%s'", data.Id.ValueString()))

	var fvRsTenantMonPolPlan, fvRsTenantMonPolState FvRsTenantMonPolFvTenantResourceModel
	data.FvRsTenantMonPol.As(ctx, &fvRsTenantMonPolPlan, basetypes.ObjectAsOptions{})
	stateData.FvRsTenantMonPol.As(ctx, &fvRsTenantMonPolState, basetypes.ObjectAsOptions{})
	var tagAnnotationPlan, tagAnnotationState []TagAnnotationFvTenantResourceModel
	data.TagAnnotation.ElementsAs(ctx, &tagAnnotationPlan, false)
	stateData.TagAnnotation.ElementsAs(ctx, &tagAnnotationState, false)
	var tagTagPlan, tagTagState []TagTagFvTenantResourceModel
	data.TagTag.ElementsAs(ctx, &tagTagPlan, false)
	stateData.TagTag.ElementsAs(ctx, &tagTagState, false)
	jsonPayload := getFvTenantCreateJsonPayload(ctx, &resp.Diagnostics, true, data, fvRsTenantMonPolPlan, fvRsTenantMonPolState, tagAnnotationPlan, tagAnnotationState, tagTagPlan, tagTagState)

	if resp.Diagnostics.HasError() {
		return
	}

	DoRestRequest(ctx, &resp.Diagnostics, r.client, fmt.Sprintf("api/mo/%s.json", data.Id.ValueString()), "POST", jsonPayload)

	if resp.Diagnostics.HasError() {
		return
	}

	getAndSetFvTenantAttributes(ctx, &resp.Diagnostics, r.client, data)

	// Save data into Terraform state
	resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
	tflog.Debug(ctx, fmt.Sprintf("End create of resource aci_tenant with id '%s'", data.Id.ValueString()))
}

func (r *FvTenantResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
	tflog.Debug(ctx, "Start read of resource: aci_tenant")
	var data *FvTenantResourceModel

	// Read Terraform prior state data into the model
	resp.Diagnostics.Append(req.State.Get(ctx, &data)...)

	if resp.Diagnostics.HasError() {
		return
	}

	tflog.Debug(ctx, fmt.Sprintf("Read of resource aci_tenant with id '%s'", data.Id.ValueString()))

	getAndSetFvTenantAttributes(ctx, &resp.Diagnostics, r.client, data)

	// Save updated data into Terraform state
	if data.Id.IsNull() {
		var emptyData *FvTenantResourceModel
		resp.Diagnostics.Append(resp.State.Set(ctx, &emptyData)...)
	} else {
		resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
	}

	tflog.Debug(ctx, fmt.Sprintf("End read of resource aci_tenant with id '%s'", data.Id.ValueString()))
}

func (r *FvTenantResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
	tflog.Debug(ctx, "Start update of resource: aci_tenant")
	var data *FvTenantResourceModel
	var stateData *FvTenantResourceModel

	// Read Terraform plan data into the model
	resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
	resp.Diagnostics.Append(req.State.Get(ctx, &stateData)...)
	// Error out when child object fvRsTenantMonPol is being deleted
	if IsEmptySingleNestedAttribute(data.FvRsTenantMonPol.Attributes()) && !IsEmptySingleNestedAttribute(stateData.FvRsTenantMonPol.Attributes()) {
		resp.Diagnostics.AddError(
			"FvRsTenantMonPol object cannot be deleted",
			"deletion of child is only possible upon deletion of the parent",
		)
	}

	if resp.Diagnostics.HasError() {
		return
	}

	tflog.Debug(ctx, fmt.Sprintf("Update of resource aci_tenant with id '%s'", data.Id.ValueString()))

	var fvRsTenantMonPolPlan, fvRsTenantMonPolState FvRsTenantMonPolFvTenantResourceModel
	data.FvRsTenantMonPol.As(ctx, &fvRsTenantMonPolPlan, basetypes.ObjectAsOptions{})
	stateData.FvRsTenantMonPol.As(ctx, &fvRsTenantMonPolState, basetypes.ObjectAsOptions{})
	var tagAnnotationPlan, tagAnnotationState []TagAnnotationFvTenantResourceModel
	data.TagAnnotation.ElementsAs(ctx, &tagAnnotationPlan, false)
	stateData.TagAnnotation.ElementsAs(ctx, &tagAnnotationState, false)
	var tagTagPlan, tagTagState []TagTagFvTenantResourceModel
	data.TagTag.ElementsAs(ctx, &tagTagPlan, false)
	stateData.TagTag.ElementsAs(ctx, &tagTagState, false)
	jsonPayload := getFvTenantCreateJsonPayload(ctx, &resp.Diagnostics, false, data, fvRsTenantMonPolPlan, fvRsTenantMonPolState, tagAnnotationPlan, tagAnnotationState, tagTagPlan, tagTagState)

	if resp.Diagnostics.HasError() {
		return
	}

	DoRestRequest(ctx, &resp.Diagnostics, r.client, fmt.Sprintf("api/mo/%s.json", data.Id.ValueString()), "POST", jsonPayload)

	if resp.Diagnostics.HasError() {
		return
	}

	getAndSetFvTenantAttributes(ctx, &resp.Diagnostics, r.client, data)

	// Save updated data into Terraform state
	resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
	tflog.Debug(ctx, fmt.Sprintf("End update of resource aci_tenant with id '%s'", data.Id.ValueString()))
}

func (r *FvTenantResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
	tflog.Debug(ctx, "Start delete of resource: aci_tenant")
	var data *FvTenantResourceModel

	// Read Terraform prior state data into the model
	resp.Diagnostics.Append(req.State.Get(ctx, &data)...)

	if resp.Diagnostics.HasError() {
		return
	}

	tflog.Debug(ctx, fmt.Sprintf("Delete of resource aci_tenant with id '%s'", data.Id.ValueString()))
	jsonPayload := GetDeleteJsonPayload(ctx, &resp.Diagnostics, "fvTenant", data.Id.ValueString())
	if resp.Diagnostics.HasError() {
		return
	}
	DoRestRequest(ctx, &resp.Diagnostics, r.client, fmt.Sprintf("api/mo/%s.json", data.Id.ValueString()), "POST", jsonPayload)
	if resp.Diagnostics.HasError() {
		return
	}
	tflog.Debug(ctx, fmt.Sprintf("End delete of resource aci_tenant with id '%s'", data.Id.ValueString()))
}

func (r *FvTenantResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
	tflog.Debug(ctx, "Start import state of resource: aci_tenant")
	resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)

	var stateData *FvTenantResourceModel
	resp.Diagnostics.Append(resp.State.Get(ctx, &stateData)...)
	tflog.Debug(ctx, fmt.Sprintf("Import state of resource aci_tenant with id '%s'", stateData.Id.ValueString()))

	tflog.Debug(ctx, "End import of state resource: aci_tenant")
}

func getAndSetFvTenantAttributes(ctx context.Context, diags *diag.Diagnostics, client *client.Client, data *FvTenantResourceModel) {
	requestData := DoRestRequest(ctx, diags, client, fmt.Sprintf("api/mo/%s.json?rsp-subtree=full&rsp-subtree-class=%s", data.Id.ValueString(), "fvTenant,fvRsTenantMonPol,tagAnnotation,tagTag,tagAnnotation,tagTag"), "GET", nil)

	readData := getEmptyFvTenantResourceModel()

	if diags.HasError() {
		return
	}
	if requestData.Search("imdata").Search("fvTenant").Data() != nil {
		classReadInfo := requestData.Search("imdata").Search("fvTenant").Data().([]interface{})
		if len(classReadInfo) == 1 {
			attributes := classReadInfo[0].(map[string]interface{})["attributes"].(map[string]interface{})
			for attributeName, attributeValue := range attributes {
				if attributeName == "dn" {
					readData.Id = basetypes.NewStringValue(attributeValue.(string))
				}
				if attributeName == "annotation" {
					readData.Annotation = basetypes.NewStringValue(attributeValue.(string))
				}
				if attributeName == "descr" {
					readData.Descr = basetypes.NewStringValue(attributeValue.(string))
				}
				if attributeName == "name" {
					readData.Name = basetypes.NewStringValue(attributeValue.(string))
				}
				if attributeName == "nameAlias" {
					readData.NameAlias = basetypes.NewStringValue(attributeValue.(string))
				}
				if attributeName == "ownerKey" {
					readData.OwnerKey = basetypes.NewStringValue(attributeValue.(string))
				}
				if attributeName == "ownerTag" {
					readData.OwnerTag = basetypes.NewStringValue(attributeValue.(string))
				}
			}
			FvRsTenantMonPolFvTenantList := make([]FvRsTenantMonPolFvTenantResourceModel, 0)
			TagAnnotationFvTenantList := make([]TagAnnotationFvTenantResourceModel, 0)
			TagTagFvTenantList := make([]TagTagFvTenantResourceModel, 0)
			_, ok := classReadInfo[0].(map[string]interface{})["children"]
			if ok {
				children := classReadInfo[0].(map[string]interface{})["children"].([]interface{})
				for _, child := range children {
					for childClassName, childClassDetails := range child.(map[string]interface{}) {
						childAttributes := childClassDetails.(map[string]interface{})["attributes"].(map[string]interface{})
						if childClassName == "fvRsTenantMonPol" {
							FvRsTenantMonPolFvTenant := getEmptyFvRsTenantMonPolFvTenantResourceModel()
							for childAttributeName, childAttributeValue := range childAttributes {
								if childAttributeName == "annotation" {
									FvRsTenantMonPolFvTenant.Annotation = basetypes.NewStringValue(childAttributeValue.(string))
								}
								if childAttributeName == "tnMonEPGPolName" {
									FvRsTenantMonPolFvTenant.TnMonEPGPolName = basetypes.NewStringValue(childAttributeValue.(string))
								}

							}
							TagAnnotationFvRsTenantMonPolFvTenantList := make([]TagAnnotationFvRsTenantMonPolFvTenantResourceModel, 0)
							TagTagFvRsTenantMonPolFvTenantList := make([]TagTagFvRsTenantMonPolFvTenantResourceModel, 0)
							childrenOfFvRsTenantMonPolFvTenant, childrenOfFvRsTenantMonPolFvTenantExist := childClassDetails.(map[string]interface{})["children"]
							if childrenOfFvRsTenantMonPolFvTenantExist {
								for _, childFvRsTenantMonPolFvTenant := range childrenOfFvRsTenantMonPolFvTenant.([]interface{}) {
									for childClassNameFvRsTenantMonPolFvTenant, childClassDetailsFvRsTenantMonPolFvTenant := range childFvRsTenantMonPolFvTenant.(map[string]interface{}) {
										if childClassNameFvRsTenantMonPolFvTenant == "tagAnnotation" {
											TagAnnotationFvRsTenantMonPolFvTenant := getEmptyTagAnnotationFvRsTenantMonPolFvTenantResourceModel()
											tagAnnotationchildAttributeValue := childClassDetailsFvRsTenantMonPolFvTenant.(map[string]interface{})["attributes"].(map[string]interface{})
											for childAttributeName, childAttributeValue := range tagAnnotationchildAttributeValue {
												if childAttributeName == "key" {
													TagAnnotationFvRsTenantMonPolFvTenant.Key = basetypes.NewStringValue(childAttributeValue.(string))
												}
												if childAttributeName == "value" {
													TagAnnotationFvRsTenantMonPolFvTenant.Value = basetypes.NewStringValue(childAttributeValue.(string))
												}
											}
											TagAnnotationFvRsTenantMonPolFvTenantList = append(TagAnnotationFvRsTenantMonPolFvTenantList, TagAnnotationFvRsTenantMonPolFvTenant)
										}
										if childClassNameFvRsTenantMonPolFvTenant == "tagTag" {
											TagTagFvRsTenantMonPolFvTenant := getEmptyTagTagFvRsTenantMonPolFvTenantResourceModel()
											tagTagchildAttributeValue := childClassDetailsFvRsTenantMonPolFvTenant.(map[string]interface{})["attributes"].(map[string]interface{})
											for childAttributeName, childAttributeValue := range tagTagchildAttributeValue {
												if childAttributeName == "key" {
													TagTagFvRsTenantMonPolFvTenant.Key = basetypes.NewStringValue(childAttributeValue.(string))
												}
												if childAttributeName == "value" {
													TagTagFvRsTenantMonPolFvTenant.Value = basetypes.NewStringValue(childAttributeValue.(string))
												}
											}
											TagTagFvRsTenantMonPolFvTenantList = append(TagTagFvRsTenantMonPolFvTenantList, TagTagFvRsTenantMonPolFvTenant)
										}
									}
								}
							}
							TagAnnotationFvRsTenantMonPolFvTenantSet, _ := types.SetValueFrom(ctx, TagAnnotationFvRsTenantMonPolFvTenantType, TagAnnotationFvRsTenantMonPolFvTenantList)
							FvRsTenantMonPolFvTenant.TagAnnotation = TagAnnotationFvRsTenantMonPolFvTenantSet
							TagTagFvRsTenantMonPolFvTenantSet, _ := types.SetValueFrom(ctx, TagTagFvRsTenantMonPolFvTenantType, TagTagFvRsTenantMonPolFvTenantList)
							FvRsTenantMonPolFvTenant.TagTag = TagTagFvRsTenantMonPolFvTenantSet
							FvRsTenantMonPolFvTenantList = append(FvRsTenantMonPolFvTenantList, FvRsTenantMonPolFvTenant)
						}
						if childClassName == "tagAnnotation" {
							TagAnnotationFvTenant := getEmptyTagAnnotationFvTenantResourceModel()
							for childAttributeName, childAttributeValue := range childAttributes {
								if childAttributeName == "key" {
									TagAnnotationFvTenant.Key = basetypes.NewStringValue(childAttributeValue.(string))
								}
								if childAttributeName == "value" {
									TagAnnotationFvTenant.Value = basetypes.NewStringValue(childAttributeValue.(string))
								}

							}
							TagAnnotationFvTenantList = append(TagAnnotationFvTenantList, TagAnnotationFvTenant)
						}
						if childClassName == "tagTag" {
							TagTagFvTenant := getEmptyTagTagFvTenantResourceModel()
							for childAttributeName, childAttributeValue := range childAttributes {
								if childAttributeName == "key" {
									TagTagFvTenant.Key = basetypes.NewStringValue(childAttributeValue.(string))
								}
								if childAttributeName == "value" {
									TagTagFvTenant.Value = basetypes.NewStringValue(childAttributeValue.(string))
								}

							}
							TagTagFvTenantList = append(TagTagFvTenantList, TagTagFvTenant)
						}
					}
				}
			}
			if len(FvRsTenantMonPolFvTenantList) == 1 {
				fvRsTenantMonPolObject, _ := types.ObjectValueFrom(ctx, FvRsTenantMonPolFvTenantType, FvRsTenantMonPolFvTenantList[0])
				readData.FvRsTenantMonPol = fvRsTenantMonPolObject
			} else {
				fvRsTenantMonPolObject, _ := types.ObjectValueFrom(ctx, FvRsTenantMonPolFvTenantType, getEmptyFvRsTenantMonPolFvTenantResourceModel())
				readData.FvRsTenantMonPol = fvRsTenantMonPolObject
			}
			tagAnnotationSet, _ := types.SetValueFrom(ctx, readData.TagAnnotation.ElementType(ctx), TagAnnotationFvTenantList)
			readData.TagAnnotation = tagAnnotationSet
			tagTagSet, _ := types.SetValueFrom(ctx, readData.TagTag.ElementType(ctx), TagTagFvTenantList)
			readData.TagTag = tagTagSet
			setFvTenantLegacyAttributes(ctx, diags, readData, data, classReadInfo)
		} else {
			diags.AddError(
				"too many results in response",
				fmt.Sprintf("%v matches returned for class 'fvTenant'. Please report this issue to the provider developers.", len(classReadInfo)),
			)
		}
	} else {
		readData.Id = basetypes.NewStringNull()
	}
	*data = *readData
}

func getFvTenantRn(ctx context.Context, data *FvTenantResourceModel) string {
	return fmt.Sprintf("tn-%s", data.Name.ValueString())
}

func setFvTenantId(ctx context.Context, data *FvTenantResourceModel) {
	rn := getFvTenantRn(ctx, data)
	data.Id = types.StringValue(fmt.Sprintf("%s/%s", strings.Split([]string{"uni/tn-{name}"}[0], "/")[0], rn))
}

func getFvTenantFvRsTenantMonPolChildPayloads(ctx context.Context, diags *diag.Diagnostics, data *FvTenantResourceModel, fvRsTenantMonPolFvTenantPlan, fvRsTenantMonPolFvTenantState FvRsTenantMonPolFvTenantResourceModel) []map[string]interface{} {
	childPayloads := []map[string]interface{}{}
	if !data.FvRsTenantMonPol.IsNull() && !data.FvRsTenantMonPol.IsUnknown() {
		FvRsTenantMonPolFvTenantChildren := make([]map[string]interface{}, 0)
		childMap := NewAciObject()
		if !IsEmptySingleNestedAttribute(data.FvRsTenantMonPol.Attributes()) {
			if !fvRsTenantMonPolFvTenantPlan.Annotation.IsUnknown() && !fvRsTenantMonPolFvTenantPlan.Annotation.IsNull() {
				childMap.Attributes["annotation"] = fvRsTenantMonPolFvTenantPlan.Annotation.ValueString()
			} else {
				childMap.Attributes["annotation"] = globalAnnotation
			}
			if !fvRsTenantMonPolFvTenantPlan.TnMonEPGPolName.IsUnknown() && !fvRsTenantMonPolFvTenantPlan.TnMonEPGPolName.IsNull() {
				childMap.Attributes["tnMonEPGPolName"] = fvRsTenantMonPolFvTenantPlan.TnMonEPGPolName.ValueString()
			}

			var tagAnnotationFvRsTenantMonPolFvTenantPlan, tagAnnotationFvRsTenantMonPolFvTenantState []TagAnnotationFvRsTenantMonPolFvTenantResourceModel
			fvRsTenantMonPolFvTenantPlan.TagAnnotation.ElementsAs(ctx, &tagAnnotationFvRsTenantMonPolFvTenantPlan, false)
			if !fvRsTenantMonPolFvTenantState.TagAnnotation.IsNull() {
				fvRsTenantMonPolFvTenantState.TagAnnotation.ElementsAs(ctx, &tagAnnotationFvRsTenantMonPolFvTenantState, false)
			}
			if !fvRsTenantMonPolFvTenantPlan.TagAnnotation.IsNull() && !fvRsTenantMonPolFvTenantPlan.TagAnnotation.IsUnknown() {
				tagAnnotationIdentifiers := []TagAnnotationIdentifier{}
				for _, tagAnnotationFvRsTenantMonPolFvTenant := range tagAnnotationFvRsTenantMonPolFvTenantPlan {
					tagAnnotationFvRsTenantMonPolFvTenantChildMap := NewAciObject()
					if !tagAnnotationFvRsTenantMonPolFvTenant.Key.IsNull() && !tagAnnotationFvRsTenantMonPolFvTenant.Key.IsUnknown() {
						tagAnnotationFvRsTenantMonPolFvTenantChildMap.Attributes["key"] = tagAnnotationFvRsTenantMonPolFvTenant.Key.ValueString()
					}
					if !tagAnnotationFvRsTenantMonPolFvTenant.Value.IsNull() && !tagAnnotationFvRsTenantMonPolFvTenant.Value.IsUnknown() {
						tagAnnotationFvRsTenantMonPolFvTenantChildMap.Attributes["value"] = tagAnnotationFvRsTenantMonPolFvTenant.Value.ValueString()
					}
					FvRsTenantMonPolFvTenantChildren = append(FvRsTenantMonPolFvTenantChildren, map[string]interface{}{"tagAnnotation": tagAnnotationFvRsTenantMonPolFvTenantChildMap})
					tagAnnotationIdentifier := TagAnnotationIdentifier{}
					tagAnnotationIdentifier.Key = tagAnnotationFvRsTenantMonPolFvTenant.Key
					tagAnnotationIdentifiers = append(tagAnnotationIdentifiers, tagAnnotationIdentifier)
				}
				for _, tagAnnotationFvRsTenantMonPolFvTenant := range tagAnnotationFvRsTenantMonPolFvTenantState {
					delete := true
					for _, tagAnnotationIdentifier := range tagAnnotationIdentifiers {
						if tagAnnotationIdentifier.Key == tagAnnotationFvRsTenantMonPolFvTenant.Key {
							delete = false
							break
						}
					}
					if delete {
						tagAnnotationFvRsTenantMonPolFvTenantChildMapForDelete := NewAciObject()
						tagAnnotationFvRsTenantMonPolFvTenantChildMapForDelete.Attributes["status"] = "deleted"
						tagAnnotationFvRsTenantMonPolFvTenantChildMapForDelete.Attributes["key"] = tagAnnotationFvRsTenantMonPolFvTenant.Key.ValueString()
						FvRsTenantMonPolFvTenantChildren = append(FvRsTenantMonPolFvTenantChildren, map[string]interface{}{"tagAnnotation": tagAnnotationFvRsTenantMonPolFvTenantChildMapForDelete})
					}
				}
			}

			var tagTagFvRsTenantMonPolFvTenantPlan, tagTagFvRsTenantMonPolFvTenantState []TagTagFvRsTenantMonPolFvTenantResourceModel
			fvRsTenantMonPolFvTenantPlan.TagTag.ElementsAs(ctx, &tagTagFvRsTenantMonPolFvTenantPlan, false)
			if !fvRsTenantMonPolFvTenantState.TagTag.IsNull() {
				fvRsTenantMonPolFvTenantState.TagTag.ElementsAs(ctx, &tagTagFvRsTenantMonPolFvTenantState, false)
			}
			if !fvRsTenantMonPolFvTenantPlan.TagTag.IsNull() && !fvRsTenantMonPolFvTenantPlan.TagTag.IsUnknown() {
				tagTagIdentifiers := []TagTagIdentifier{}
				for _, tagTagFvRsTenantMonPolFvTenant := range tagTagFvRsTenantMonPolFvTenantPlan {
					tagTagFvRsTenantMonPolFvTenantChildMap := NewAciObject()
					if !tagTagFvRsTenantMonPolFvTenant.Key.IsNull() && !tagTagFvRsTenantMonPolFvTenant.Key.IsUnknown() {
						tagTagFvRsTenantMonPolFvTenantChildMap.Attributes["key"] = tagTagFvRsTenantMonPolFvTenant.Key.ValueString()
					}
					if !tagTagFvRsTenantMonPolFvTenant.Value.IsNull() && !tagTagFvRsTenantMonPolFvTenant.Value.IsUnknown() {
						tagTagFvRsTenantMonPolFvTenantChildMap.Attributes["value"] = tagTagFvRsTenantMonPolFvTenant.Value.ValueString()
					}
					FvRsTenantMonPolFvTenantChildren = append(FvRsTenantMonPolFvTenantChildren, map[string]interface{}{"tagTag": tagTagFvRsTenantMonPolFvTenantChildMap})
					tagTagIdentifier := TagTagIdentifier{}
					tagTagIdentifier.Key = tagTagFvRsTenantMonPolFvTenant.Key
					tagTagIdentifiers = append(tagTagIdentifiers, tagTagIdentifier)
				}
				for _, tagTagFvRsTenantMonPolFvTenant := range tagTagFvRsTenantMonPolFvTenantState {
					delete := true
					for _, tagTagIdentifier := range tagTagIdentifiers {
						if tagTagIdentifier.Key == tagTagFvRsTenantMonPolFvTenant.Key {
							delete = false
							break
						}
					}
					if delete {
						tagTagFvRsTenantMonPolFvTenantChildMapForDelete := NewAciObject()
						tagTagFvRsTenantMonPolFvTenantChildMapForDelete.Attributes["status"] = "deleted"
						tagTagFvRsTenantMonPolFvTenantChildMapForDelete.Attributes["key"] = tagTagFvRsTenantMonPolFvTenant.Key.ValueString()
						FvRsTenantMonPolFvTenantChildren = append(FvRsTenantMonPolFvTenantChildren, map[string]interface{}{"tagTag": tagTagFvRsTenantMonPolFvTenantChildMapForDelete})
					}
				}
			}
			childMap.Children = FvRsTenantMonPolFvTenantChildren
			childPayloads = append(childPayloads, map[string]interface{}{"fvRsTenantMonPol": childMap})
		}
	} else {
		FvRsTenantMonPolObject, _ := types.ObjectValueFrom(ctx, FvRsTenantMonPolFvTenantType, getEmptyFvRsTenantMonPolFvTenantResourceModel())
		data.FvRsTenantMonPol = FvRsTenantMonPolObject
	}

	return childPayloads
}

func getFvTenantTagAnnotationChildPayloads(ctx context.Context, diags *diag.Diagnostics, data *FvTenantResourceModel, tagAnnotationFvTenantPlan, tagAnnotationFvTenantState []TagAnnotationFvTenantResourceModel) []map[string]interface{} {
	childPayloads := []map[string]interface{}{}
	if !data.TagAnnotation.IsNull() && !data.TagAnnotation.IsUnknown() {
		tagAnnotationIdentifiers := []TagAnnotationIdentifier{}
		for _, tagAnnotationFvTenant := range tagAnnotationFvTenantPlan {
			childMap := NewAciObject()
			if !tagAnnotationFvTenant.Key.IsNull() && !tagAnnotationFvTenant.Key.IsUnknown() {
				childMap.Attributes["key"] = tagAnnotationFvTenant.Key.ValueString()
			}
			if !tagAnnotationFvTenant.Value.IsNull() && !tagAnnotationFvTenant.Value.IsUnknown() {
				childMap.Attributes["value"] = tagAnnotationFvTenant.Value.ValueString()
			}
			childPayloads = append(childPayloads, map[string]interface{}{"tagAnnotation": childMap})
			tagAnnotationIdentifier := TagAnnotationIdentifier{}
			tagAnnotationIdentifier.Key = tagAnnotationFvTenant.Key
			tagAnnotationIdentifiers = append(tagAnnotationIdentifiers, tagAnnotationIdentifier)
		}
		for _, tagAnnotation := range tagAnnotationFvTenantState {
			delete := true
			for _, tagAnnotationIdentifier := range tagAnnotationIdentifiers {
				if tagAnnotationIdentifier.Key == tagAnnotation.Key {
					delete = false
					break
				}
			}
			if delete {
				tagAnnotationChildMapForDelete := NewAciObject()
				tagAnnotationChildMapForDelete.Attributes["status"] = "deleted"
				tagAnnotationChildMapForDelete.Attributes["key"] = tagAnnotation.Key.ValueString()
				childPayloads = append(childPayloads, map[string]interface{}{"tagAnnotation": tagAnnotationChildMapForDelete})
			}
		}
	} else {
		data.TagAnnotation = types.SetNull(data.TagAnnotation.ElementType(ctx))
	}

	return childPayloads
}

func getFvTenantTagTagChildPayloads(ctx context.Context, diags *diag.Diagnostics, data *FvTenantResourceModel, tagTagFvTenantPlan, tagTagFvTenantState []TagTagFvTenantResourceModel) []map[string]interface{} {
	childPayloads := []map[string]interface{}{}
	if !data.TagTag.IsNull() && !data.TagTag.IsUnknown() {
		tagTagIdentifiers := []TagTagIdentifier{}
		for _, tagTagFvTenant := range tagTagFvTenantPlan {
			childMap := NewAciObject()
			if !tagTagFvTenant.Key.IsNull() && !tagTagFvTenant.Key.IsUnknown() {
				childMap.Attributes["key"] = tagTagFvTenant.Key.ValueString()
			}
			if !tagTagFvTenant.Value.IsNull() && !tagTagFvTenant.Value.IsUnknown() {
				childMap.Attributes["value"] = tagTagFvTenant.Value.ValueString()
			}
			childPayloads = append(childPayloads, map[string]interface{}{"tagTag": childMap})
			tagTagIdentifier := TagTagIdentifier{}
			tagTagIdentifier.Key = tagTagFvTenant.Key
			tagTagIdentifiers = append(tagTagIdentifiers, tagTagIdentifier)
		}
		for _, tagTag := range tagTagFvTenantState {
			delete := true
			for _, tagTagIdentifier := range tagTagIdentifiers {
				if tagTagIdentifier.Key == tagTag.Key {
					delete = false
					break
				}
			}
			if delete {
				tagTagChildMapForDelete := NewAciObject()
				tagTagChildMapForDelete.Attributes["status"] = "deleted"
				tagTagChildMapForDelete.Attributes["key"] = tagTag.Key.ValueString()
				childPayloads = append(childPayloads, map[string]interface{}{"tagTag": tagTagChildMapForDelete})
			}
		}
	} else {
		data.TagTag = types.SetNull(data.TagTag.ElementType(ctx))
	}

	return childPayloads
}

func getFvTenantCreateJsonPayload(ctx context.Context, diags *diag.Diagnostics, createType bool, data *FvTenantResourceModel, fvRsTenantMonPolPlan, fvRsTenantMonPolState FvRsTenantMonPolFvTenantResourceModel, tagAnnotationPlan, tagAnnotationState []TagAnnotationFvTenantResourceModel, tagTagPlan, tagTagState []TagTagFvTenantResourceModel) *container.Container {
	payloadMap := map[string]interface{}{}
	payloadMap["attributes"] = map[string]string{}

	if createType && !globalAllowExistingOnCreate {
		payloadMap["attributes"].(map[string]string)["status"] = "created"
	}
	childPayloads := []map[string]interface{}{}

	FvRsTenantMonPolchildPayloads := getFvTenantFvRsTenantMonPolChildPayloads(ctx, diags, data, fvRsTenantMonPolPlan, fvRsTenantMonPolState)
	if FvRsTenantMonPolchildPayloads == nil {
		return nil
	}
	childPayloads = append(childPayloads, FvRsTenantMonPolchildPayloads...)

	TagAnnotationchildPayloads := getFvTenantTagAnnotationChildPayloads(ctx, diags, data, tagAnnotationPlan, tagAnnotationState)
	if TagAnnotationchildPayloads == nil {
		return nil
	}
	childPayloads = append(childPayloads, TagAnnotationchildPayloads...)

	TagTagchildPayloads := getFvTenantTagTagChildPayloads(ctx, diags, data, tagTagPlan, tagTagState)
	if TagTagchildPayloads == nil {
		return nil
	}
	childPayloads = append(childPayloads, TagTagchildPayloads...)

	payloadMap["children"] = childPayloads
	if !data.Annotation.IsNull() && !data.Annotation.IsUnknown() {
		payloadMap["attributes"].(map[string]string)["annotation"] = data.Annotation.ValueString()
	}
	if !data.Descr.IsNull() && !data.Descr.IsUnknown() {
		payloadMap["attributes"].(map[string]string)["descr"] = data.Descr.ValueString()
	}
	if !data.Name.IsNull() && !data.Name.IsUnknown() {
		payloadMap["attributes"].(map[string]string)["name"] = data.Name.ValueString()
	}
	if !data.NameAlias.IsNull() && !data.NameAlias.IsUnknown() {
		payloadMap["attributes"].(map[string]string)["nameAlias"] = data.NameAlias.ValueString()
	}
	if !data.OwnerKey.IsNull() && !data.OwnerKey.IsUnknown() {
		payloadMap["attributes"].(map[string]string)["ownerKey"] = data.OwnerKey.ValueString()
	}
	if !data.OwnerTag.IsNull() && !data.OwnerTag.IsUnknown() {
		payloadMap["attributes"].(map[string]string)["ownerTag"] = data.OwnerTag.ValueString()
	}
	payload, err := json.Marshal(map[string]interface{}{"fvTenant": payloadMap})
	if err != nil {
		diags.AddError(
			"Marshalling of json payload failed",
			fmt.Sprintf("Err: %s. Please report this issue to the provider developers.", err),
		)
		return nil
	}

	jsonPayload, err := container.ParseJSON(payload)

	if err != nil {
		diags.AddError(
			"Construction of json payload failed",
			fmt.Sprintf("Err: %s. Please report this issue to the provider developers.", err),
		)
		return nil
	}
	return jsonPayload
}
