import * as z from "zod";

import { LOBBY_STATUSES } from "../constants.js";
import { GameQuestionSchema } from "./game.js";

export const LobbyPlayerSchema = z.object({
  lobbyId: z.uuid(),
  userId: z.string(),
  score: z.number().int().min(0),
  user: z.object({ id: z.string(), name: z.string() }),
});

export type LobbyPlayer = z.infer<typeof LobbyPlayerSchema>;

export const LobbySchema = z.object({
  id: z.uuid(),
  code: z.string().min(1).max(10),
  hostUserId: z.string(),
  status: z.enum(LOBBY_STATUSES),
  createdAt: z.iso.datetime(),
  players: z.array(LobbyPlayerSchema),
});

export type Lobby = z.infer<typeof LobbySchema>;

export const JoinLobbyResponseSchema = LobbySchema;

export type JoinLobbyResponse = z.infer<typeof JoinLobbyResponseSchema>;

export const GameRouteSearchSchema = z.object({ lobbyId: z.uuid() });
export type GameRouteSearch = z.infer<typeof GameRouteSearchSchema>;

// ----------------------------------------------------------------------------
// WebSocket: Client → Server
// ----------------------------------------------------------------------------

export const WsLobbyJoinSchema = z.object({
  type: z.literal("lobby:join"),
  code: z.string().min(1).max(10),
});

export type WsLobbyJoin = z.infer<typeof WsLobbyJoinSchema>;

export const WsLobbyLeaveSchema = z.object({
  type: z.literal("lobby:leave"),
  lobbyId: z.uuid(),
});

export type WsLobbyLeave = z.infer<typeof WsLobbyLeaveSchema>;

export const WsLobbyStartSchema = z.object({
  type: z.literal("lobby:start"),
  lobbyId: z.uuid(),
});

export type WsLobbyStart = z.infer<typeof WsLobbyStartSchema>;

export const WsGameReadySchema = z.object({
  type: z.literal("game:ready"),
  lobbyId: z.uuid(),
});
export type WsGameReady = z.infer<typeof WsGameReadySchema>;

export const WsGameAnswerSchema = z.object({
  type: z.literal("game:answer"),
  lobbyId: z.uuid(),
  questionId: z.uuid(),
  selectedOptionId: z.number().int().min(0).max(3),
});

export type WsGameAnswer = z.infer<typeof WsGameAnswerSchema>;

export const WsClientMessageSchema = z.discriminatedUnion("type", [
  WsLobbyJoinSchema,
  WsLobbyLeaveSchema,
  WsLobbyStartSchema,
  WsGameAnswerSchema,
  WsGameReadySchema,
]);
export type WsClientMessage = z.infer<typeof WsClientMessageSchema>;

// ----------------------------------------------------------------------------
// WebSocket: Server → Client
// ----------------------------------------------------------------------------

export const WsLobbyStateSchema = z.object({
  type: z.literal("lobby:state"),
  lobby: LobbySchema,
});

export type WsLobbyState = z.infer<typeof WsLobbyStateSchema>;

export const WsGameQuestionSchema = z.object({
  type: z.literal("game:question"),
  question: GameQuestionSchema,
  questionNumber: z.number().int().min(1),
  totalQuestions: z.number().int().min(1),
});

export type WsGameQuestion = z.infer<typeof WsGameQuestionSchema>;

export const WsGameAnswerResultSchema = z.object({
  type: z.literal("game:answer_result"),
  correctOptionId: z.number().int().min(0).max(3),
  results: z.array(
    z.object({
      userId: z.string(),
      selectedOptionId: z.number().int().min(0).max(3).nullable(),
      isCorrect: z.boolean(),
    }),
  ),
  players: z.array(LobbyPlayerSchema),
});

export type WsGameAnswerResult = z.infer<typeof WsGameAnswerResultSchema>;

export const WsGameFinishedSchema = z.object({
  type: z.literal("game:finished"),
  players: z.array(LobbyPlayerSchema),
  winnerIds: z.array(z.string()),
});

export type WsGameFinished = z.infer<typeof WsGameFinishedSchema>;

export const WsErrorSchema = z.object({
  type: z.literal("error"),
  code: z.string(),
  message: z.string(),
});
export type WsError = z.infer<typeof WsErrorSchema>;

export const WsServerMessageSchema = z.discriminatedUnion("type", [
  WsLobbyStateSchema,
  WsGameQuestionSchema,
  WsGameAnswerResultSchema,
  WsGameFinishedSchema,
  WsErrorSchema,
]);

export type WsServerMessage = z.infer<typeof WsServerMessageSchema>;
