package grpc

import (
	"context"

	activityv1 "hyapp.local/api/proto/activity/v1"
	"hyapp/pkg/appcode"
	"hyapp/pkg/xerr"
	messagedomain "hyapp/services/activity-service/internal/domain/message"
	messageservice "hyapp/services/activity-service/internal/service/message"
)

// ActionConfirmServer adapts generic IM action confirmations to gRPC.
type ActionConfirmServer struct {
	activityv1.UnimplementedMessageActionConfirmServiceServer

	svc *messageservice.ActionConfirmService
}

func NewActionConfirmServer(svc *messageservice.ActionConfirmService) *ActionConfirmServer {
	return &ActionConfirmServer{svc: svc}
}

func (s *ActionConfirmServer) AcceptActionConfirm(ctx context.Context, req *activityv1.AcceptActionConfirmRequest) (*activityv1.AcceptActionConfirmResponse, error) {
	if s.svc == nil {
		return nil, xerr.ToGRPCError(xerr.New(xerr.Unavailable, "action confirm service is not configured"))
	}
	ctx = appcode.WithContext(ctx, req.GetMeta().GetAppCode())
	confirm, err := s.svc.AcceptActionConfirm(ctx, req.GetActorUserId(), req.GetConfirmId(), req.GetCommandId())
	if err != nil {
		return nil, xerr.ToGRPCError(err)
	}
	return &activityv1.AcceptActionConfirmResponse{Confirm: actionConfirmProto(confirm)}, nil
}

func (s *ActionConfirmServer) RejectActionConfirm(ctx context.Context, req *activityv1.RejectActionConfirmRequest) (*activityv1.RejectActionConfirmResponse, error) {
	if s.svc == nil {
		return nil, xerr.ToGRPCError(xerr.New(xerr.Unavailable, "action confirm service is not configured"))
	}
	ctx = appcode.WithContext(ctx, req.GetMeta().GetAppCode())
	confirm, err := s.svc.RejectActionConfirm(ctx, req.GetActorUserId(), req.GetConfirmId(), req.GetCommandId(), req.GetReason())
	if err != nil {
		return nil, xerr.ToGRPCError(err)
	}
	return &activityv1.RejectActionConfirmResponse{Confirm: actionConfirmProto(confirm)}, nil
}

func (s *ActionConfirmServer) BatchGetActionConfirmStatus(ctx context.Context, req *activityv1.BatchGetActionConfirmStatusRequest) (*activityv1.BatchGetActionConfirmStatusResponse, error) {
	if s.svc == nil {
		return nil, xerr.ToGRPCError(xerr.New(xerr.Unavailable, "action confirm service is not configured"))
	}
	ctx = appcode.WithContext(ctx, req.GetMeta().GetAppCode())
	items, err := s.svc.BatchGetActionConfirmStatus(ctx, req.GetUserId(), req.GetConfirmIds())
	if err != nil {
		return nil, xerr.ToGRPCError(err)
	}
	resp := &activityv1.BatchGetActionConfirmStatusResponse{Items: make([]*activityv1.ActionConfirm, 0, len(items))}
	for _, item := range items {
		resp.Items = append(resp.Items, actionConfirmProto(item))
	}
	return resp, nil
}

func (s *ActionConfirmServer) ListConversationActionConfirms(ctx context.Context, req *activityv1.ListConversationActionConfirmsRequest) (*activityv1.ListConversationActionConfirmsResponse, error) {
	if s.svc == nil {
		return nil, xerr.ToGRPCError(xerr.New(xerr.Unavailable, "action confirm service is not configured"))
	}
	ctx = appcode.WithContext(ctx, req.GetMeta().GetAppCode())
	items, nextPageToken, err := s.svc.ListConversationActionConfirms(ctx, req.GetUserId(), req.GetPeerUserId(), req.GetPageSize(), req.GetPageToken())
	if err != nil {
		return nil, xerr.ToGRPCError(err)
	}
	resp := &activityv1.ListConversationActionConfirmsResponse{Items: make([]*activityv1.ActionConfirm, 0, len(items)), NextPageToken: nextPageToken}
	for _, item := range items {
		resp.Items = append(resp.Items, actionConfirmProto(item))
	}
	return resp, nil
}

func actionConfirmProto(confirm messagedomain.ActionConfirm) *activityv1.ActionConfirm {
	return &activityv1.ActionConfirm{
		ConfirmId:       confirm.ConfirmID,
		BusinessType:    confirm.BusinessType,
		BusinessSubtype: confirm.BusinessSubtype,
		BusinessId:      confirm.BusinessID,
		SenderUserId:    confirm.SenderUserID,
		ReceiverUserId:  confirm.ReceiverUserID,
		Status:          confirm.Status,
		Action:          confirm.Action,
		ProcessedAtMs:   confirm.ProcessedAtMS,
		CreatedAtMs:     confirm.CreatedAtMS,
		UpdatedAtMs:     confirm.UpdatedAtMS,
	}
}
