import { chromium } from 'playwright';
import { execSync } from 'child_process';

const WIKI = 'http://127.0.0.1:8083';
const KC_USER = 'testdev';
const KC_PASS = 'testpass';
const WIKI_USER = 'Admin';
const WIKI_PASS = 'admin1234admin';

function dbExec(sql) {
  return execSync(
    `docker exec archwiki-db mariadb -u archwiki -parchwiki archwiki -e "${sql}"`,
    { encoding: 'utf8' }
  ).trim();
}

function clearSsoLink() {
  dbExec("DELETE FROM openid_connect;");
  console.log('  Cleared openid_connect table');
}

async function sleep(ms) {
  return new Promise(r => setTimeout(r, ms));
}

async function typeIntoRole(page, role, name, text) {
  const el = page.getByRole(role, { name });
  await el.click();
  await sleep(150 + Math.random() * 200);
  await el.pressSequentially(text, { delay: 55 + Math.random() * 40 });
}

async function hoverAndClick(el, pauseMs = 500) {
  await el.hover();
  await sleep(pauseMs + Math.random() * 300);
  await el.click();
}

async function handleKeycloak(page, firstVisit = false) {
  await sleep(2000);
  if (!page.url().includes('auth.josie.cloud')) return;
  console.log('  On Keycloak, waiting for form...');
  await page.waitForLoadState('networkidle');

  const kcUser = page.getByRole('textbox', { name: 'Username or email' });
  const kcPass = page.getByRole('textbox', { name: 'Password' });
  const hasUserField = await kcUser.isVisible({ timeout: 5000 }).catch(() => false);

  if (hasUserField && firstVisit) {
    await typeIntoRole(page, 'textbox', 'Username or email', KC_USER);
    await sleep(400);
    await typeIntoRole(page, 'textbox', 'Password', KC_PASS);
    await sleep(500);
  } else if (await kcPass.isVisible({ timeout: 3000 }).catch(() => false)) {
    console.log('  Re-auth form (password only)');
    await typeIntoRole(page, 'textbox', 'Password', KC_PASS);
    await sleep(500);
  } else {
    console.log('  No recognized form fields, auto-redirect expected');
    return;
  }

  const signInBtn = page.getByRole('button', { name: 'Sign In' });
  await signInBtn.hover();
  await sleep(500);
  await signInBtn.click();

  // Wait for redirect away from Keycloak - wiki callback can be slow (token exchange)
  for (let i = 0; i < 60; i++) {
    await sleep(1000);
    if (!page.url().includes('auth.josie.cloud')) break;
  }
  await page.waitForLoadState('domcontentloaded').catch(() => {});
  console.log('  Redirected to:', page.url());
}

(async () => {
  const browser = await chromium.launch({ headless: true });
  const context = await browser.newContext({
    viewport: { width: 1280, height: 800 },
    recordVideo: {
      dir: '/tmp/archweb-demo/raw-wiki/',
      size: { width: 1280, height: 800 },
    },
  });

  const page = await context.newPage();

  // =============================================
  // FLOW 2 first: SSO Account Linking
  // (We do linking first so SSO login works after)
  // =============================================
  console.log('--- Flow 2: SSO Account Linking ---');

  clearSsoLink();

  // Log in with wiki password
  await page.goto(WIKI + '/index.php?title=Special:UserLogin');
  await sleep(2000);

  await typeIntoRole(page, 'textbox', 'Username', WIKI_USER);
  await sleep(400);
  await typeIntoRole(page, 'textbox', 'Password', WIKI_PASS);
  await sleep(600);

  // Click the local "Log in" button (not the SSO one)
  await hoverAndClick(page.getByRole('button', { name: 'Log in' }).first(), 400);
  await sleep(2000);

  // Navigate to Special:LinkSSO
  await page.goto(WIKI + '/index.php?title=Special:LinkSSO');
  await sleep(2000);

  // Click "Link your account"
  await hoverAndClick(page.getByRole('button', { name: /Link your account/i }), 600);

  // Handle Keycloak - first visit, type credentials
  await handleKeycloak(page, true);
  await sleep(2500);

  // After callback, navigate to LinkSSO to show linked status
  await page.goto(WIKI + '/index.php?title=Special:LinkSSO');
  await sleep(2000);

  console.log('Flow 2 complete');

  // =============================================
  // FLOW 3: SSO Account Unlinking
  // =============================================
  console.log('--- Flow 3: SSO Account Unlinking ---');

  await sleep(1500);

  await hoverAndClick(page.getByRole('button', { name: /Unlink your account/i }), 800);
  await sleep(2500);

  // Navigate back to show unlinked status
  await page.goto(WIKI + '/index.php?title=Special:LinkSSO');
  await sleep(2000);

  console.log('Flow 3 complete');

  // =============================================
  // FLOW 1: SSO Login
  // =============================================
  console.log('--- Flow 1: SSO Login ---');

  // Re-link via UI for SSO login demo
  await hoverAndClick(page.getByRole('button', { name: /Link your account/i }), 600);

  // Keycloak session should still be active from Flow 2
  await handleKeycloak(page, false);
  await sleep(2000);
  console.log('  Re-linked for SSO login demo');

  // Log out
  await page.goto(WIKI + '/index.php?title=Special:UserLogout');
  await sleep(1500);
  // MediaWiki may show a confirmation page
  const confirmBtn = page.getByRole('button', { name: /Log out/i });
  if (await confirmBtn.isVisible({ timeout: 2000 }).catch(() => false)) {
    await confirmBtn.click();
    await sleep(1500);
  }

  // Go to login page
  await page.goto(WIKI + '/index.php?title=Special:UserLogin');
  await sleep(2000);

  // Click "Arch Linux SSO" button
  await hoverAndClick(page.getByRole('button', { name: 'Arch Linux SSO' }), 700);

  // Keycloak session should auto-redirect (no prompt=login for SSO login)
  await handleKeycloak(page, false);
  await sleep(2500);

  // Show preferences page to prove logged in
  await page.goto(WIKI + '/index.php?title=Special:Preferences');
  await sleep(2500);

  // Show LinkSSO page to show linked status
  await page.goto(WIKI + '/index.php?title=Special:LinkSSO');
  await sleep(2500);

  console.log('Flow 1 complete');

  await sleep(2000);
  await context.close();
  await browser.close();
  console.log('Done. Video in /tmp/archweb-demo/raw-wiki/');
})();
