package flattens

import (
	"context"
	"fmt"
	"strconv"

	"github.com/hashicorp/terraform-plugin-framework/diag"
	"github.com/hashicorp/terraform-plugin-framework/types"
	"github.com/hashicorp/terraform-plugin-log/tflog"
	"repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/bservice"
	"repository.basistech.ru/BASIS/terraform-provider-dynamix/internal/client"
	"repository.basistech.ru/BASIS/terraform-provider-dynamix/internal/flattens"
	"repository.basistech.ru/BASIS/terraform-provider-dynamix/internal/service/cloudapi/bservice/models"
	"repository.basistech.ru/BASIS/terraform-provider-dynamix/internal/service/cloudapi/bservice/utilities"
)

func BServiceGroupResource(ctx context.Context, plan *models.ResourceRecordGroupModel, c *client.Client) diag.Diagnostics {
	tflog.Info(ctx, "Start BServiceGroupResource", map[string]any{"service_id": plan.ServiceID.ValueInt64(), "compgroup_id": plan.CompgroupID.ValueInt64()})

	diags := diag.Diagnostics{}
	serviceID := plan.ServiceID.ValueInt64()
	comgroupID := plan.CompgroupID.ValueInt64()
	if serviceID == 0 {
		id, err := strconv.Atoi(plan.SID.ValueString())
		if err != nil {
			diags.AddError(
				"flattens.BServiceGroupResource: cannot parse resource ID from state",
				err.Error())
			return diags
		}
		serviceID = int64(id)
	}

	if comgroupID == 0 {
		id, err := strconv.Atoi(plan.ID.ValueString())
		if err != nil {
			diags.AddError(
				"flattens.BServiceGroupResource: cannot parse resource ID from state",
				err.Error())
			return diags
		}
		comgroupID = int64(id)
	}

	recordResourceGroup, err := utilities.BServiceGroupResourceCheckPresence(ctx, uint64(serviceID), uint64(comgroupID), c)
	if err != nil {
		diags.AddError(fmt.Sprintf("Cannot get info about bservice group with service_id %d and compgroup_id %d", serviceID, comgroupID), err.Error())
		return diags
	}

	*plan = models.ResourceRecordGroupModel{
		ServiceID:      types.Int64Value(int64(recordResourceGroup.ServiceID)),
		CompCount:      plan.CompCount,
		Name:           types.StringValue(recordResourceGroup.Name),
		CPU:            types.Int64Value(int64(recordResourceGroup.CPU)),
		RAM:            types.Int64Value(int64(recordResourceGroup.RAM)),
		Disk:           types.Int64Value(int64(recordResourceGroup.Disk)),
		ImageID:        types.Int64Value(int64(recordResourceGroup.ImageID)),
		Chipset:        plan.Chipset,
		Driver:         types.StringValue(recordResourceGroup.Driver),
		SEPID:          types.Int64Value(int64(recordResourceGroup.SEPID)),
		SepPool:        types.StringValue(recordResourceGroup.PoolName),
		CloudInit:      plan.CloudInit,
		Role:           types.StringValue(recordResourceGroup.Role),
		TimeoutStart:   types.Int64Value(int64(recordResourceGroup.TimeoutStart)),
		VINSes:         flattens.FlattenSimpleTypeToList(ctx, types.Int64Type, recordResourceGroup.VINSes),
		ExtNets:        flattens.FlattenSimpleTypeToList(ctx, types.Int64Type, recordResourceGroup.ExtNets),
		Mode:           plan.Mode,
		Start:          plan.Start,
		ForceStop:      plan.ForceStop,
		ForceUpdate:    plan.ForceUpdate,
		Parents:        flattens.FlattenSimpleTypeToList(ctx, types.Int64Type, recordResourceGroup.Parents),
		RemoveComputes: plan.RemoveComputes,
		CompgroupID:    types.Int64Value(int64(recordResourceGroup.ID)),
		ID:             types.StringValue(strconv.Itoa(int(recordResourceGroup.ID))),
		SID:            types.StringValue(strconv.Itoa(int(recordResourceGroup.ServiceID))),
		Timeouts:       plan.Timeouts,
		AccountID:      types.Int64Value(int64(recordResourceGroup.AccountID)),
		AccountName:    types.StringValue(recordResourceGroup.AccountName),
		Computes:       flattenGroupComputes(ctx, recordResourceGroup.Computes),
		Consistency:    types.BoolValue(recordResourceGroup.Consistency),
		CreatedBy:      types.StringValue(recordResourceGroup.CreatedBy),
		CreatedTime:    types.Int64Value(int64(recordResourceGroup.CreatedTime)),
		DeletedBy:      types.StringValue(recordResourceGroup.DeletedBy),
		DeletedTime:    types.Int64Value(int64(recordResourceGroup.DeletedTime)),
		GID:            types.Int64Value(int64(recordResourceGroup.GID)),
		GUID:           types.Int64Value(int64(recordResourceGroup.GUID)),
		Milestones:     types.Int64Value(int64(recordResourceGroup.Milestones)),
		RGID:           types.Int64Value(int64(recordResourceGroup.RGID)),
		RGName:         types.StringValue(recordResourceGroup.RGName),
		SeqNo:          types.Int64Value(int64(recordResourceGroup.SeqNo)),
		Status:         types.StringValue(recordResourceGroup.Status),
		TechStatus:     types.StringValue(recordResourceGroup.TechStatus),
		UpdatedBy:      types.StringValue(recordResourceGroup.UpdatedBy),
		UpdatedTime:    types.Int64Value(int64(recordResourceGroup.UpdatedTime)),
	}

	if plan.CompCount == types.Int64Null() {
		plan.CompCount = types.Int64Value(int64(len(recordResourceGroup.Computes)))
	}

	tflog.Info(ctx, "End BServiceGroupResource", map[string]any{"service_id": plan.ServiceID.ValueInt64(), "compgroup_id": plan.CompgroupID.ValueInt64()})
	return nil
}

