package control

import (
	"fmt"
	"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, fmt.Sprintf("invalid shard id format: %s", 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,
			Evacuated:    state.Evacuated(),
			Total:        state.Total(),
			Failed:       state.Failed(),
			Status:       evacStatus,
			StartedAt:    startedAt,
			Duration:     duration,
			ErrorMessage: state.ErrorMessage(),
		},
	}, nil
}