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

package address

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

	"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_address"

type tfModel struct {
	ID             types.String `tfsdk:"id"`
	AddressID      types.String `tfsdk:"address_id"`
	AddressLines   types.Set    `tfsdk:"address_lines"`
	City           types.String `tfsdk:"city"`
	CountryCode    types.String `tfsdk:"country_code"`
	CreateTime     types.String `tfsdk:"create_time"`
	Name           types.String `tfsdk:"name"`
	OrganizationID types.String `tfsdk:"organization_id"`
	State          types.String `tfsdk:"state"`
	UpdateTime     types.String `tfsdk:"update_time"`
	ZipCode        types.String `tfsdk:"zip_code"`
}

func (tf *tfModel) SetID(vOrganizationID string, vAddressID string) {
	tf.OrganizationID = types.StringValue(vOrganizationID)
	tf.AddressID = types.StringValue(vAddressID)
	tf.ID = types.StringValue(filepath.Join(vOrganizationID, vAddressID))
}

type apiModel struct {
	AddressID      *string   `json:"address_id,omitempty"`
	AddressLines   *[]string `json:"address_lines,omitempty"`
	City           *string   `json:"city,omitempty"`
	CountryCode    *string   `json:"country_code,omitempty"`
	CreateTime     *string   `json:"create_time,omitempty"`
	Name           *string   `json:"name,omitempty"`
	OrganizationID *string   `json:"organization_id,omitempty"`
	State          *string   `json:"state,omitempty"`
	UpdateTime     *string   `json:"update_time,omitempty"`
	ZipCode        *string   `json:"zip_code,omitempty"`
}

// composeID the ID attribute fields, i.e.:
// terraform import aiven_organization_address.foo ORGANIZATION_ID/ADDRESS_ID
func composeID() []string {
	return []string{"organization_id", "address_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.AddressLines.IsNull() || state != nil && !state.AddressLines.IsNull() {
		vAddressLines := make([]string, 0)
		diags := plan.AddressLines.ElementsAs(ctx, &vAddressLines, false)
		if diags.HasError() {
			return diags
		}
		api.AddressLines = &vAddressLines
	}
	if !plan.City.IsNull() || state != nil && !state.City.IsNull() {
		vCity := plan.City.ValueString()
		api.City = &vCity
	}
	if !plan.CountryCode.IsNull() || state != nil && !state.CountryCode.IsNull() {
		vCountryCode := plan.CountryCode.ValueString()
		api.CountryCode = &vCountryCode
	}
	if !plan.Name.IsNull() || state != nil && !state.Name.IsNull() {
		vName := plan.Name.ValueString()
		api.Name = &vName
	}
	if !plan.OrganizationID.IsNull() || state != nil && !state.OrganizationID.IsNull() {
		vOrganizationID := plan.OrganizationID.ValueString()
		api.OrganizationID = &vOrganizationID
	}
	if !plan.State.IsNull() || state != nil && !state.State.IsNull() {
		vState := plan.State.ValueString()
		api.State = &vState
	}
	if !plan.ZipCode.IsNull() || state != nil && !state.ZipCode.IsNull() {
		vZipCode := plan.ZipCode.ValueString()
		api.ZipCode = &vZipCode
	}
	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
}

// 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.AddressLines != nil && (len(*api.AddressLines) > 0 || !state.AddressLines.IsNull()) {
		vAddressLines, diags := types.SetValueFrom(ctx, types.StringType, api.AddressLines)
		if diags.HasError() {
			return diags
		}
		state.AddressLines = vAddressLines
	}
	if api.AddressID != nil && (*api.AddressID != "" || !state.AddressID.IsNull()) {
		state.AddressID = types.StringPointerValue(api.AddressID)
	}
	if api.City != nil && (*api.City != "" || !state.City.IsNull()) {
		state.City = types.StringPointerValue(api.City)
	}
	if api.CountryCode != nil && (*api.CountryCode != "" || !state.CountryCode.IsNull()) {
		state.CountryCode = types.StringPointerValue(api.CountryCode)
	}
	if api.CreateTime != nil && (*api.CreateTime != "" || !state.CreateTime.IsNull()) {
		state.CreateTime = types.StringPointerValue(api.CreateTime)
	}
	if api.Name != nil && (*api.Name != "" || !state.Name.IsNull()) {
		state.Name = types.StringPointerValue(api.Name)
	}
	if api.OrganizationID != nil && (*api.OrganizationID != "" || !state.OrganizationID.IsNull()) {
		state.OrganizationID = types.StringPointerValue(api.OrganizationID)
	}
	if api.State != nil && (*api.State != "" || !state.State.IsNull()) {
		state.State = types.StringPointerValue(api.State)
	}
	if api.UpdateTime != nil && (*api.UpdateTime != "" || !state.UpdateTime.IsNull()) {
		state.UpdateTime = types.StringPointerValue(api.UpdateTime)
	}
	if api.ZipCode != nil && (*api.ZipCode != "" || !state.ZipCode.IsNull()) {
		state.ZipCode = types.StringPointerValue(api.ZipCode)
	}
	// 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 [2]string
		for i, v := range strings.SplitN(state.ID.ValueString(), "/", 2) {
			parts[i] = v
		}
		if state.OrganizationID.ValueString() == "" {
			state.OrganizationID = types.StringValue(parts[0])
		}
		if state.AddressID.ValueString() == "" {
			state.AddressID = types.StringValue(parts[1])
		}
	}
	state.SetID(state.OrganizationID.ValueString(), state.AddressID.ValueString())
	return nil
}