func flattenGroupComputes(ctx context.Context, items bservice.ListGroupComputes) types.List {
	tflog.Info(ctx, "Start flattenGroupComputes")
	tempSlice := make([]types.Object, 0, len(items))
	for _, v := range items {
		temp := models.ResourceItemGroupComputeModel{

			ID:          types.Int64Value(int64(v.ID)),
			Name:        types.StringValue(v.Name),
			IPAddresses: flattens.FlattenSimpleTypeToList(ctx, types.StringType, v.IPAddresses),
			Chipset:     types.StringValue(v.Chipset),
			OSUsers:     flattenOSuser(ctx, v.OSUsers),
		}
		obj, diags := types.ObjectValueFrom(ctx, models.ResourceItemGroupCompute, temp)
		if diags != nil {
			tflog.Error(ctx, fmt.Sprint("Error flattenGroupComputes struct to obj", diags))
		}
		tempSlice = append(tempSlice, obj)
	}

	res, diags := types.ListValueFrom(ctx, types.ObjectType{AttrTypes: models.ResourceItemGroupCompute}, tempSlice)
	if diags != nil {
		tflog.Error(ctx, fmt.Sprint("Error flattenGroupComputes", diags))
	}

	tflog.Info(ctx, "End flattenGroupComputes")
	return res
}

func flattenOSuser(ctx context.Context, items bservice.ListOSUsers) types.List {
	tflog.Info(ctx, "Start flattenOSuser")
	tempSlice := make([]types.Object, 0, len(items))
	for _, v := range items {
		temp := models.ResourceItemOSUserModel{
			Login:    types.StringValue(v.Login),
			Password: types.StringValue(v.Password),
		}
		obj, diags := types.ObjectValueFrom(ctx, models.ResourceItemOSUser, temp)
		if diags != nil {
			tflog.Error(ctx, fmt.Sprint("Error flattenOSuser struct to obj", diags))
		}
		tempSlice = append(tempSlice, obj)
	}

	res, diags := types.ListValueFrom(ctx, types.ObjectType{AttrTypes: models.ResourceItemOSUser}, tempSlice)
	if diags != nil {
		tflog.Error(ctx, fmt.Sprint("Error flattenOSuser", diags))
	}

	tflog.Info(ctx, "End flattenOSuser")
	return res
}
