const TID_ALPHABET = "234567abcdefghijklmnopqrstuvwxyz";

export function createTid(dateString) {
  let tid = BigInt(new Date(dateString).getTime()) * 1000n;
  tid = tid << 10n;
  let result = "";
  for (let i = 0; i < 13; i++) {
    const remainder = tid % 32n;
    result = TID_ALPHABET[Number(remainder)] + result;
    tid = tid / 32n;
  }
  return result;
}

function createTestUserMember() {
  return {
    did: "did:plc:testuser123",
    handle: "testuser.bsky.social",
    displayName: "Test User",
    avatar: "",
    viewer: { muted: false, blockedBy: false },
    labels: [],
    createdAt: "2025-01-01T00:00:00.000Z",
  };
}

export function createConvo({
  id,
  otherMember,
  lastMessage,
  status = "accepted",
  unreadCount = 0,
}) {
  return {
    id,
    rev: "rev" + id,
    members: [createTestUserMember(), otherMember],
    status,
    unreadCount,
    lastMessage: lastMessage || undefined,
  };
}

export function createGroupConvo({
  id,
  name,
  otherMembers,
  lastMessage,
  status = "accepted",
  unreadCount = 0,
  lockStatus = "unlocked",
  memberCount,
  ownerDid,
}) {
  let members = [createTestUserMember(), ...otherMembers];
  if (ownerDid) {
    members = members.map((member) => ({
      ...member,
      kind: {
        $type: "chat.bsky.actor.defs#groupConvoMember",
        role: member.did === ownerDid ? "owner" : "standard",
      },
    }));
  }
  return {
    id,
    rev: "rev" + id,
    members,
    status,
    unreadCount,
    muted: false,
    lastMessage: lastMessage || undefined,
    kind: {
      $type: "chat.bsky.convo.defs#groupConvo",
      name,
      memberCount: memberCount ?? otherMembers.length + 1,
      memberLimit: 100,
      lockStatus,
      createdAt: "2025-01-01T00:00:00.000Z",
    },
  };
}

export function createGroupConvoMember({
  profile,
  role = "standard",
  addedBy,
}) {
  return {
    ...profile,
    kind: {
      $type: "chat.bsky.actor.defs#groupConvoMember",
      role,
      ...(addedBy ? { addedBy } : {}),
    },
  };
}

export function createMessageLog({ convoId, message, relatedProfiles }) {
  return {
    $type: "chat.bsky.convo.defs#logCreateMessage",
    rev: "rev-log-" + message.id,
    convoId,
    message,
    relatedProfiles: relatedProfiles || [],
  };
}

export function createSystemMessageLog({
  convoId,
  logType,
  message,
  relatedProfiles,
}) {
  return {
    $type: `chat.bsky.convo.defs#${logType}`,
    rev: "rev-log-" + message.id,
    convoId,
    message,
    relatedProfiles: relatedProfiles || [],
  };
}

export function createSystemMessage({ id, dataType, data = {}, sentAt }) {
  return {
    $type: "chat.bsky.convo.defs#systemMessageView",
    id,
    rev: "rev" + id,
    sentAt: sentAt || "2025-01-15T12:00:00.000Z",
    data: {
      $type: `chat.bsky.convo.defs#${dataType}`,
      ...data,
    },
  };
}

export function createMessage({ id, text, senderDid, sentAt, embed, replyTo }) {
  return {
    $type: "chat.bsky.convo.defs#messageView",
    id,
    rev: "rev" + id,
    text,
    facets: [],
    sender: { did: senderDid },
    sentAt: sentAt || "2025-01-15T12:00:00.000Z",
    reactions: [],
    ...(embed ? { embed } : {}),
    ...(replyTo ? { replyTo } : {}),
  };
}

export function createProfile({
  did,
  handle,
  displayName,
  description,
  avatar,
  banner,
  followersCount,
  followsCount,
  postsCount,
  associated,
  viewer,
  labels,
}) {
  return {
    did,
    handle,
    displayName,
    description: description || "",
    avatar: avatar || "",
    banner: banner || "",
    viewer: { muted: false, blockedBy: false, ...viewer },
    labels: labels || [],
    createdAt: "2025-01-01T00:00:00.000Z",
    ...(associated ? { associated } : {}),
    ...(followersCount !== undefined ? { followersCount } : {}),
    ...(followsCount !== undefined ? { followsCount } : {}),
    ...(postsCount !== undefined ? { postsCount } : {}),
  };
}

