package getsvc

import (
	"context"

	"git.frostfs.info/TrueCloudLab/frostfs-node/internal/logs"
	"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/client"
	"go.uber.org/zap"
)

func (r *request) executeOnContainer(ctx context.Context) {
	if r.isLocal() {
		r.log.Debug(ctx, logs.GetReturnResultDirectly)
		return
	}

	lookupDepth := r.netmapLookupDepth()

	r.log.Debug(ctx, logs.TryingToExecuteInContainer,
		zap.Uint64("netmap lookup depth", lookupDepth),
	)

	// initialize epoch number
	ok := r.initEpoch(ctx)
	if !ok {
		return
	}

	localStatus := r.status

	for {
		if r.processCurrentEpoch(ctx, localStatus) {
			break
		}

		// check the maximum depth has been reached
		if lookupDepth == 0 {
			break
		}

		lookupDepth--

		// go to the previous epoch
		r.curProcEpoch--
	}
}

func (r *request) processCurrentEpoch(ctx context.Context, localStatus int) bool {
	r.log.Debug(ctx, logs.ProcessEpoch,
		zap.Uint64("number", r.curProcEpoch),
	)

	traverser, ok := r.generateTraverser(ctx, r.address())
	if !ok {
		return true
	}

	ctx, cancel := context.WithCancel(ctx)
	defer cancel()

	if localStatus == statusEC { // possible only for raw == true and local == false
		r.status = statusEC
	} else {
		r.status = statusUndefined
	}

	for {
		addrs := traverser.Next()
		if len(addrs) == 0 {
			r.log.Debug(ctx, logs.NoMoreNodesAbortPlacementIteration)

			return false
		}

		for i := range addrs {
			select {
			case <-ctx.Done():
				r.log.Debug(ctx, logs.InterruptPlacementIterationByContext,
					zap.Error(ctx.Err()),
				)

				return true
			default:
			}

			// TODO: #1142 consider parallel execution
			// TODO: #1142 consider optimization: if status == SPLIT we can continue until
			//  we reach the best result - split info with linking object ID.
			var info client.NodeInfo

			client.NodeInfoFromNetmapElement(&info, addrs[i])

			if r.processNode(ctx, info) {
				r.log.Debug(ctx, logs.GetCompletingTheOperation)
				return true
			}
		}
	}
}