/**
 * Full workflow browser E2E: page crashes after server hydrate + content quality API checks.
 * Usage: npx tsx scripts/browser-workflow-e2e.ts [baseUrl]
 */
import { chromium, type Page } from "playwright";

const base = process.argv[2] ?? "http://127.0.0.1:3056";

const PAGES = [
  "/dashboard",
  "/my-project",
  "/brand-profile",
  "/posting-context",
  "/connected-accounts",
  "/smart-schedule",
  "/automation",
  "/live-generation",
  "/generated-posts",
  "/content-library",
];

async function auth(page: Page) {
  await page.request.post(`${base}/api/auth/demo`);
  await page.goto(`${base}/dashboard`, { waitUntil: "domcontentloaded" });
  await page
    .waitForResponse((r) => r.url().includes("/api/projects") && r.status() === 200, {
      timeout: 20000,
    })
    .catch(() => {});
  await page.waitForTimeout(1000);
}

async function visitPage(page: Page, path: string) {
  const pageErrors: string[] = [];
  const handler = (err: Error) => pageErrors.push(err.message);
  page.on("pageerror", handler);

  await page.goto(`${base}${path}`, { waitUntil: "domcontentloaded", timeout: 60000 });
  await page
    .waitForResponse((r) => r.url().includes("/api/projects") && r.status() === 200, {
      timeout: 15000,
    })
    .catch(() => {});
  await page.waitForTimeout(2000);

  const body = await page.locator("body").innerText();
  const crashed =
    body.includes("Application error") || body.includes("client-side exception");
  page.off("pageerror", handler);
  return { path, crashed, pageErrors };
}

async function checkContentQuality(page: Page) {
  const data = await page.evaluate(async () => {
    const res = await fetch("/api/generation/posts");
    if (!res.ok) return { error: `HTTP ${res.status}` };
    return res.json() as Promise<{ posts?: unknown[] }>;
  });

  if ("error" in data && data.error) return { ok: false, detail: String(data.error) };

  const posts = ("posts" in data ? data.posts : []) as Array<{
    caption?: string;
    imageUrl?: string | null;
    videoUrl?: string | null;
    videoStatus?: string;
    engagementScore?: number | null;
    qaPassed?: boolean;
    qaOverall?: number;
  }>;
  if (!posts.length) return { ok: true, detail: "no posts yet (skip quality)" };

  const withCaption = posts.filter((p) => (p.caption?.trim().length ?? 0) >= 40);
  const withImage = posts.filter((p) => Boolean(p.imageUrl));
  const withVideo = posts.filter((p) => p.videoStatus === "generated" && p.videoUrl);
  const qaPass = posts.filter((p) => p.qaPassed === true);
  const avgScore =
    posts.reduce((s, p) => s + (p.engagementScore ?? p.qaOverall ?? 0), 0) / posts.length;

  const ok =
    withCaption.length >= Math.ceil(posts.length * 0.5) &&
    withImage.length >= Math.ceil(posts.length * 0.5);

  return {
    ok,
    detail: `${posts.length} posts | caption≥40: ${withCaption.length} | images: ${withImage.length} | videos: ${withVideo.length} | QA pass: ${qaPass.length} | avg score: ${avgScore.toFixed(1)}`,
  };
}

async function testAutomationToggle(page: Page) {
  await page.goto(`${base}/automation`, { waitUntil: "domcontentloaded" });
  await page.waitForTimeout(2500);
  const body = await page.locator("body").innerText();
  if (body.includes("Application error")) {
    return { ok: false, detail: "page crashed before toggle" };
  }

  const toggle = page.getByRole("switch", { name: /Loop Post Sequence/i }).first();
  if (!(await toggle.count())) {
    return { ok: false, detail: "Loop Post Sequence toggle not found" };
  }

  const before = await toggle.getAttribute("aria-checked");
  await toggle.click();
  await page.waitForTimeout(1500);
  const after = await toggle.getAttribute("aria-checked");
  if (before === after) return { ok: false, detail: "toggle did not change state" };

  const postCrash = await page.locator("body").innerText();
  if (postCrash.includes("Application error")) {
    return { ok: false, detail: "page crashed after toggle" };
  }
  return { ok: true, detail: `toggle ${before} → ${after}` };
}

async function main() {
  const browser = await chromium.launch({ headless: true });
  const page = await browser.newPage();

  await auth(page);

  console.log("\n=== Page crash check (after server hydrate) ===");
  let failCount = 0;
  for (const path of PAGES) {
    const r = await visitPage(page, path);
    const status = r.crashed ? "FAIL" : "PASS";
    if (r.crashed) failCount++;
    console.log(
      `${status}\t${path}${r.pageErrors[0] ? ` — ${r.pageErrors[0].slice(0, 100)}` : ""}`,
    );
  }

  console.log("\n=== Automation toggle ===");
  const toggle = await testAutomationToggle(page);
  console.log(`${toggle.ok ? "PASS" : "FAIL"}\t/automation toggle — ${toggle.detail}`);
  if (!toggle.ok) failCount++;

  console.log("\n=== Content / image / video quality (API) ===");
  const quality = await checkContentQuality(page);
  console.log(`${quality.ok ? "PASS" : "WARN"}\t${quality.detail}`);

  await browser.close();
  console.log(`\n=== Summary: ${PAGES.length + 1 - failCount}/${PAGES.length + 1} checks passed ===\n`);
  process.exit(failCount > 0 ? 1 : 0);
}

main().catch((e) => {
  console.error(e);
  process.exit(2);
});
