import {
  DELETED_MESSAGE_CONTENT,
  type BanEntry,
  type Message,
  type Reaction,
  type Room,
  type User
} from '../../../shared-kernel';
import type { ChatAttachmentMeta, CustomEmoji } from '../../../shared-kernel';

export interface MessageRow {
  id: string;
  roomId: string;
  ownerUserId?: string | null;
  channelId?: string | null;
  senderId: string;
  senderName: string;
  content: string;
  timestamp: number;
  editedAt?: number | null;
  isDeleted: number;
  replyToId?: string | null;
  linkMetadata?: string | null;
  kind?: string | null;
  systemEvent?: string | null;
  revision?: number | null;
  headHash?: string | null;
}

export interface UserRow {
  id: string;
  oderId?: string | null;
  username?: string | null;
  displayName?: string | null;
  description?: string | null;
  profileUpdatedAt?: number | null;
  avatarUrl?: string | null;
  avatarHash?: string | null;
  avatarMime?: string | null;
  avatarUpdatedAt?: number | null;
  status?: string | null;
  role?: string | null;
  joinedAt?: number | null;
  peerId?: string | null;
  isOnline: number;
  isAdmin: number;
  isRoomOwner: number;
  voiceState?: string | null;
  screenShareState?: string | null;
  homeSignalServerUrl?: string | null;
}

export interface RoomRow {
  id: string;
  name: string;
  description?: string | null;
  topic?: string | null;
  hostId: string;
  password?: string | null;
  hasPassword: number;
  isPrivate: number;
  createdAt: number;
  userCount: number;
  maxUsers?: number | null;
  icon?: string | null;
  iconUpdatedAt?: number | null;
  slowModeInterval: number;
  sourceId?: string | null;
  sourceName?: string | null;
  sourceUrl?: string | null;
}

function encodeJson(value: unknown): string | null {
  if (value === undefined || value === null) {
    return null;
  }

  return JSON.stringify(value);
}

function decodeJson<T>(value: string | null | undefined): T | undefined {
  if (!value) {
    return undefined;
  }

  try {
    return JSON.parse(value) as T;
  } catch {
    return undefined;
  }
}

export function messageToRow(message: Message): MessageRow {
  return {
    id: message.id,
    roomId: message.roomId,
    channelId: message.channelId ?? null,
    senderId: message.senderId,
    senderName: message.senderName,
    content: message.content,
    timestamp: message.timestamp,
    editedAt: message.editedAt ?? null,
    isDeleted: message.isDeleted ? 1 : 0,
    replyToId: message.replyToId ?? null,
    linkMetadata: encodeJson(message.linkMetadata),
    kind: message.kind ?? null,
    systemEvent: message.systemEvent ?? null,
    revision: message.revision ?? 0,
    headHash: message.headHash ?? null
  };
}

export function rowToMessage(row: MessageRow, reactions: Reaction[] = []): Message {
  const message: Message = {
    id: row.id,
    roomId: row.roomId,
    channelId: row.channelId ?? undefined,
    senderId: row.senderId,
    senderName: row.senderName,
    content: row.content,
    timestamp: row.timestamp,
    editedAt: row.editedAt ?? undefined,
    revision: row.revision ?? 0,
    headHash: row.headHash ?? undefined,
    isDeleted: row.isDeleted === 1,
    replyToId: row.replyToId ?? undefined,
    linkMetadata: decodeJson(row.linkMetadata),
    kind: (row.kind as Message['kind']) ?? undefined,
    systemEvent: (row.systemEvent as Message['systemEvent']) ?? undefined,
    reactions
  };

  if (message.content === DELETED_MESSAGE_CONTENT) {
    return { ...message, reactions: [] };
  }

  return message;
}

export function userToRow(user: User): UserRow {
  return {
    id: user.id,
    oderId: user.oderId,
    username: user.username,
    displayName: user.displayName,
    description: user.description ?? null,
    profileUpdatedAt: user.profileUpdatedAt ?? null,
    avatarUrl: user.avatarUrl ?? null,
    avatarHash: user.avatarHash ?? null,
    avatarMime: user.avatarMime ?? null,
    avatarUpdatedAt: user.avatarUpdatedAt ?? null,
    status: user.status,
    role: user.role,
    joinedAt: user.joinedAt,
    peerId: user.peerId ?? null,
    isOnline: user.isOnline ? 1 : 0,
    isAdmin: user.isAdmin ? 1 : 0,
    isRoomOwner: user.isRoomOwner ? 1 : 0,
    voiceState: encodeJson(user.voiceState),
    screenShareState: encodeJson(user.screenShareState),
    homeSignalServerUrl: user.homeSignalServerUrl ?? null
  };
}

