// Copyright (c) 2025 Aiven, Helsinki, Finland. https://aiven.io/
// Code generated by user config generator. DO NOT EDIT.

package permission

import (
	"context"
	"fmt"
	"path/filepath"
	"strings"

	"github.com/hashicorp/terraform-plugin-framework/attr"
	"github.com/hashicorp/terraform-plugin-framework/diag"
	"github.com/hashicorp/terraform-plugin-framework/types"

	"github.com/aiven/terraform-provider-aiven/internal/plugin/util"
)

const aivenName = "aiven_organization_permission"

type tfModel struct {
	ID             types.String `tfsdk:"id"`
	OrganizationID types.String `tfsdk:"organization_id"`
	Permissions    types.Set    `tfsdk:"permissions"`
	ResourceID     types.String `tfsdk:"resource_id"`
	ResourceType   types.String `tfsdk:"resource_type"`
}

func (tf *tfModel) SetID(vOrganizationID string, vResourceType string, vResourceID string) {
	tf.OrganizationID = types.StringValue(vOrganizationID)
	tf.ResourceType = types.StringValue(vResourceType)
	tf.ResourceID = types.StringValue(vResourceID)
	tf.ID = types.StringValue(filepath.Join(vOrganizationID, vResourceType, vResourceID))
}

type tfModelPermissions struct {
	CreateTime    types.String `tfsdk:"create_time"`
	Permissions   types.Set    `tfsdk:"permissions"`
	PrincipalID   types.String `tfsdk:"principal_id"`
	PrincipalType types.String `tfsdk:"principal_type"`
	UpdateTime    types.String `tfsdk:"update_time"`
}

type apiModel struct {
	OrganizationID *string                 `json:"organization_id,omitempty"`
	Permissions    *[]*apiModelPermissions `json:"permissions,omitempty"`
	ResourceID     *string                 `json:"resource_id,omitempty"`
	ResourceType   *string                 `json:"resource_type,omitempty"`
}

type apiModelPermissions struct {
	CreateTime    *string   `json:"create_time,omitempty"`
	Permissions   *[]string `json:"permissions,omitempty"`
	PrincipalID   *string   `json:"principal_id,omitempty"`
	PrincipalType *string   `json:"principal_type,omitempty"`
	UpdateTime    *string   `json:"update_time,omitempty"`
}

// composeID the ID attribute fields, i.e.:
// terraform import aiven_organization_permission.foo ORGANIZATION_ID/RESOURCE_TYPE/RESOURCE_ID
func composeID() []string {
	return []string{"organization_id", "resource_type", "resource_id"}
}

// expandData turns TF object into Request
func expandData[R any](ctx context.Context, plan, state *tfModel, req *R, modifiers ...util.MapModifier[apiModel]) diag.Diagnostics {
	api := new(apiModel)
	if !plan.Permissions.IsNull() || state != nil && !state.Permissions.IsNull() {
		vPermissions, diags := util.ExpandSetNested(ctx, expandPermissions, plan.Permissions)
		if diags.HasError() {
			return diags
		}
		api.Permissions = &vPermissions
	}
	if !plan.OrganizationID.IsNull() || state != nil && !state.OrganizationID.IsNull() {
		vOrganizationID := plan.OrganizationID.ValueString()
		api.OrganizationID = &vOrganizationID
	}
	if !plan.ResourceID.IsNull() || state != nil && !state.ResourceID.IsNull() {
		vResourceID := plan.ResourceID.ValueString()
		api.ResourceID = &vResourceID
	}
	if !plan.ResourceType.IsNull() || state != nil && !state.ResourceType.IsNull() {
		vResourceType := plan.ResourceType.ValueString()
		api.ResourceType = &vResourceType
	}
	err := util.Unmarshal(api, req, modifiers...)
	if err != nil {
		var diags diag.Diagnostics
		diags.AddError("Unmarshal error", fmt.Sprintf("Failed to unmarshal dtoModel to Request: %s", err.Error()))
		return diags
	}
	return nil
}

