package client

import (
	"context"

	"google.golang.org/grpc"
	robotv1 "hyapp.local/api/proto/robot/v1"
	"hyapp/pkg/appcode"
	dicedomain "hyapp/services/game-service/internal/domain/dice"
)

// GameRobotClient 是 game-service 到 robot-service 的薄适配层；旧 dice service 只依赖领域 Robot，不直接依赖 robot proto。
type GameRobotClient struct {
	client robotv1.GameRobotServiceClient
}

func NewGameRobotClient(conn *grpc.ClientConn) *GameRobotClient {
	return &GameRobotClient{client: robotv1.NewGameRobotServiceClient(conn)}
}

func (c *GameRobotClient) PickActiveDiceRobot(ctx context.Context, appCode string, gameID string, matchID string, excludeUserIDs []int64, nowMS int64) (dicedomain.Robot, error) {
	resp, err := c.client.PickGameRobot(ctx, &robotv1.PickGameRobotRequest{
		Meta:           robotMeta(appCode),
		GameId:         gameID,
		MatchId:        matchID,
		SelectedAtMs:   nowMS,
		ExcludeUserIds: excludeUserIDs,
	})
	if err != nil {
		return dicedomain.Robot{}, err
	}
	return diceRobotFromProto(resp.GetRobot()), nil
}

func (c *GameRobotClient) ListDiceRobots(ctx context.Context, appCode string, gameID string, status string, pageSize int32, cursor string) ([]dicedomain.Robot, string, error) {
	resp, err := c.client.ListGameRobots(ctx, &robotv1.ListGameRobotsRequest{
		Meta:     robotMeta(appCode),
		GameId:   gameID,
		Status:   status,
		PageSize: pageSize,
		Cursor:   cursor,
	})
	if err != nil {
		return nil, "", err
	}
	items := make([]dicedomain.Robot, 0, len(resp.GetRobots()))
	for _, item := range resp.GetRobots() {
		items = append(items, diceRobotFromProto(item))
	}
	return items, resp.GetNextCursor(), nil
}

func (c *GameRobotClient) RegisterDiceRobots(ctx context.Context, appCode string, gameID string, userIDs []int64, adminID int64, nowMS int64) ([]dicedomain.Robot, error) {
	resp, err := c.client.RegisterGameRobots(ctx, &robotv1.RegisterGameRobotsRequest{
		Meta:    robotMetaWithActor(appCode, adminID),
		GameId:  gameID,
		UserIds: userIDs,
	})
	if err != nil {
		return nil, err
	}
	items := make([]dicedomain.Robot, 0, len(resp.GetRobots()))
	for _, item := range resp.GetRobots() {
		items = append(items, diceRobotFromProto(item))
	}
	return items, nil
}

func (c *GameRobotClient) SetDiceRobotStatus(ctx context.Context, appCode string, gameID string, userID int64, status string, nowMS int64) (dicedomain.Robot, error) {
	resp, err := c.client.SetGameRobotStatus(ctx, &robotv1.SetGameRobotStatusRequest{
		Meta:   robotMeta(appCode),
		GameId: gameID,
		UserId: userID,
		Status: status,
	})
	if err != nil {
		return dicedomain.Robot{}, err
	}
	return diceRobotFromProto(resp.GetRobot()), nil
}

func (c *GameRobotClient) DeleteDiceRobot(ctx context.Context, appCode string, gameID string, userID int64) error {
	_, err := c.client.DeleteGameRobot(ctx, &robotv1.DeleteGameRobotRequest{
		Meta:   robotMeta(appCode),
		GameId: gameID,
		UserId: userID,
	})
	return err
}

func robotMeta(appCode string) *robotv1.RequestMeta {
	return robotMetaWithActor(appCode, 0)
}

func robotMetaWithActor(appCode string, actorUserID int64) *robotv1.RequestMeta {
	return &robotv1.RequestMeta{
		Caller:      "game-service",
		ActorUserId: actorUserID,
		AppCode:     appcode.Normalize(appCode),
	}
}

func diceRobotFromProto(item *robotv1.Robot) dicedomain.Robot {
	if item == nil {
		return dicedomain.Robot{}
	}
	return dicedomain.Robot{
		AppCode:          item.GetAppCode(),
		GameID:           item.GetGameId(),
		UserID:           item.GetUserId(),
		Status:           item.GetStatus(),
		CreatedByAdminID: item.GetCreatedByAdminId(),
		CreatedAtMS:      item.GetCreatedAtMs(),
		UpdatedAtMS:      item.GetUpdatedAtMs(),
		LastUsedAtMS:     item.GetLastUsedAtMs(),
		UsedCount:        item.GetUsedCount(),
	}
}
