package utilities

import (
	"context"
	"fmt"
	"strconv"
	"strings"
	"time"

	"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/status"
)

func createRequestResourceImage(ctx context.Context, plan *models.ImageResourceModel) image.CreateRequest {
	tflog.Info(ctx, "Start createRequestResourceImage", map[string]any{"name": plan.ImageName.ValueString()})
	req := image.CreateRequest{
		Name:      plan.ImageName.ValueString(),
		URL:       plan.URL.ValueString(),
		BootType:  plan.BootType.ValueString(),
		ImageType: plan.ImageType.ValueString(),
	}
	result := make([]string, 0, len(plan.Drivers.Elements()))
	for _, val := range plan.Drivers.Elements() {
		result = append(result, strings.Trim(val.String(), "\""))
	}
	req.Drivers = result

	if plan.HotResize.IsUnknown() {
		req.HotResize = false
	} else {
		req.HotResize = plan.HotResize.ValueBool()
	}
	if !plan.Username.IsUnknown() {
		req.Username = plan.Username.ValueString()
	}
	if !plan.Password.IsUnknown() {
		req.Password = plan.Password.ValueString()
	}
	if !plan.AccountID.IsUnknown() {
		req.AccountID = uint64(plan.AccountID.ValueInt64())
	}
	if !plan.UsernameDL.IsNull() {
		req.UsernameDL = plan.UsernameDL.ValueString()
	}
	if !plan.PasswordDL.IsNull() {
		req.PasswordDL = plan.PasswordDL.ValueString()
	}
	if !plan.SepID.IsUnknown() {
		req.SEPID = uint64(plan.SepID.ValueInt64())
	}
	if !plan.PoolName.IsUnknown() {
		req.Pool = plan.PoolName.ValueString()
	}
	if plan.Architecture.IsUnknown() {
		req.Architecture = "X86_64"
	} else {
		req.Architecture = plan.Architecture.ValueString()
	}

	tflog.Info(ctx, "End createRequestResourceImage", map[string]any{"name": plan.ImageName.ValueString()})
	return req
}

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

	diags := diag.Diagnostics{}

	// Make request and get response
	imageId, err := c.CloudAPI().Image().Create(ctx, createRequestResourceImage(ctx, plan))
	if err != nil {
		tflog.Error(ctx, "Error response for create image")
		diags.AddError("Unable to Create image", err.Error())
		return diags
	}

	plan.Id = types.StringValue(strconv.Itoa(int(imageId)))
	plan.LastUpdated = types.StringValue(time.Now().Format(time.RFC850))

	tflog.Info(ctx, "End ResourceImageCreate", map[string]any{"image_id": imageId})
	return nil
}

func ImageResourceCheckPresence(ctx context.Context, imageId uint64, c *client.Client) (*image.RecordImage, error) {
	tflog.Info(ctx, "Get info about image with ID", map[string]any{"image_id": imageId})

	image, err := c.CloudAPI().Image().Get(ctx, image.GetRequest{ImageID: imageId})
	if err != nil {
		return nil, fmt.Errorf("cannot get info about image with error: %w", err)

	}

	tflog.Info(ctx, "Getting info about image successfully", map[string]any{"image_id": imageId})
	return image, nil
}

func ImageReadStatus(ctx context.Context, imageId uint64, c *client.Client) diag.Diagnostics {
	tflog.Info(ctx, "Read status image with ID", map[string]any{"image": imageId})

	diags := diag.Diagnostics{}

	image, err := ImageResourceCheckPresence(ctx, imageId, c)
	if err != nil {
		diags.AddError("Cannot get info about image ", err.Error())
		return diags
	}

	switch image.Status {
	case status.Modeled:
		diags.AddError("Error:", fmt.Sprintf("The image is in status: %s, please, contact support for more information", image.Status))
		return diags
	case status.Destroying:
		diags.AddError("Error:", fmt.Sprintf("The image is in progress with status: %s", image.Status))
		return diags
	case status.Destroyed, status.Purged:
		diags.AddError("Error:", "The resource cannot be updated because it has been destroyed")
		return diags
	}

	tflog.Info(ctx, "Read status image successfully", map[string]any{"image_id": imageId})
	return nil
}

func ImageUpdateName(ctx context.Context, imageId uint64, name string, c *client.Client) diag.Diagnostics {
	tflog.Info(ctx, "Update name image with ID", map[string]any{"image_id": imageId})

	diags := diag.Diagnostics{}

	_, err := c.CloudAPI().Image().Rename(ctx, image.RenameRequest{ImageID: imageId, Name: name})
	if err != nil {
		diags.AddError(fmt.Sprintf("Cannot update name image with ID - %d", imageId), err.Error())
		return diags
	}

	tflog.Info(ctx, "Update name image successfully", map[string]any{"image_id": imageId})
	return nil
}