func expandPermissions(ctx context.Context, plan *tfModelPermissions) (*apiModelPermissions, diag.Diagnostics) {
	api := new(apiModelPermissions)
	if !plan.Permissions.IsNull() {
		vPermissions := make([]string, 0)
		diags := plan.Permissions.ElementsAs(ctx, &vPermissions, false)
		if diags.HasError() {
			return nil, diags
		}
		api.Permissions = &vPermissions
	}
	if !plan.PrincipalID.IsNull() {
		vPrincipalID := plan.PrincipalID.ValueString()
		api.PrincipalID = &vPrincipalID
	}
	if !plan.PrincipalType.IsNull() {
		vPrincipalType := plan.PrincipalType.ValueString()
		api.PrincipalType = &vPrincipalType
	}
	return api, nil
}

// flattenData turns Response into TF object
func flattenData[R any](ctx context.Context, state *tfModel, rsp *R, modifiers ...util.MapModifier[R]) diag.Diagnostics {
	api := new(apiModel)
	err := util.Unmarshal(rsp, api, modifiers...)
	if err != nil {
		var diags diag.Diagnostics
		diags.AddError("Unmarshal error", fmt.Sprintf("Failed to unmarshal Response to dtoModel: %s", err.Error()))
		return diags
	}
	if api.Permissions != nil {
		vPermissions, diags := util.FlattenSetNested(ctx, flattenPermissions, *api.Permissions, attrsPermissions())
		if diags.HasError() {
			return diags
		}
		state.Permissions = vPermissions
	}
	if api.OrganizationID != nil && (*api.OrganizationID != "" || !state.OrganizationID.IsNull()) {
		state.OrganizationID = types.StringPointerValue(api.OrganizationID)
	}
	if api.ResourceID != nil && (*api.ResourceID != "" || !state.ResourceID.IsNull()) {
		state.ResourceID = types.StringPointerValue(api.ResourceID)
	}
	if api.ResourceType != nil && (*api.ResourceType != "" || !state.ResourceType.IsNull()) {
		state.ResourceType = types.StringPointerValue(api.ResourceType)
	}
	// Response may not contain ID fields.
	// In that case, `terraform import` won't be able to set them. Gets values from the ID.
	if state.ID.ValueString() != "" {
		var parts [3]string
		for i, v := range strings.SplitN(state.ID.ValueString(), "/", 3) {
			parts[i] = v
		}
		if state.OrganizationID.ValueString() == "" {
			state.OrganizationID = types.StringValue(parts[0])
		}
		if state.ResourceType.ValueString() == "" {
			state.ResourceType = types.StringValue(parts[1])
		}
		if state.ResourceID.ValueString() == "" {
			state.ResourceID = types.StringValue(parts[2])
		}
	}
	state.SetID(state.OrganizationID.ValueString(), state.ResourceType.ValueString(), state.ResourceID.ValueString())
	return nil
}

func flattenPermissions(ctx context.Context, api *apiModelPermissions) (*tfModelPermissions, diag.Diagnostics) {
	state := new(tfModelPermissions)
	if api.Permissions != nil {
		vPermissions, diags := types.SetValueFrom(ctx, types.StringType, api.Permissions)
		if diags.HasError() {
			return nil, diags
		}
		state.Permissions = vPermissions
	}
	if api.CreateTime != nil {
		state.CreateTime = types.StringPointerValue(api.CreateTime)
	}
	if api.PrincipalID != nil {
		state.PrincipalID = types.StringPointerValue(api.PrincipalID)
	}
	if api.PrincipalType != nil {
		state.PrincipalType = types.StringPointerValue(api.PrincipalType)
	}
	if api.UpdateTime != nil {
		state.UpdateTime = types.StringPointerValue(api.UpdateTime)
	}
	return state, nil
}

func attrsPermissions() types.ObjectType {
	return types.ObjectType{AttrTypes: map[string]attr.Type{
		"create_time":    types.StringType,
		"permissions":    types.SetType{ElemType: types.StringType},
		"principal_id":   types.StringType,
		"principal_type": types.StringType,
		"update_time":    types.StringType,
	}}
}
