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

package applicationusertoken

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

type tfModel struct {
	ID                         types.String `tfsdk:"id"`
	CreateTime                 types.String `tfsdk:"create_time"`
	CreatedManually            types.Bool   `tfsdk:"created_manually"`
	CurrentlyActive            types.Bool   `tfsdk:"currently_active"`
	Description                types.String `tfsdk:"description"`
	ExpiryTime                 types.String `tfsdk:"expiry_time"`
	ExtendWhenUsed             types.Bool   `tfsdk:"extend_when_used"`
	FullToken                  types.String `tfsdk:"full_token"`
	IpAllowlist                types.Set    `tfsdk:"ip_allowlist"`
	LastIP                     types.String `tfsdk:"last_ip"`
	LastUsedTime               types.String `tfsdk:"last_used_time"`
	LastUserAgent              types.String `tfsdk:"last_user_agent"`
	LastUserAgentHumanReadable types.String `tfsdk:"last_user_agent_human_readable"`
	MaxAgeSeconds              types.Int64  `tfsdk:"max_age_seconds"`
	OrganizationID             types.String `tfsdk:"organization_id"`
	Scopes                     types.Set    `tfsdk:"scopes"`
	TokenPrefix                types.String `tfsdk:"token_prefix"`
	UserID                     types.String `tfsdk:"user_id"`
}

func (tf *tfModel) SetID(vOrganizationID string, vUserID string, vTokenPrefix string) {
	tf.OrganizationID = types.StringValue(vOrganizationID)
	tf.UserID = types.StringValue(vUserID)
	tf.TokenPrefix = types.StringValue(vTokenPrefix)
	tf.ID = types.StringValue(filepath.Join(vOrganizationID, vUserID, vTokenPrefix))
}

type apiModel struct {
	CreateTime                 *string   `json:"create_time,omitempty"`
	CreatedManually            *bool     `json:"created_manually,omitempty"`
	CurrentlyActive            *bool     `json:"currently_active,omitempty"`
	Description                *string   `json:"description,omitempty"`
	ExpiryTime                 *string   `json:"expiry_time,omitempty"`
	ExtendWhenUsed             *bool     `json:"extend_when_used,omitempty"`
	FullToken                  *string   `json:"full_token,omitempty"`
	IpAllowlist                *[]string `json:"ip_allowlist,omitempty"`
	LastIP                     *string   `json:"last_ip,omitempty"`
	LastUsedTime               *string   `json:"last_used_time,omitempty"`
	LastUserAgent              *string   `json:"last_user_agent,omitempty"`
	LastUserAgentHumanReadable *string   `json:"last_user_agent_human_readable,omitempty"`
	MaxAgeSeconds              *int64    `json:"max_age_seconds,omitempty"`
	OrganizationID             *string   `json:"organization_id,omitempty"`
	Scopes                     *[]string `json:"scopes,omitempty"`
	TokenPrefix                *string   `json:"token_prefix,omitempty"`
	UserID                     *string   `json:"user_id,omitempty"`
}

// composeID the ID attribute fields, i.e.:
// terraform import aiven_organization_application_user_token.foo ORGANIZATION_ID/USER_ID/TOKEN_PREFIX
func composeID() []string {
	return []string{"organization_id", "user_id", "token_prefix"}
}