export function rowToUser(row: UserRow): User {
  return {
    id: row.id,
    oderId: row.oderId ?? row.id,
    username: row.username ?? '',
    displayName: row.displayName ?? '',
    description: row.description ?? undefined,
    profileUpdatedAt: row.profileUpdatedAt ?? undefined,
    avatarUrl: row.avatarUrl ?? undefined,
    avatarHash: row.avatarHash ?? undefined,
    avatarMime: row.avatarMime ?? undefined,
    avatarUpdatedAt: row.avatarUpdatedAt ?? undefined,
    status: (row.status as User['status']) ?? 'offline',
    role: (row.role as User['role']) ?? 'member',
    joinedAt: row.joinedAt ?? 0,
    peerId: row.peerId ?? undefined,
    isOnline: row.isOnline === 1,
    isAdmin: row.isAdmin === 1,
    isRoomOwner: row.isRoomOwner === 1,
    voiceState: decodeJson(row.voiceState),
    screenShareState: decodeJson(row.screenShareState),
    homeSignalServerUrl: row.homeSignalServerUrl ?? undefined
  };
}

export function roomToRow(room: Room): RoomRow {
  return {
    id: room.id,
    name: room.name,
    description: room.description ?? null,
    topic: room.topic ?? null,
    hostId: room.hostId,
    password: room.password ?? null,
    hasPassword: room.hasPassword ? 1 : 0,
    isPrivate: room.isPrivate ? 1 : 0,
    createdAt: room.createdAt,
    userCount: room.userCount,
    maxUsers: room.maxUsers ?? null,
    icon: room.icon ?? null,
    iconUpdatedAt: room.iconUpdatedAt ?? null,
    slowModeInterval: room.slowModeInterval ?? 0,
    sourceId: room.sourceId ?? null,
    sourceName: room.sourceName ?? null,
    sourceUrl: room.sourceUrl ?? null
  };
}

export function rowToRoom(row: RoomRow): Room {
  return {
    id: row.id,
    name: row.name,
    description: row.description ?? undefined,
    topic: row.topic ?? undefined,
    hostId: row.hostId,
    password: row.password ?? undefined,
    hasPassword: row.hasPassword === 1,
    isPrivate: row.isPrivate === 1,
    createdAt: row.createdAt,
    userCount: row.userCount,
    maxUsers: row.maxUsers ?? undefined,
    icon: row.icon ?? undefined,
    iconUpdatedAt: row.iconUpdatedAt ?? undefined,
    slowModeInterval: row.slowModeInterval,
    sourceId: row.sourceId ?? undefined,
    sourceName: row.sourceName ?? undefined,
    sourceUrl: row.sourceUrl ?? undefined
  };
}

export function reactionToValues(reaction: Reaction): unknown[] {
  return [
    reaction.id,
    reaction.messageId,
    reaction.oderId,
    reaction.userId,
    reaction.emoji,
    reaction.timestamp
  ];
}

export function rowToReaction(row: Reaction): Reaction {
  return row;
}

export function banToValues(ban: BanEntry): unknown[] {
  return [
    ban.oderId,
    ban.roomId,
    ban.userId,
    ban.bannedBy,
    ban.displayName ?? null,
    ban.reason ?? null,
    ban.expiresAt ?? null,
    ban.timestamp
  ];
}

export function attachmentToValues(attachment: ChatAttachmentMeta): unknown[] {
  return [
    attachment.id,
    attachment.messageId,
    attachment.filename,
    attachment.size,
    attachment.mime,
    attachment.isImage ? 1 : 0,
    attachment.uploaderPeerId ?? null,
    attachment.filePath ?? null,
    attachment.savedPath ?? null
  ];
}

export function rowToAttachment(row: {
  id: string;
  messageId: string;
  filename: string;
  size: number;
  mime: string;
  isImage: number;
  uploaderPeerId?: string | null;
  filePath?: string | null;
  savedPath?: string | null;
}): ChatAttachmentMeta {
  return {
    id: row.id,
    messageId: row.messageId,
    filename: row.filename,
    size: row.size,
    mime: row.mime,
    isImage: row.isImage === 1,
    uploaderPeerId: row.uploaderPeerId ?? undefined,
    filePath: row.filePath ?? undefined,
    savedPath: row.savedPath ?? undefined
  };
}

export function customEmojiToValues(emoji: CustomEmoji): unknown[] {
  return [
    emoji.id,
    emoji.name,
    emoji.creatorUserId,
    emoji.dataUrl,
    emoji.hash,
    emoji.mime,
    emoji.size,
    emoji.createdAt,
    emoji.updatedAt
  ];
}

export function rowToCustomEmoji(row: {
  id: string;
  name: string;
  creatorUserId: string;
  dataUrl: string;
  hash: string;
  mime: string;
  size: number;
  createdAt: number;
  updatedAt: number;
}): CustomEmoji {
  return row;
}
