export const CommandType = {
  RegisterUser:            'register-user',
  UpsertServer:            'upsert-server',
  DeleteServer:            'delete-server',
  CreateJoinRequest:       'create-join-request',
  UpdateJoinRequestStatus: 'update-join-request-status',
  DeleteStaleJoinRequests: 'delete-stale-join-requests'
} as const;

export type CommandTypeKey = typeof CommandType[keyof typeof CommandType];

export const QueryType = {
  GetUserByUsername:           'get-user-by-username',
  GetUserById:                 'get-user-by-id',
  GetAllPublicServers:         'get-all-public-servers',
  GetFeaturedServers:          'get-featured-servers',
  GetTrendingServers:          'get-trending-servers',
  GetServerById:               'get-server-by-id',
  GetJoinRequestById:          'get-join-request-by-id',
  GetPendingRequestsForServer: 'get-pending-requests-for-server'
} as const;

export type QueryTypeKey = typeof QueryType[keyof typeof QueryType];

export interface AuthUserPayload {
  id: string;
  username: string;
  passwordHash: string;
  displayName: string;
  createdAt: number;
  signingPublicKey?: string | null;
}

export type ServerChannelType = 'text' | 'voice';

export interface ServerChannelPayload {
  id: string;
  name: string;
  type: ServerChannelType;
  position: number;
}

export type PermissionStatePayload = 'allow' | 'deny' | 'inherit';

export type ServerPermissionKeyPayload =
  | 'manageServer'
  | 'manageRoles'
  | 'manageChannels'
  | 'manageIcon'
  | 'kickMembers'
  | 'banMembers'
  | 'manageBans'
  | 'deleteMessages'
  | 'joinVoice'
  | 'shareScreen'
  | 'uploadFiles';

export interface AccessRolePayload {
  id: string;
  name: string;
  color?: string;
  position: number;
  isSystem?: boolean;
  permissions?: Partial<Record<ServerPermissionKeyPayload, PermissionStatePayload>>;
}

export interface RoleAssignmentPayload {
  userId: string;
  oderId?: string;
  roleIds: string[];
}

export interface ChannelPermissionPayload {
  channelId: string;
  targetType: 'role' | 'user';
  targetId: string;
  permission: ServerPermissionKeyPayload;
  value: PermissionStatePayload;
}

export interface ServerPayload {
  id: string;
  name: string;
  description?: string;
  ownerId: string;
  ownerPublicKey: string;
  hasPassword?: boolean;
  passwordHash?: string | null;
  isPrivate: boolean;
  maxUsers: number;
  currentUsers: number;
  icon?: string;
  iconUpdatedAt?: number;
  slowModeInterval?: number;
  tags: string[];
  channels: ServerChannelPayload[];
  roles?: AccessRolePayload[];
  roleAssignments?: RoleAssignmentPayload[];
  channelPermissions?: ChannelPermissionPayload[];
  createdAt: number;
  lastSeen: number;
}

export interface JoinRequestPayload {
  id: string;
  serverId: string;
  userId: string;
  userPublicKey: string;
  displayName: string;
  status: 'pending' | 'approved' | 'rejected';
  createdAt: number;
}

export interface RegisterUserCommand {
  type: typeof CommandType.RegisterUser;
  payload: { user: AuthUserPayload };
}

export interface UpsertServerCommand {
  type: typeof CommandType.UpsertServer;
  payload: { server: ServerPayload };
}

export interface DeleteServerCommand {
  type: typeof CommandType.DeleteServer;
  payload: { serverId: string };
}

export interface CreateJoinRequestCommand {
  type: typeof CommandType.CreateJoinRequest;
  payload: { request: JoinRequestPayload };
}

export interface UpdateJoinRequestStatusCommand {
  type: typeof CommandType.UpdateJoinRequestStatus;
  payload: { requestId: string; status: JoinRequestPayload['status'] };
}

export interface DeleteStaleJoinRequestsCommand {
  type: typeof CommandType.DeleteStaleJoinRequests;
  payload: { maxAgeMs: number };
}

export type Command =
  | RegisterUserCommand
  | UpsertServerCommand
  | DeleteServerCommand
  | CreateJoinRequestCommand
  | UpdateJoinRequestStatusCommand
  | DeleteStaleJoinRequestsCommand;

export interface GetUserByUsernameQuery {
  type: typeof QueryType.GetUserByUsername;
  payload: { username: string };
}

export interface GetUserByIdQuery {
  type: typeof QueryType.GetUserById;
  payload: { userId: string };
}

export interface GetAllPublicServersQuery {
  type: typeof QueryType.GetAllPublicServers;
  payload: Record<string, never>;
}

export interface GetServerByIdQuery {
  type: typeof QueryType.GetServerById;
  payload: { serverId: string };
}

export interface GetJoinRequestByIdQuery {
  type: typeof QueryType.GetJoinRequestById;
  payload: { requestId: string };
}

export interface GetPendingRequestsForServerQuery {
  type: typeof QueryType.GetPendingRequestsForServer;
  payload: { serverId: string };
}

export type Query =
  | GetUserByUsernameQuery
  | GetUserByIdQuery
  | GetAllPublicServersQuery
  | GetServerByIdQuery
  | GetJoinRequestByIdQuery
  | GetPendingRequestsForServerQuery;
