/**
 * Page Metadata Flow — navigate to a Facebook page and collect metadata +
 * transparency information via intercepted GraphQL responses.
 */

import type { BrowserContext } from '../cdp.js';
import type { NetworkInterceptor, GraphQLResponse } from '../network.js';
import type { FbPageData, FbTransparencyData } from '../../../types.js';
import { delay, clickElement, idlePause } from '../human.js';
import { extractPageData, extractTransparency } from '../extract/index.js';

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

/** Merge two partial FbPageData objects, preferring non-null newer values. */
function mergePageData(base: Partial<FbPageData>, incoming: Partial<FbPageData>): Partial<FbPageData> {
  const merged = { ...base };
  for (const [key, value] of Object.entries(incoming)) {
    if (value != null && value !== '') {
      (merged as Record<string, unknown>)[key] = value;
    }
  }
  // Deep-merge transparency
  if (incoming.transparency && base.transparency) {
    merged.transparency = { ...base.transparency, ...incoming.transparency } as FbTransparencyData;
  }
  return merged;
}

/**
 * Navigate to a Facebook page and collect metadata + transparency data.
 *
 * Listens to intercepted GraphQL responses and attempts to trigger the
 * "About" / "Transparency" section to capture additional data.
 */
export async function collectPageMetadata(
  ctx: BrowserContext,
  pageUrl: string,
  interceptor: NetworkInterceptor,
): Promise<FbPageData | null> {
  console.log(`[${ts()}] ▶ page-meta: navigating to ${pageUrl}`);

  let accumulated: Partial<FbPageData> = {};

  // Listener: capture page data from every GraphQL response
  const onGraphQL = (response: GraphQLResponse) => {
    try {
      const extracted = extractPageData(response.body);
      if (extracted) {
        accumulated = mergePageData(accumulated, extracted);
      }
      const transparency = extractTransparency(response.body);
      if (transparency) {
        accumulated.transparency = accumulated.transparency
          ? ({ ...accumulated.transparency, ...transparency } as FbTransparencyData)
          : transparency;
      }
    } catch {
      // Extraction may fail on unrelated responses — ignore
    }
  };

  interceptor.on('graphql', onGraphQL);

  try {
    // Navigate to the page
    await ctx.evaluate(`window.location.href = ${JSON.stringify(pageUrl)}`);
    await delay(3000 + Math.random() * 2000);

    console.log(`[${ts()}]   page loaded, waiting for GraphQL data…`);
    await idlePause();

    // Try to surface more data by clicking About / Transparency tabs
    const aboutClicked = await tryClickLink(ctx, 'About');
    if (aboutClicked) {
      console.log(`[${ts()}]   clicked "About" section`);
      await delay(2000 + Math.random() * 1500);
    }

    const transparencyClicked = await tryClickLink(ctx, 'Page transparency');
    if (!transparencyClicked) {
      await tryClickLink(ctx, 'Transparency');
    }
    if (transparencyClicked) {
      console.log(`[${ts()}]   clicked transparency section`);
      await delay(2000 + Math.random() * 1500);
    }

    // Also try "See all" inside transparency for name history etc.
    await tryClickLink(ctx, 'See all');
    await delay(1500 + Math.random() * 1000);

    // Final idle to collect remaining GraphQL responses
    await idlePause();

    if (!accumulated.page_id) {
      console.log(`[${ts()}]   ⚠ no page_id found in GraphQL responses`);
      return null;
    }

    console.log(`[${ts()}] ✓ page-meta: collected metadata for "${accumulated.name ?? accumulated.page_id}"`);
    return accumulated as FbPageData;
  } finally {
    interceptor.off('graphql', onGraphQL);
  }
}

/**
 * Attempt to click a link or button whose visible text matches `label`.
 * First scrolls the element into view, then uses clickElement with a
 * dynamically-generated selector.
 */
async function tryClickLink(ctx: BrowserContext, label: string): Promise<boolean> {
  try {
    // Scroll matching element into view and store a temporary data attribute
    const found = await ctx.evaluate<boolean>(`
      (() => {
        const els = [...document.querySelectorAll('a, span, div[role="button"], [role="tab"]')];
        const target = els.find(el => {
          const text = el.textContent?.trim() ?? '';
          return text === ${JSON.stringify(label)} ||
                 text.toLowerCase().includes(${JSON.stringify(label.toLowerCase())});
        });
        if (target) {
          target.scrollIntoView({ block: 'center' });
          target.setAttribute('data-fbscrape-click', 'pending');
          return true;
        }
        return false;
      })()
    `);
    if (found) {
      await delay(300 + Math.random() * 300);
      const clicked = await clickElement(ctx, '[data-fbscrape-click="pending"]');
      // Clean up the marker attribute
      await ctx.evaluate<void>(`
        document.querySelector('[data-fbscrape-click="pending"]')?.removeAttribute('data-fbscrape-click')
      `);
      return clicked;
    }
  } catch {
    // Element not present — expected on some pages
  }
  return false;
}
