package flattens

import (
	"context"
	"encoding/json"

	"github.com/google/uuid"
	"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/terraform-provider-dynamix/internal/client"
	"repository.basistech.ru/BASIS/terraform-provider-dynamix/internal/service/cloudbroker/rg/models"
	"repository.basistech.ru/BASIS/terraform-provider-dynamix/internal/service/cloudbroker/rg/utilities"
)

// RGListLBDataSource flattens data source for rg list lb.
// Return error in case data source is not found on the platform.
// Flatten errors are added to tflog.
func RGListLBDataSource(ctx context.Context, state *models.DataSourceRGListLBModel, c *client.Client) diag.Diagnostics {
	tflog.Info(ctx, "Start flattens.RGListLBDataSource")

	diags := diag.Diagnostics{}

	rgListLB, err := utilities.RGListLBCheckPresence(ctx, state, c)
	if err != nil {
		diags.AddError("Cannot get info about resource group list lb", err.Error())
		return diags
	}

	tflog.Info(ctx, "flattens.RGListLBDataSource: before flatten")

	id := uuid.New()
	*state = models.DataSourceRGListLBModel{
		RGID:       state.RGID,
		ByID:       state.ByID,
		Name:       state.Name,
		TechStatus: state.TechStatus,
		Status:     state.Status,
		FrontIP:    state.FrontIP,
		BackIP:     state.BackIP,
		SortBy:     state.SortBy,
		Page:       state.Page,
		Size:       state.Size,
		Timeouts:   state.Timeouts,

		Id: types.StringValue(id.String()),
	}

	items := make([]models.ItemsRGListLBModel, 0, len(rgListLB.Data))
	for _, lbItem := range rgListLB.Data {
		acl, _ := json.Marshal(lbItem.ACL)
		item := models.ItemsRGListLBModel{
			HAMode:      types.BoolValue(lbItem.HAMode),
			ACL:         types.StringValue(string(acl)),
			CreatedBy:   types.StringValue(lbItem.CreatedBy),
			CreatedTime: types.Int64Value(int64(lbItem.CreatedTime)),
			DeletedBy:   types.StringValue(lbItem.DeletedBy),
			DeletedTime: types.Int64Value(int64(lbItem.DeletedTime)),
			Description: types.StringValue(lbItem.Description),
			DPAPIUser:   types.StringValue(lbItem.DPAPIUser),
			ExtNetID:    types.Int64Value(int64(lbItem.ExtNetID)),
			GID:         types.Int64Value(int64(lbItem.GID)),
			GUID:        types.Int64Value(int64(lbItem.GUID)),
			ID:          types.Int64Value(int64(lbItem.ID)),
			ImageID:     types.Int64Value(int64(lbItem.ImageID)),
			Milestones:  types.Int64Value(int64(lbItem.Milestones)),
			Name:        types.StringValue(lbItem.Name),
			PrimaryNode: models.RecordNodeModel{
				BackendIP:  types.StringValue(lbItem.PrimaryNode.BackendIP),
				ComputeID:  types.Int64Value(int64(lbItem.PrimaryNode.ComputeID)),
				FrontendIP: types.StringValue(lbItem.PrimaryNode.FrontendIP),
				GUID:       types.StringValue(lbItem.PrimaryNode.GUID),
				MGMTIP:     types.StringValue(lbItem.PrimaryNode.MGMTIP),
				NetworkID:  types.Int64Value(int64(lbItem.PrimaryNode.NetworkID)),
			},
			RGName: types.StringValue(lbItem.RGName),
			SecondaryNode: models.RecordNodeModel{
				BackendIP:  types.StringValue(lbItem.SecondaryNode.BackendIP),
				ComputeID:  types.Int64Value(int64(lbItem.SecondaryNode.ComputeID)),
				FrontendIP: types.StringValue(lbItem.SecondaryNode.FrontendIP),
				GUID:       types.StringValue(lbItem.SecondaryNode.GUID),
				MGMTIP:     types.StringValue(lbItem.SecondaryNode.MGMTIP),
				NetworkID:  types.Int64Value(int64(lbItem.SecondaryNode.NetworkID)),
			},
			Status:      types.StringValue(lbItem.Status),
			TechStatus:  types.StringValue(lbItem.TechStatus),
			UpdatedBy:   types.StringValue(lbItem.UpdatedBy),
			UpdatedTime: types.Int64Value(int64(lbItem.UpdatedTime)),
			VINSID:      types.Int64Value(int64(lbItem.VINSID)),
		}

		// flatten Backends
		backends := make([]models.ItemBackendModel, 0, len(lbItem.Backends))
		for _, backendItem := range lbItem.Backends {
			be := models.ItemBackendModel{
				Algorithm: types.StringValue(backendItem.Algorithm),
				GUID:      types.StringValue(backendItem.GUID),
				Name:      types.StringValue(backendItem.Name),
				ServerDefaultSettings: models.RecordServerSettingsModel{
					Inter:     types.Int64Value(int64(backendItem.ServerDefaultSettings.Inter)),
					GUID:      types.StringValue(backendItem.ServerDefaultSettings.GUID),
					DownInter: types.Int64Value(int64(backendItem.ServerDefaultSettings.DownInter)),
					Rise:      types.Int64Value(int64(backendItem.ServerDefaultSettings.Rise)),
					Fall:      types.Int64Value(int64(backendItem.ServerDefaultSettings.Fall)),
					SlowStart: types.Int64Value(int64(backendItem.ServerDefaultSettings.SlowStart)),
					MaxConn:   types.Int64Value(int64(backendItem.ServerDefaultSettings.MaxConn)),
					MaxQueue:  types.Int64Value(int64(backendItem.ServerDefaultSettings.MaxQueue)),
					Weight:    types.Int64Value(int64(backendItem.ServerDefaultSettings.Weight)),
				},
			}

			servers := make([]models.ItemServerModel, 0, len(backendItem.Servers))
			for _, server := range backendItem.Servers {
				s := models.ItemServerModel{
					Address: types.StringValue(server.Address),
					Check:   types.StringValue(server.Check),
					GUID:    types.StringValue(server.GUID),
					Name:    types.StringValue(server.Name),
					Port:    types.Int64Value(int64(server.Port)),
					ServerSettings: models.RecordServerSettingsModel{
						Inter:     types.Int64Value(int64(server.ServerSettings.Inter)),
						GUID:      types.StringValue(server.ServerSettings.GUID),
						DownInter: types.Int64Value(int64(server.ServerSettings.DownInter)),
						Rise:      types.Int64Value(int64(server.ServerSettings.Rise)),
						Fall:      types.Int64Value(int64(server.ServerSettings.Fall)),
						SlowStart: types.Int64Value(int64(server.ServerSettings.SlowStart)),
						MaxConn:   types.Int64Value(int64(server.ServerSettings.MaxConn)),
						MaxQueue:  types.Int64Value(int64(server.ServerSettings.MaxQueue)),
						Weight:    types.Int64Value(int64(server.ServerSettings.Weight)),
					},
				}
				servers = append(servers, s)
			}
			be.Servers = servers
			backends = append(backends, be)
		}
		item.Backends = backends

		// flatten Frontends
		frontends := make([]models.ItemFrontendModel, 0, len(lbItem.Frontends))
		for _, frontendItem := range lbItem.Frontends {
			fr := models.ItemFrontendModel{
				Backend: types.StringValue(frontendItem.Backend),
				GUID:    types.StringValue(frontendItem.GUID),
				Name:    types.StringValue(frontendItem.Name),
			}
			bindings := make([]models.ItemBindingModel, 0, len(frontendItem.Bindings))
			for _, bingingItem := range frontendItem.Bindings {
				b := models.ItemBindingModel{
					Address: types.StringValue(bingingItem.Address),
					GUID:    types.StringValue(bingingItem.GUID),
					Name:    types.StringValue(bingingItem.Name),
					Port:    types.Int64Value(int64(bingingItem.Port)),
				}
				bindings = append(bindings, b)
			}
			fr.Bindings = bindings
			frontends = append(frontends, fr)
		}
		item.Frontends = frontends

		items = append(items, item)
	}

	state.Items = items
	state.EntryCount = types.Int64Value(int64(rgListLB.EntryCount))

	tflog.Info(ctx, "flattens.RGListLBDataSource: after flatten")

	tflog.Info(ctx, "End flattens.RGListLBDataSource")
	return nil
}
