package review

import (
	"context"
	"errors"
	"time"

	"juwan-backend/app/order/rpc/orderservice"
	"juwan-backend/app/review/api/internal/svc"
	"juwan-backend/app/review/api/internal/types"
	reviewpb "juwan-backend/app/review/rpc/pb"
	"juwan-backend/common/utils/contextj"

	"github.com/zeromicro/go-zero/core/logx"
)

type SubmitReviewLogic struct {
	logx.Logger
	ctx    context.Context
	svcCtx *svc.ServiceContext
}

func NewSubmitReviewLogic(ctx context.Context, svcCtx *svc.ServiceContext) *SubmitReviewLogic {
	return &SubmitReviewLogic{
		Logger: logx.WithContext(ctx),
		ctx:    ctx,
		svcCtx: svcCtx,
	}
}

func (l *SubmitReviewLogic) SubmitReview(req *types.SubmitReviewReq) (resp *types.EmptyResp, err error) {
	uid, err := contextj.UserIDFrom(l.ctx)
	if err != nil {
		return nil, err
	}

	orderResp, err := l.svcCtx.OrderRpc.GetOrdersById(l.ctx, &orderservice.GetOrdersByIdReq{Id: req.Id})
	if err != nil {
		return nil, err
	}
	order := orderResp.GetOrders()
	if order == nil {
		return nil, errors.New("order not found")
	}
	if order.GetStatus() != "pending_review" {
		return nil, errors.New("order is not in pending_review status")
	}

	consumerID, playerUserID, err := orderParticipantUserIDs(l.ctx, l.svcCtx, order)
	if err != nil {
		return nil, err
	}

	var fromUserId, toUserId int64
	if uid == consumerID {
		fromUserId = consumerID
		toUserId = playerUserID
	} else if uid == playerUserID {
		fromUserId = playerUserID
		toUserId = consumerID
	} else {
		return nil, errors.New("not a participant of this order")
	}

	_, err = l.svcCtx.ReviewRpc.AddReviews(l.ctx, &reviewpb.AddReviewsReq{
		OrderId:    req.Id,
		FromUserId: fromUserId,
		ToUserId:   toUserId,
		Rating:     int32(req.Rating),
		Content:    req.Content,
		Sealed:     true,
	})
	if err != nil {
		return nil, err
	}

	existing, err := l.svcCtx.ReviewRpc.SearchReviews(l.ctx, &reviewpb.SearchReviewsReq{
		Offset:  0,
		Limit:   2,
		OrderId: &req.Id,
	})
	if err != nil {
		return nil, err
	}

	if len(existing.GetReviews()) >= 2 {
		now := time.Now().Unix()
		sealed := false
		for _, r := range existing.GetReviews() {
			_, err = l.svcCtx.ReviewRpc.UpdateReviews(l.ctx, &reviewpb.UpdateReviewsReq{
				Id:         r.GetId(),
				Sealed:     &sealed,
				UnsealedAt: &now,
			})
			if err != nil {
				return nil, err
			}
		}

		completedStatus := "completed"
		completedAt := now
		updatedAt := now
		_, err = l.svcCtx.OrderRpc.UpdateOrders(l.ctx, &orderservice.UpdateOrdersReq{
			Id:          req.Id,
			Status:      &completedStatus,
			CompletedAt: &completedAt,
			UpdatedAt:   &updatedAt,
		})
		if err != nil {
			return nil, err
		}
	}

	return &types.EmptyResp{}, nil
}
