package netmap

import (
	"context"

	"git.frostfs.info/TrueCloudLab/frostfs-node/internal/logs"
	"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/innerring/processors/governance"
	netmapEvent "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/event/netmap"
	"go.uber.org/zap"
)

// Process new epoch notification by setting global epoch value and resetting
// local epoch timer.
func (np *Processor) processNewEpoch(ctx context.Context, ev netmapEvent.NewEpoch) bool {
	epoch := ev.EpochNumber()

	epochDuration, err := np.netmapClient.EpochDuration(ctx)
	if err != nil {
		np.log.Warn(ctx, logs.NetmapCantGetEpochDuration,
			zap.Error(err))
	} else {
		np.epochState.SetEpochDuration(epochDuration)
	}

	np.epochState.SetEpochCounter(epoch)

	h, err := np.netmapClient.MorphTxHeight(ev.TxHash())
	if err != nil {
		np.log.Warn(ctx, logs.NetmapCantGetTransactionHeight,
			zap.String("hash", ev.TxHash().StringLE()),
			zap.Error(err))
	}

	if err := np.epochTimer.ResetEpochTimer(h); err != nil {
		np.log.Warn(ctx, logs.NetmapCantResetEpochTimer,
			zap.Error(err))
	}

	// get new netmap snapshot
	networkMap, err := np.netmapClient.NetMap(ctx)
	if err != nil {
		np.log.Warn(ctx, logs.NetmapCantGetNetmapSnapshotToPerformCleanup,
			zap.Error(err))

		return false
	}

	np.netmapSnapshot.update(*networkMap, epoch)
	np.handleCleanupTick(ctx, netmapCleanupTick{epoch: epoch, txHash: ev.TxHash()})
	np.handleAlphabetSync(ctx, governance.NewSyncEvent(ev.TxHash()))
	np.handleNotaryDeposit(ctx, ev)

	return true
}

// Process new epoch tick by invoking new epoch method in network map contract.
func (np *Processor) processNewEpochTick(ctx context.Context) bool {
	if !np.alphabetState.IsAlphabet(ctx) {
		np.log.Info(ctx, logs.NetmapNonAlphabetModeIgnoreNewEpochTick)
		return true
	}

	nextEpoch := np.epochState.EpochCounter() + 1
	np.log.Debug(ctx, logs.NetmapNextEpoch, zap.Uint64("value", nextEpoch))

	err := np.netmapClient.NewEpoch(ctx, nextEpoch)
	if err != nil {
		np.log.Error(ctx, logs.NetmapCantInvokeNetmapNewEpoch, zap.Error(err))
		return false
	}

	return true
}