// 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.IpAllowlist.IsNull() || state != nil && !state.IpAllowlist.IsNull() {
		vIpAllowlist := make([]string, 0)
		diags := plan.IpAllowlist.ElementsAs(ctx, &vIpAllowlist, false)
		if diags.HasError() {
			return diags
		}
		api.IpAllowlist = &vIpAllowlist
	}
	if !plan.Scopes.IsNull() || state != nil && !state.Scopes.IsNull() {
		vScopes := make([]string, 0)
		diags := plan.Scopes.ElementsAs(ctx, &vScopes, false)
		if diags.HasError() {
			return diags
		}
		api.Scopes = &vScopes
	}
	if !plan.Description.IsNull() || state != nil && !state.Description.IsNull() {
		vDescription := plan.Description.ValueString()
		api.Description = &vDescription
	}
	if !plan.ExtendWhenUsed.IsNull() && !plan.ExtendWhenUsed.IsUnknown() {
		vExtendWhenUsed := plan.ExtendWhenUsed.ValueBool()
		api.ExtendWhenUsed = &vExtendWhenUsed
	}
	if !plan.MaxAgeSeconds.IsNull() || state != nil && !state.MaxAgeSeconds.IsNull() {
		vMaxAgeSeconds := plan.MaxAgeSeconds.ValueInt64()
		api.MaxAgeSeconds = &vMaxAgeSeconds
	}
	if !plan.OrganizationID.IsNull() || state != nil && !state.OrganizationID.IsNull() {
		vOrganizationID := plan.OrganizationID.ValueString()
		api.OrganizationID = &vOrganizationID
	}
	if !plan.UserID.IsNull() || state != nil && !state.UserID.IsNull() {
		vUserID := plan.UserID.ValueString()
		api.UserID = &vUserID
	}
	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.IpAllowlist != nil && (len(*api.IpAllowlist) > 0 || !state.IpAllowlist.IsNull()) {
		vIpAllowlist, diags := types.SetValueFrom(ctx, types.StringType, api.IpAllowlist)
		if diags.HasError() {
			return diags
		}
		state.IpAllowlist = vIpAllowlist
	}
	if api.Scopes != nil && (len(*api.Scopes) > 0 || !state.Scopes.IsNull()) {
		vScopes, diags := types.SetValueFrom(ctx, types.StringType, api.Scopes)
		if diags.HasError() {
			return diags
		}
		state.Scopes = vScopes
	}
	if api.CreateTime != nil && (*api.CreateTime != "" || !state.CreateTime.IsNull()) {
		state.CreateTime = types.StringPointerValue(api.CreateTime)
	}
	if api.CreatedManually != nil {
		state.CreatedManually = types.BoolPointerValue(api.CreatedManually)
	}
	if api.CurrentlyActive != nil {
		state.CurrentlyActive = types.BoolPointerValue(api.CurrentlyActive)
	}
	if api.Description != nil && (*api.Description != "" || !state.Description.IsNull()) {
		state.Description = types.StringPointerValue(api.Description)
	}
	if api.ExpiryTime != nil && (*api.ExpiryTime != "" || !state.ExpiryTime.IsNull()) {
		state.ExpiryTime = types.StringPointerValue(api.ExpiryTime)
	}
	if api.ExtendWhenUsed != nil {
		state.ExtendWhenUsed = types.BoolPointerValue(api.ExtendWhenUsed)
	}
	if api.FullToken != nil && (*api.FullToken != "" || !state.FullToken.IsNull()) {
		state.FullToken = types.StringPointerValue(api.FullToken)
	}
	if api.LastIP != nil && (*api.LastIP != "" || !state.LastIP.IsNull()) {
		state.LastIP = types.StringPointerValue(api.LastIP)
	}
	if api.LastUsedTime != nil && (*api.LastUsedTime != "" || !state.LastUsedTime.IsNull()) {
		state.LastUsedTime = types.StringPointerValue(api.LastUsedTime)
	}
	if api.LastUserAgent != nil && (*api.LastUserAgent != "" || !state.LastUserAgent.IsNull()) {
		state.LastUserAgent = types.StringPointerValue(api.LastUserAgent)
	}
	if api.LastUserAgentHumanReadable != nil && (*api.LastUserAgentHumanReadable != "" || !state.LastUserAgentHumanReadable.IsNull()) {
		state.LastUserAgentHumanReadable = types.StringPointerValue(api.LastUserAgentHumanReadable)
	}
	if api.MaxAgeSeconds != nil {
		state.MaxAgeSeconds = types.Int64PointerValue(api.MaxAgeSeconds)
	}
	if api.OrganizationID != nil && (*api.OrganizationID != "" || !state.OrganizationID.IsNull()) {
		state.OrganizationID = types.StringPointerValue(api.OrganizationID)
	}
	if api.TokenPrefix != nil && (*api.TokenPrefix != "" || !state.TokenPrefix.IsNull()) {
		state.TokenPrefix = types.StringPointerValue(api.TokenPrefix)
	}
	if api.UserID != nil && (*api.UserID != "" || !state.UserID.IsNull()) {
		state.UserID = types.StringPointerValue(api.UserID)
	}
	// 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.UserID.ValueString() == "" {
			state.UserID = types.StringValue(parts[1])
		}
		if state.TokenPrefix.ValueString() == "" {
			state.TokenPrefix = types.StringValue(parts[2])
		}
	}
	state.SetID(state.OrganizationID.ValueString(), state.UserID.ValueString(), state.TokenPrefix.ValueString())
	return nil
}
