package flattens

import (
	"context"
	"encoding/json"
	"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/image"
	"repository.basistech.ru/BASIS/terraform-provider-dynamix/internal/client"
	"repository.basistech.ru/BASIS/terraform-provider-dynamix/internal/service/cloudapi/image/models"
	"repository.basistech.ru/BASIS/terraform-provider-dynamix/internal/service/cloudapi/image/utilities"
)

func ResourceImage(ctx context.Context, plan *models.ImageResourceModel, c *client.Client) diag.Diagnostics {
	tflog.Info(ctx, "Start FlattenResourceImage", map[string]any{"image_id": plan.Id.ValueString()})

	diags := diag.Diagnostics{}

	imageId, err := strconv.ParseUint(plan.Id.ValueString(), 10, 64)
	if err != nil {
		diags.AddError(fmt.Sprintf("Cannot parsed ID image from state %d", imageId), err.Error())
		return diags
	}

	image, err := utilities.ImageResourceCheckPresence(ctx, imageId, c)
	if err != nil {
		diags.AddError(fmt.Sprintf("Cannot get info about image with ID %d", image.ID), err.Error())
		return diags
	}

	cdPresentedTo, _ := json.Marshal(image.CdPresentedTo)
	*plan = models.ImageResourceModel{
		ImageName:              types.StringValue(image.Name),
		URL:                    plan.URL,
		BootType:               types.StringValue(image.BootType),
		ImageType:              types.StringValue(image.Type),
		HotResize:              types.BoolValue(image.HotResize),
		NetworkInterfaceNaming: types.StringValue(image.NetworkInterfaceNaming),
		Username:               types.StringValue(image.Username),
		Password:               types.StringValue(image.Password),
		AccountID:              types.Int64Value(int64(image.AccountID)),
		UsernameDL:             plan.UsernameDL,
		PasswordDL:             plan.PasswordDL,
		SepID:                  types.Int64Value(int64(image.SepID)),
		PoolName:               types.StringValue(image.Pool),
		Architecture:           types.StringValue(image.Architecture),
		ImageId:                types.Int64Value(int64(image.ID)),
		Timeouts:               plan.Timeouts,
		Id:                     types.StringValue(strconv.Itoa(int(image.ID))),
		LastUpdated:            plan.LastUpdated,
		UNCPath:                types.StringValue(image.UNCPath),
		CKey:                   types.StringValue(image.CKey),
		Bootable:               types.BoolValue(image.Bootable),
		ComputeCIID:            types.Int64Value(int64(image.ComputeCIID)),
		CdPresentedTo:          types.StringValue(string(cdPresentedTo)),
		GID:                    types.Int64Value(int64(image.GID)),
		DeletedTime:            types.Int64Value(int64(image.DeletedTime)),
		Description:            types.StringValue(image.Description),
		Enabled:                types.BoolValue(image.Enabled),
		GUID:                   types.Int64Value(int64(image.GUID)),
		History:                flattenHistoryInResource(ctx, &image.History),
		LastModified:           types.Int64Value(int64(image.LastModified)),
		LinkTo:                 types.Int64Value(int64(image.LinkTo)),
		Milestones:             types.Int64Value(int64(image.Milestones)),
		ProviderName:           types.StringValue(image.ProviderName),
		PurgeAttempts:          types.Int64Value(int64(image.PurgeAttempts)),
		ResID:                  types.StringValue(image.ResID),
		RescueCD:               types.BoolValue(image.RescueCD),
		Size:                   types.Int64Value(int64(image.Size)),
		SnapshotID:             types.StringValue(image.SnapshotID),
		Status:                 types.StringValue(image.Status),
		TechStatus:             types.StringValue(image.TechStatus),
		Version:                types.StringValue(image.Version),
	}

	plan.ACL, diags = types.ListValueFrom(ctx, types.StringType, image.ACL)
	if diags != nil {
		tflog.Error(ctx, fmt.Sprint("Error flattenACL", diags))
	}
	plan.Drivers, diags = types.ListValueFrom(ctx, types.StringType, image.Drivers)
	if diags != nil {
		tflog.Error(ctx, fmt.Sprint("Error flattenDrivers", diags))
	}
	plan.PresentTo, diags = types.MapValueFrom(ctx, types.Int64Type, image.PresentTo)
	if diags != nil {
		tflog.Error(ctx, fmt.Sprint("Error flattenPresentTo", diags))
	}
	plan.SharedWith, diags = types.ListValueFrom(ctx, types.Int64Type, image.SharedWith)
	if diags != nil {
		tflog.Error(ctx, fmt.Sprint("Error flattenSharedWith", diags))
	}

	tflog.Info(ctx, "End FlattenResourceImage", map[string]any{"image_id": plan.ImageId.ValueInt64()})
	return nil
}

func flattenHistoryInResource(ctx context.Context, history *image.ListHistories) types.List {
	tflog.Info(ctx, "Start flattenHistoryInResource")

	tempSlice := make([]types.Object, 0, len(*history))
	for _, item := range *history {
		temp := models.HistoryInImageResourceModel{
			GUID:      types.StringValue(item.GUID),
			ID:        types.Int64Value(int64(item.ID)),
			Timestamp: types.Int64Value(int64(item.Timestamp)),
		}

		obj, err := types.ObjectValueFrom(ctx, models.HistoryInResource, temp)
		if err != nil {
			tflog.Error(ctx, fmt.Sprint("Error flattenHistoryInResource struct to obj", err))
		}

		tempSlice = append(tempSlice, obj)
	}

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

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