export function createFeedGenerator({
  uri,
  displayName,
  creatorHandle,
  description,
}) {
  const creatorDid = uri.split("/")[2];
  return {
    uri,
    cid: "bafyreitest" + uri.split("/").pop(),
    did: `did:web:feed.${creatorHandle}`,
    creator: {
      did: creatorDid,
      handle: creatorHandle,
      displayName: creatorHandle.split(".")[0],
      avatar: "",
      viewer: { muted: false, blockedBy: false },
      labels: [],
      createdAt: "2025-01-01T00:00:00.000Z",
    },
    displayName,
    description: description || "",
    avatar: "",
    likeCount: 10,
    indexedAt: "2025-01-01T00:00:00.000Z",
    labels: [],
    viewer: {},
  };
}

export function createList({
  uri,
  name,
  creatorHandle,
  purpose = "app.bsky.graph.defs#curatelist",
}) {
  const creatorDid = uri.split("/")[2];
  return {
    uri,
    cid: "bafyreitest" + uri.split("/").pop(),
    creator: {
      did: creatorDid,
      handle: creatorHandle,
      displayName: creatorHandle.split(".")[0],
      avatar: "",
      viewer: { muted: false, blockedBy: false },
      labels: [],
      createdAt: "2025-01-01T00:00:00.000Z",
    },
    name,
    purpose,
    avatar: "",
    indexedAt: "2025-01-01T00:00:00.000Z",
    labels: [],
    viewer: {},
  };
}

export function createStarterPack({ uri, name, creatorHandle, description }) {
  const creatorDid = uri.split("/")[2];
  const rkey = uri.split("/").pop();
  return {
    uri,
    cid: "bafyreitest" + rkey,
    record: {
      $type: "app.bsky.graph.starterpack",
      name,
      description: description || "",
      list: `at://${creatorDid}/app.bsky.graph.list/${rkey}`,
      createdAt: "2025-01-01T00:00:00.000Z",
    },
    creator: {
      did: creatorDid,
      handle: creatorHandle,
      displayName: creatorHandle.split(".")[0],
      avatar: "",
      viewer: { muted: false, blockedBy: false },
      labels: [],
      createdAt: "2025-01-01T00:00:00.000Z",
    },
    listItemCount: 3,
    joinedWeekCount: 0,
    joinedAllTimeCount: 0,
    indexedAt: "2025-01-01T00:00:00.000Z",
    labels: [],
  };
}

export function createNotification({
  reason,
  author,
  reasonSubject,
  uri,
  isRead = false,
  indexedAt = "2025-01-15T12:00:00.000Z",
  record,
}) {
  return {
    uri: uri || `at://${author.did}/app.bsky.feed.like/notif-${Date.now()}`,
    cid: "bafyreinotif" + Math.random().toString(36).slice(2),
    author,
    reason,
    reasonSubject: reasonSubject || "",
    record: record || {},
    isRead,
    indexedAt,
    labels: [],
  };
}

export function createLabelerView({
  did,
  handle,
  displayName,
  labelDefinitions = [],
  creator,
}) {
  return {
    uri: `at://${did}/app.bsky.labeler.service/self`,
    cid: `bafyreilabeler${did.split(":").pop()}`,
    creator: creator || {
      did,
      handle,
      displayName,
      avatar: "",
      viewer: { muted: false, blockedBy: false },
      labels: [],
      createdAt: "2025-01-01T00:00:00.000Z",
    },
    policies: {
      labelValueDefinitions: labelDefinitions,
    },
    labels: [],
  };
}

export function createPost({
  uri,
  text,
  authorHandle,
  authorDisplayName,
  authorAvatar,
  replyCount = 0,
  repostCount = 0,
  likeCount = 5,
  quoteCount = 0,
  reply,
  embed,
  recordEmbed,
  labels,
  viewer,
  loggedOut = false,
  threadgate,
}) {
  const did = uri.split("/")[2];
  return {
    uri,
    cid: "bafyreitest" + uri.split("/").pop(),
    author: {
      did,
      handle: authorHandle,
      displayName: authorDisplayName,
      avatar: authorAvatar || "",
      ...(loggedOut ? {} : { viewer: { muted: false, blockedBy: false } }),
      labels: [],
      createdAt: "2025-01-01T00:00:00.000Z",
    },
    record: {
      $type: "app.bsky.feed.post",
      text,
      createdAt: "2025-01-01T00:00:00.000Z",
      langs: ["en"],
      ...(reply ? { reply } : {}),
      ...(recordEmbed ? { embed: recordEmbed } : {}),
    },
    replyCount,
    repostCount,
    likeCount,
    quoteCount,
    ...(embed ? { embed } : {}),
    indexedAt: "2025-01-01T00:00:00.000Z",
    ...(loggedOut ? {} : { viewer: { ...viewer } }),
    labels: labels || [],
    ...(threadgate ? { threadgate } : {}),
  };
}

export function createFeedItem({
  post,
  feedContext = "test-context",
  reply,
  reason,
}) {
  return {
    post,
    ...(reply ? { reply } : {}),
    ...(reason ? { reason } : {}),
    feedContext,
  };
}
