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/vins"
	"repository.basistech.ru/BASIS/terraform-provider-dynamix/internal/client"
	"repository.basistech.ru/BASIS/terraform-provider-dynamix/internal/service/cloudapi/vins/models"
)

func VINSStaticRouteResourceCheckPresence(ctx context.Context, vinsId, routeId uint64, c *client.Client) (*vins.ItemRoutes, diag.Diagnostics) {
	tflog.Info(ctx, "VINSStaticRouteResourceCheckPresence: Get info about vins static route")

	diags := diag.Diagnostics{}

	tflog.Info(ctx, "VINSStaticRouteResourceCheckPresence: before call to CloudAPI().VINS().StaticRouteList", map[string]any{"vins_id": vinsId, "route_id": routeId})
	staticRouteList, err := c.CloudAPI().VINS().StaticRouteList(ctx, vins.StaticRouteListRequest{VINSID: vinsId})
	if err != nil {
		diags.AddError(
			fmt.Sprintf("VINSStaticRouteResourceCheckPresence: Cannot get info about vins static route %v", vinsId),
			err.Error())
		return nil, diags
	}

	tflog.Info(ctx, "VINSStaticRouteResourceCheckPresence: response from CloudAPI().VINS().StaticRouteList", map[string]any{"vins_id": vinsId, "response": staticRouteList})

	staticRoute := &vins.ItemRoutes{}
	for _, route := range staticRouteList.Data {
		if routeId == route.ID {
			staticRoute = &route
			return staticRoute, nil
		}
	}

	diags.AddError(
		"VINSStaticRouteResourceCheckPresence: static route not found",
		fmt.Sprintf("static route not found for route_id=%d and vins_id=%d", routeId, vinsId))

	return nil, diags

}

func GetVinsIDAndRouteID(ctx context.Context, plan *models.ResourceVINSStaticRouteModel) (uint64, uint64, diag.Diagnostics) {
	tflog.Info(ctx, "Start GetVinsIDAndRouteID")

	var err error
	diags := diag.Diagnostics{}

	vinsId := uint64(plan.VinsID.ValueInt64())
	routeId := uint64(plan.RouteID.ValueInt64())

	if plan.Id.ValueString() != "" {
		vals := strings.Split(plan.Id.ValueString(), "#")
		if len(vals) != 2 {
			diags.AddError(
				"GetVinsIDAndRouteID: broken state id",
				fmt.Sprintf("state id expected: <vins_id>#<route_id>, got: %v", plan.Id.ValueString()))
			return 0, 0, diags
		}

		vinsId, err = strconv.ParseUint(vals[0], 10, 64)
		if err != nil {
			diags.AddError("GetVinsIDAndRouteID: can not parse vinsId from state", err.Error())
			return 0, 0, diags
		}

		routeId, err = strconv.ParseUint(vals[1], 10, 64)
		if err != nil {
			diags.AddError("GetVinsIDAndRouteID: can not parse routeId from state", err.Error())
			return 0, 0, diags
		}
	}

	return vinsId, routeId, nil
}

func GetStaticRouteID(ctx context.Context, plan *models.ResourceVINSStaticRouteModel, c *client.Client) (uint64, diag.Diagnostics) {
	tflog.Info(ctx, "Start GetStaticRouteID")

	diags := diag.Diagnostics{}

	vinsId := uint64(plan.VinsID.ValueInt64())

	tflog.Info(ctx, "GetStaticRouteID: before call to CloudAPI().VINS().StaticRouteList", map[string]any{"vins_id": vinsId})
	staticRouteList, err := c.CloudAPI().VINS().StaticRouteList(ctx, vins.StaticRouteListRequest{VINSID: vinsId})
	if err != nil {
		diags.AddError(
			fmt.Sprintf("GetStaticRouteID: Cannot get info about vins static routes %v", vinsId),
			err.Error())
		return 0, diags
	}

	tflog.Info(ctx, "GetStaticRouteID: response from CloudAPI().VINS().StaticRouteList", map[string]any{"vins_id": vinsId, "response": staticRouteList})

	destination := plan.Destination.ValueString()
	gateway := plan.Gateway.ValueString()

	staticRoute := &vins.ItemRoutes{}
	for _, route := range staticRouteList.Data {
		if destination == route.Destination && gateway == route.Gateway {
			staticRoute = &route
			return staticRoute.ID, nil
		}
	}

	diags.AddError(
		"GetStaticRouteID: static route not found",
		fmt.Sprintf("Static route (destination=%s, gateway=%s) not found for vins with vins_id=%d", destination, gateway, vinsId))

	return 0, diags
}

// contains returns true if slice contains element. Otherwise it returns false.
func contains(element uint64, slice []uint64) bool {
	for _, s := range slice {
		if s == element {
			return true
		}
	}
	return false
}
