package robotclient

import (
	"context"
	"fmt"
	"strings"
	"time"

	"hyapp-admin-server/internal/appctx"
	robotv1 "hyapp.local/api/proto/robot/v1"

	"google.golang.org/grpc"
)

type Client interface {
	ListGameRobots(ctx context.Context, req ListGameRobotsRequest) (ListGameRobotsResult, error)
	ListRoomRobots(ctx context.Context, req ListRoomRobotsRequest) (ListRoomRobotsResult, error)
}

type Robot struct {
	UserID       int64
	Status       string
	RoomScene    string
	CreatedAtMS  int64
	UpdatedAtMS  int64
	LastUsedAtMS int64
	UsedCount    int64
}

type ListRoomRobotsRequest struct {
	RoomScene string
	Status    string
	PageSize  int32
	Cursor    string
}

type ListGameRobotsRequest struct {
	GameID   string
	Status   string
	PageSize int32
	Cursor   string
}

type ListRoomRobotsResult struct {
	Robots       []Robot
	NextCursor   string
	ServerTimeMS int64
}

type ListGameRobotsResult struct {
	Robots       []Robot
	NextCursor   string
	ServerTimeMS int64
}

type GRPCClient struct {
	gameClient robotv1.GameRobotServiceClient
	roomClient robotv1.RoomRobotServiceClient
}

func NewGRPC(conn grpc.ClientConnInterface) *GRPCClient {
	return &GRPCClient{
		gameClient: robotv1.NewGameRobotServiceClient(conn),
		roomClient: robotv1.NewRoomRobotServiceClient(conn),
	}
}

func (c *GRPCClient) ListGameRobots(ctx context.Context, req ListGameRobotsRequest) (ListGameRobotsResult, error) {
	if c == nil || c.gameClient == nil {
		return ListGameRobotsResult{}, fmt.Errorf("game robot service client is not configured")
	}
	resp, err := c.gameClient.ListGameRobots(ctx, &robotv1.ListGameRobotsRequest{
		Meta:     requestMeta(ctx, "admin-game-robots"),
		GameId:   strings.TrimSpace(req.GameID),
		Status:   strings.TrimSpace(req.Status),
		PageSize: req.PageSize,
		Cursor:   strings.TrimSpace(req.Cursor),
	})
	if err != nil {
		return ListGameRobotsResult{}, err
	}
	return ListGameRobotsResult{Robots: robotsFromProto(resp.GetRobots()), NextCursor: resp.GetNextCursor(), ServerTimeMS: resp.GetServerTimeMs()}, nil
}

func (c *GRPCClient) ListRoomRobots(ctx context.Context, req ListRoomRobotsRequest) (ListRoomRobotsResult, error) {
	if c == nil || c.roomClient == nil {
		return ListRoomRobotsResult{}, fmt.Errorf("robot service client is not configured")
	}
	resp, err := c.roomClient.ListRoomRobots(ctx, &robotv1.ListRoomRobotsRequest{
		Meta:      requestMeta(ctx, "admin-room-robots"),
		RoomScene: strings.TrimSpace(req.RoomScene),
		Status:    strings.TrimSpace(req.Status),
		PageSize:  req.PageSize,
		Cursor:    strings.TrimSpace(req.Cursor),
	})
	if err != nil {
		return ListRoomRobotsResult{}, err
	}
	return ListRoomRobotsResult{Robots: robotsFromProto(resp.GetRobots()), NextCursor: resp.GetNextCursor(), ServerTimeMS: resp.GetServerTimeMs()}, nil
}

func requestMeta(ctx context.Context, prefix string) *robotv1.RequestMeta {
	return &robotv1.RequestMeta{
		RequestId:   fmt.Sprintf("%s-%d", prefix, time.Now().UnixMilli()),
		Caller:      "admin-server",
		AppCode:     appctx.FromContext(ctx),
		SentAtMs:    time.Now().UnixMilli(),
		ActorUserId: 0,
	}
}

func robotsFromProto(source []*robotv1.Robot) []Robot {
	items := make([]Robot, 0, len(source))
	for _, item := range source {
		items = append(items, Robot{
			UserID:       item.GetUserId(),
			Status:       item.GetStatus(),
			RoomScene:    item.GetRoomScene(),
			CreatedAtMS:  item.GetCreatedAtMs(),
			UpdatedAtMS:  item.GetUpdatedAtMs(),
			LastUsedAtMS: item.GetLastUsedAtMs(),
			UsedCount:    item.GetUsedCount(),
		})
	}
	return items
}
