package control

import (
	"time"

	"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/engine"
	"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/control"
	"github.com/mr-tron/base58"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
)

func stateToResponse(state *engine.EvacuationState) (*control.GetShardEvacuationStatusResponse, error) {
	shardIDs := make([][]byte, 0, len(state.ShardIDs()))
	for _, shID := range state.ShardIDs() {
		id, err := base58.Decode(shID)
		if err != nil {
			return nil, status.Error(codes.Internal, "invalid shard id format: "+shID)
		}
		shardIDs = append(shardIDs, id)
	}
	var evacStatus control.GetShardEvacuationStatusResponse_Body_Status
	switch state.ProcessingStatus() {
	case engine.EvacuateProcessStateRunning:
		evacStatus = control.GetShardEvacuationStatusResponse_Body_RUNNING
	case engine.EvacuateProcessStateCompleted:
		evacStatus = control.GetShardEvacuationStatusResponse_Body_COMPLETED
	default:
		evacStatus = control.GetShardEvacuationStatusResponse_Body_EVACUATE_SHARD_STATUS_UNDEFINED
	}
	var startedAt *control.GetShardEvacuationStatusResponse_Body_UnixTimestamp
	if state.StartedAt() != nil {
		startedAt = &control.GetShardEvacuationStatusResponse_Body_UnixTimestamp{
			Value: state.StartedAt().Unix(),
		}
	}
	var duration *control.GetShardEvacuationStatusResponse_Body_Duration
	if state.StartedAt() != nil {
		end := time.Now().UTC()
		if state.FinishedAt() != nil {
			end = *state.FinishedAt()
		}
		duration = &control.GetShardEvacuationStatusResponse_Body_Duration{
			Seconds: int64(end.Sub(*state.StartedAt()).Seconds()),
		}
	}
	return &control.GetShardEvacuationStatusResponse{
		Body: &control.GetShardEvacuationStatusResponse_Body{
			Shard_ID:         shardIDs,
			EvacuatedObjects: state.ObjectsEvacuated(),
			TotalObjects:     state.ObjectsTotal(),
			FailedObjects:    state.ObjectsFailed(),
			Status:           evacStatus,
			StartedAt:        startedAt,
			Duration:         duration,
			ErrorMessage:     state.ErrorMessage(),
			SkippedObjects:   state.ObjectsSkipped(),
			TotalTrees:       state.TreesTotal(),
			EvacuatedTrees:   state.TreesEvacuated(),
			FailedTrees:      state.TreesFailed(),
		},
	}, nil
}