package utilities

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

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

func CreateResourceLBBackendServer(ctx context.Context, plan *models.ResourceLBBackendServerModel, c *client.Client) diag.Diagnostics {
	tflog.Info(ctx, fmt.Sprintf("Start create ResourceLBBackendServer: name %s", plan.Name.ValueString()))

	diags := diag.Diagnostics{}

	createReq := lb.BackendServerAddRequest{
		LBID:        uint64(plan.LBID.ValueInt64()),
		BackendName: plan.Backend.ValueString(),
		ServerName:  plan.Name.ValueString(),
		Address:     plan.Address.ValueString(),
		Port:        uint64(plan.Port.ValueInt64()),
	}

	if !plan.Check.IsUnknown() { // Check is optional & computed
		createReq.Check = plan.Check.ValueString()
	}

	if !plan.Inter.IsUnknown() { // Inter is optional & computed
		createReq.Inter = uint64(plan.Inter.ValueInt64())
	}

	if !plan.DownInter.IsUnknown() { // DownInter is optional & computed
		createReq.DownInter = uint64(plan.DownInter.ValueInt64())
	}

	if !plan.Rise.IsUnknown() { // Rise is optional & computed
		createReq.Rise = uint64(plan.Rise.ValueInt64())
	}

	if !plan.Fall.IsUnknown() { // Fall is optional & computed
		createReq.Fall = uint64(plan.Fall.ValueInt64())
	}

	if !plan.SlowStart.IsUnknown() { // SlowStart is optional & computed
		createReq.SlowStart = uint64(plan.SlowStart.ValueInt64())
	}

	if !plan.MaxConn.IsUnknown() { // MaxConn is optional & computed
		createReq.MaxConn = uint64(plan.MaxConn.ValueInt64())
	}

	if !plan.MaxQueue.IsUnknown() { // MaxQueue is optional & computed
		createReq.MaxQueue = uint64(plan.MaxQueue.ValueInt64())
	}

	if !plan.Weight.IsUnknown() { // Weight is optional & computed
		createReq.Weight = uint64(plan.Weight.ValueInt64())
	}

	tflog.Info(ctx, "ResourceLBBackendServer: before call CloudAPI().LB().BackendServerAdd", map[string]any{"req": createReq})

	resp, err := c.CloudAPI().LB().BackendServerAdd(ctx, createReq)
	if err != nil {
		diags.AddError("ResourceLBBackendServer: unable to create LB Backend Server", err.Error())
		return diags
	}
	tflog.Info(ctx, "ResourceLBBackendServer: LB Backend Server created", map[string]any{"responce": resp, "name": plan.Name.ValueString()})

	return nil
}

func LBBackendServerResourceCheckPresence(ctx context.Context, plan *models.ResourceLBBackendServerModel, c *client.Client) (*lb.ItemServer, diag.Diagnostics) {
	tflog.Info(ctx, fmt.Sprintf("LBBackendServerCheckPresence: Get info about LB Backend Server with ID - %v", plan.ID.ValueString()))

	diags := diag.Diagnostics{}
	req := lb.GetRequest{}
	bName := plan.Backend.ValueString()
	sName := plan.Name.ValueString()

	if !plan.LBID.IsNull() {
		req.LBID = uint64(plan.LBID.ValueInt64())
	} else {
		parameters := strings.Split(plan.ID.ValueString(), "#")
		if len(parameters) != 3 {
			diags.AddError("LBBackendServerResourceCheckPresence: broken state id",
				fmt.Sprintf("state id expected: <lb_id>#<backend_name>#<server_name>, got: %v", plan.ID.ValueString()))
			return nil, diags
		}
		lbId, _ := strconv.ParseUint(parameters[0], 10, 64)
		req.LBID = lbId
		bName = parameters[1]
		sName = parameters[2]
	}

	lbItem, err := c.CloudAPI().LB().Get(ctx, req)
	if err != nil {
		diags.AddError(fmt.Sprintf("Cannot get info about lb with ID %v", req.LBID), err.Error())
		return nil, diags
	}

	backend := &lb.ItemBackend{}
	backends := lbItem.Backends
	for i, b := range backends {
		if b.Name == bName {
			backend = &backends[i]
			break
		}
	}
	if backend.Name == "" {
		diags.AddError(fmt.Sprintf("can not find backend with name: %s for lb: %d", bName, lbItem.ID), "")
		return nil, diags
	}

	for _, s := range backend.Servers {
		if s.Name == sName {
			return &s, nil
		}
	}

	diags.AddError(fmt.Sprintf("can not find server with name: %s for backend: %s for lb: %d", sName, bName, lbItem.ID), "")
	return nil, diags
}

func UpdateLBBackendServer(ctx context.Context, plan, state *models.ResourceLBBackendServerModel, c *client.Client) diag.Diagnostics {
	tflog.Info(ctx, fmt.Sprintf("UpdateLBBackendServer: Start edit lb backend server with ID - %v", state.ID.ValueString()))

	diags := diag.Diagnostics{}

	req := lb.BackendServerUpdateRequest{
		LBID:        uint64(plan.LBID.ValueInt64()),
		BackendName: plan.Backend.ValueString(),
		ServerName:  plan.Name.ValueString(),
		Address:     plan.Address.ValueString(),
		Port:        uint64(plan.Port.ValueInt64()),
	}

	if !plan.Check.IsUnknown() {
		req.Check = plan.Check.ValueString()
	}

	if !plan.Inter.IsUnknown() {
		req.Inter = uint64(plan.Inter.ValueInt64())
	}

	if !plan.DownInter.IsUnknown() {
		req.DownInter = uint64(plan.DownInter.ValueInt64())
	}

	if !plan.Rise.IsUnknown() {
		req.Rise = uint64(plan.Rise.ValueInt64())
	}

	if !plan.Fall.IsUnknown() {
		req.Fall = uint64(plan.Fall.ValueInt64())
	}

	if !plan.SlowStart.IsUnknown() {
		req.SlowStart = uint64(plan.SlowStart.ValueInt64())
	}

	if !plan.MaxConn.IsUnknown() {
		req.MaxConn = uint64(plan.MaxConn.ValueInt64())
	}

	if !plan.MaxQueue.IsUnknown() {
		req.MaxQueue = uint64(plan.MaxQueue.ValueInt64())
	}

	if !plan.Weight.IsUnknown() {
		req.Weight = uint64(plan.Weight.ValueInt64())
	}

	_, err := c.CloudAPI().LB().BackendServerUpdate(ctx, req)
	if err != nil {
		diags.AddError("UpdateLBBackendServer: cannot edit lb backend server", err.Error())
		return diags
	}

	tflog.Info(ctx, fmt.Sprintf("UpdateLBBackendServer: Finish edit lb backend server with name - %v", req.BackendName))

	return nil
}
