import type { ForumPost, ForumSection, ForumThreadSummary, ForumTopic } from './types';
import {
  applyTopicStatusSort,
  filterPostsBySearch,
  parseTopicSearchQuery,
} from './topicSearch';

export function countAllReplies(replies: ForumPost[] | undefined): number {
  let total = 0;
  for (const reply of replies || []) {
    total += 1;
    total += countAllReplies(reply.replies);
  }
  return total;
}

export function maxThreadTimestamp(post: ForumPost): number {
  let maxValue = post.timestamp;
  const stack = [...(post.replies || [])];
  while (stack.length > 0) {
    const current = stack.pop();
    if (!current) continue;
    if (current.timestamp > maxValue) maxValue = current.timestamp;
    if (current.replies?.length) stack.push(...current.replies);
  }
  return maxValue;
}

export function buildThreadSummaries(posts: ForumPost[]): ForumThreadSummary[] {
  return posts.map((post) => ({
    eventId: post.eventId,
    title: post.title || post.body.slice(0, 160) || '(no title)',
    body: post.body,
    sender: post.sender,
    senderDisplayName: post.senderDisplayName,
    timestamp: post.timestamp,
    topicRoomId: post.topicRoomId,
    sectionTitle: post.sectionTitle,
    topicName: post.topicName,
    totalReplies: post.bundledReplyCount ?? countAllReplies(post.replies),
    lastActivityTs: maxThreadTimestamp(post),
    isPinned: false,
  }));
}

export function buildTopicThreads(
  posts: ForumPost[],
  query: { q?: string; status?: string; sort?: string } = {}
): ForumThreadSummary[] {
  const parsed = parseTopicSearchQuery(query.q || '');
  const filtered = filterPostsBySearch(posts, parsed);
  const summaries = buildThreadSummaries(filtered);
  return applyTopicStatusSort(summaries, query.status || 'all', query.sort || 'hot');
}

export function buildForumSections(topics: ForumTopic[]): ForumSection[] {
  const spaces = topics.filter((topic) => topic.isSpace);
  const postableTopics = topics.filter((topic) => !topic.isSpace);
  const sections: ForumSection[] = [];

  for (const space of spaces) {
    const childTopics = postableTopics.filter((topic) => topic.parentRoomId === space.roomId);

    sections.push({
      spaceId: space.roomId,
      title: space.name,
      description: space.topic || null,
      topics: childTopics.sort((a, b) => a.name.localeCompare(b.name)),
    });
  }

  const coveredTopicIds = new Set(
    sections.flatMap((section) => section.topics.map((topic) => topic.roomId))
  );
  const uncategorizedTopics = postableTopics.filter((topic) => !coveredTopicIds.has(topic.roomId));
  if (uncategorizedTopics.length > 0) {
    sections.push({
      title: 'General Topics',
      description: null,
      topics: uncategorizedTopics.sort((a, b) => a.name.localeCompare(b.name)),
    });
  }

  return sections;
}

/** Insert a reply under the parent event (immutable). */
export function appendReplyToThread(
  root: ForumPost,
  parentEventId: string,
  reply: ForumPost
): ForumPost {
  const walk = (node: ForumPost): ForumPost => {
    if (node.eventId === parentEventId) {
      return {
        ...node,
        replies: [...node.replies, reply].sort((a, b) => a.timestamp - b.timestamp),
      };
    }
    let changed = false;
    const nextReplies = node.replies.map((child) => {
      const updated = walk(child);
      if (updated !== child) changed = true;
      return updated;
    });
    if (!changed) return node;
    return { ...node, replies: nextReplies };
  };
  return walk(root);
}

export function annotatePostsWithRoomScope(
  posts: ForumPost[],
  roomId: string,
  scope: { sectionTitle?: string; topicName?: string } | null = null
): void {
  const sectionTitle = scope?.sectionTitle ? String(scope.sectionTitle) : '';
  const topicName = scope?.topicName ? String(scope.topicName) : '';

  for (const post of posts) {
    post.topicRoomId = roomId;
    if (sectionTitle) post.sectionTitle = sectionTitle;
    if (topicName) post.topicName = topicName;
  }
}
