/**
 * Post Detail Flow — expand comments and collect individual reactions
 * for a set of posts.
 */

import type { BrowserContext } from '../cdp.js';
import type { NetworkInterceptor, GraphQLResponse } from '../network.js';
import type { FbPostData, FbCommentData, FbReactionData } from '../../../types.js';
import { delay, naturalScroll, idlePause } from '../human.js';
import { extractComments, extractReactions } from '../extract/index.js';

function ts(): string {
  return new Date().toISOString();
}

export interface PostDetailOptions {
  /** Expand and collect all comments on each post. */
  collectComments?: boolean;
  /** Open reaction dialog and collect individual reactor lists. */
  collectReactions?: boolean;
}

/**
 * Iterate through posts and collect detailed comments and/or reactions.
 */
export async function collectPostDetails(
  ctx: BrowserContext,
  interceptor: NetworkInterceptor,
  posts: FbPostData[],
  opts: PostDetailOptions = {},
): Promise<{ comments: FbCommentData[]; reactions: FbReactionData[] }> {
  const allComments: FbCommentData[] = [];
  const allReactions: FbReactionData[] = [];

  if (!opts.collectComments && !opts.collectReactions) {
    return { comments: allComments, reactions: allReactions };
  }

  console.log(
    `[${ts()}] ▶ post-detail: processing ${posts.length} posts` +
    `${opts.collectComments ? ' [comments]' : ''}` +
    `${opts.collectReactions ? ' [reactions]' : ''}`,
  );

  for (let i = 0; i < posts.length; i++) {
    const post = posts[i];
    console.log(`[${ts()}]   post ${i + 1}/${posts.length}: ${post.post_id}`);

    if (opts.collectComments) {
      const comments = await collectCommentsForPost(ctx, interceptor, post);
      allComments.push(...comments);
    }

    if (opts.collectReactions) {
      const reactions = await collectReactionsForPost(ctx, interceptor, post);
      allReactions.push(...reactions);
    }

    // Brief pause between posts to avoid rate-limiting
    if (i < posts.length - 1) {
      await delay(1000 + Math.random() * 1000);
    }
  }

  console.log(
    `[${ts()}] ✓ post-detail: ${allComments.length} comments, ${allReactions.length} reactions`,
  );

  return { comments: allComments, reactions: allReactions };
}

// ─── Comment Collection ────────────────────────────────────────────────────

async function collectCommentsForPost(
  ctx: BrowserContext,
  interceptor: NetworkInterceptor,
  post: FbPostData,
): Promise<FbCommentData[]> {
  const comments = new Map<string, FbCommentData>();

  const onGraphQL = (response: GraphQLResponse) => {
    try {
      const extracted = extractComments(response.body);
      if (!extracted) return;
      for (const comment of extracted) {
        if (comment.comment_id && !comments.has(comment.comment_id)) {
          comments.set(comment.comment_id, { ...comment, post_id: post.post_id });
        }
      }
    } catch {
      // Ignore unrelated responses
    }
  };

  interceptor.on('graphql', onGraphQL);

  try {
    // Try to open "All comments" sort or "View more comments"
    await tryExpandComments(ctx);
    await delay(1500 + Math.random() * 1000);

    // Scroll through the comment section a few times to load more
    const MAX_COMMENT_SCROLLS = 5;
    let emptyScrolls = 0;

    for (let s = 0; s < MAX_COMMENT_SCROLLS && emptyScrolls < 2; s++) {
      const sizeBefore = comments.size;

      // Click "View more comments" or "View N previous comments" if present
      await tryClickCommentExpanders(ctx);
      await naturalScroll(ctx, 300 + Math.random() * 200);
      await delay(1500 + Math.random() * 1000);

      if (comments.size === sizeBefore) {
        emptyScrolls++;
      } else {
        emptyScrolls = 0;
      }
    }

    if (comments.size > 0) {
      console.log(`[${ts()}]     ${comments.size} comments collected`);
    }

    return Array.from(comments.values());
  } finally {
    interceptor.off('graphql', onGraphQL);
  }
}

/**
 * Try to switch comment sort to "All comments" and expand the section.
 */
async function tryExpandComments(ctx: BrowserContext): Promise<void> {
  try {
    // Click "Most relevant" dropdown if present
    await ctx.evaluate(`
      (() => {
        const btns = [...document.querySelectorAll('[role="button"]')];
        const sortBtn = btns.find(el =>
          el.textContent?.trim().match(/^(Most relevant|Top comments|Newest)/i)
        );
        if (sortBtn) (sortBtn as HTMLElement).click();
      })()
    `);
    await delay(800 + Math.random() * 400);

    // Select "All comments"
    await ctx.evaluate(`
      (() => {
        const items = [...document.querySelectorAll('[role="menuitem"], [role="option"]')];
        const allComments = items.find(el =>
          el.textContent?.trim().toLowerCase().includes('all comments')
        );
        if (allComments) (allComments as HTMLElement).click();
      })()
    `);
    await delay(800 + Math.random() * 400);
  } catch {
    // Not all posts have the comment sort dropdown
  }
}

/**
 * Click "View more comments" / "View N previous comments" buttons.
 */
async function tryClickCommentExpanders(ctx: BrowserContext): Promise<void> {
  try {
    await ctx.evaluate(`
      (() => {
        const btns = [...document.querySelectorAll('[role="button"]')];
        const expanders = btns.filter(el => {
          const text = el.textContent?.trim().toLowerCase() ?? '';
          return text.includes('view more comments') ||
                 text.includes('view previous comments') ||
                 text.match(/view \\d+ (more |previous )?comments?/);
        });
        expanders.forEach(el => (el as HTMLElement).click());
      })()
    `);
  } catch {
    // Non-critical
  }
}

// ─── Reaction Collection ───────────────────────────────────────────────────

async function collectReactionsForPost(
  ctx: BrowserContext,
  interceptor: NetworkInterceptor,
  post: FbPostData,
): Promise<FbReactionData[]> {
  const reactions: FbReactionData[] = [];

  const onGraphQL = (response: GraphQLResponse) => {
    try {
      const extracted = extractReactions(response.body);
      if (!extracted) return;
      for (const reaction of extracted) {
        reactions.push({ ...reaction, post_id: post.post_id });
      }
    } catch {
      // Ignore unrelated responses
    }
  };

  interceptor.on('graphql', onGraphQL);

  try {
    // Click the reaction count to open the reaction dialog
    const opened = await tryOpenReactionDialog(ctx);
    if (!opened) return reactions;

    await delay(2000 + Math.random() * 1000);

    // Scroll through the reaction list to load more
    const MAX_REACTION_SCROLLS = 5;
    for (let s = 0; s < MAX_REACTION_SCROLLS; s++) {
      const sizeBefore = reactions.length;

      // Scroll within the dialog
      await ctx.evaluate(`
        (() => {
          const dialog = document.querySelector('[role="dialog"]');
          if (dialog) {
            const scrollable = dialog.querySelector('[style*="overflow"]') || dialog;
            scrollable.scrollTop += 500;
          }
        })()
      `);
      await delay(1200 + Math.random() * 800);

      if (reactions.length === sizeBefore) break;
    }

    // Close the dialog
    await tryCloseDialog(ctx);

    if (reactions.length > 0) {
      console.log(`[${ts()}]     ${reactions.length} reactions collected`);
    }

    return reactions;
  } finally {
    interceptor.off('graphql', onGraphQL);
  }
}

/**
 * Click the reaction count element to open the reaction details dialog.
 */
async function tryOpenReactionDialog(ctx: BrowserContext): Promise<boolean> {
  try {
    const found = await ctx.evaluate(`
      (() => {
        // Look for the reaction summary bar (typically shows emoji counts)
        const candidates = [...document.querySelectorAll(
          '[aria-label*="reaction"], [aria-label*="like"], [role="button"]'
        )];
        const reactionBar = candidates.find(el => {
          const label = el.getAttribute('aria-label') ?? '';
          const text = el.textContent?.trim() ?? '';
          return label.match(/\\d+.*reaction/i) ||
                 label.match(/\\d+.*like/i) ||
                 (text.match(/^\\d+$/) && el.closest('[role="button"]'));
        });
        if (reactionBar) {
          (reactionBar as HTMLElement).click();
          return true;
        }
        return false;
      })()
    `);
    return !!found;
  } catch {
    return false;
  }
}

/**
 * Close the currently open dialog (reaction list, etc.).
 */
async function tryCloseDialog(ctx: BrowserContext): Promise<void> {
  try {
    await ctx.evaluate(`
      (() => {
        const closeBtn = document.querySelector(
          '[role="dialog"] [aria-label="Close"], [role="dialog"] [aria-label="close"]'
        );
        if (closeBtn) (closeBtn as HTMLElement).click();
      })()
    `);
    await delay(500 + Math.random() * 300);
  } catch {
    // Dialog may have closed itself
  }
}
