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

const AURWEB = 'http://127.0.0.1:8082';
const KC_USER = 'testdev';
const KC_PASS = 'testpass';
const KC_SUB = 'a135bad2-5164-44bc-a5e9-c6ff4cc21af9';
const AUR_USER = 'testuser';
const AUR_PASS = 'testuser123';

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

function setSsoAccountId(value) {
  const val = value === null ? 'NULL' : `'${value}'`;
  dbExec(`UPDATE Users SET SSOAccountID = ${val} WHERE Username = '${AUR_USER}';`);
  console.log(`  SSOAccountID -> ${val}`);
}

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: 3000 }).catch(() => false);

  if (hasUserField && firstVisit) {
    // Full login form -- type both fields naturally
    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)) {
    // Re-auth form (prompt=login with session) -- only password field
    console.log('  Re-auth form (password only)');
    await typeIntoRole(page, 'textbox', 'Password', KC_PASS);
    await sleep(500);
  } else {
    console.log('  No recognized form fields');
    return;
  }

  const signInBtn = page.getByRole('button', { name: 'Sign In' });
  await signInBtn.hover();
  await sleep(500);
  await Promise.all([
    page.waitForURL((url) => !url.toString().includes('auth.josie.cloud'), { timeout: 20000 }),
    signInBtn.click(),
  ]);
  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-aurweb/',
      size: { width: 1280, height: 800 },
    },
  });

  const page = await context.newPage();

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

  setSsoAccountId(KC_SUB);

  await page.goto(AURWEB + '/login');
  await sleep(2000);

  await hoverAndClick(page.getByRole('link', { name: 'Login with SSO' }), 700);
  await page.waitForURL('**/auth.josie.cloud/**', { timeout: 15000 });
  await sleep(1500);

  // First Keycloak visit: type credentials naturally
  await typeIntoRole(page, 'textbox', 'Username or email', KC_USER);
  await sleep(500);
  await typeIntoRole(page, 'textbox', 'Password', KC_PASS);
  await sleep(700);
  await hoverAndClick(page.getByRole('button', { name: 'Sign In' }), 500);
  await page.waitForURL(AURWEB + '/**', { timeout: 15000 });
  await sleep(1500);

  // Show account page to prove logged in with SSO linked
  await page.goto(AURWEB + '/account/' + AUR_USER);
  await sleep(1500);
  const ssoRow = page.getByText('Linked');
  await ssoRow.scrollIntoViewIfNeeded();
  await sleep(2500);

  console.log('Flow 1 complete');

  // =============================================
  // FLOW 2: SSO Account Linking
  // =============================================
  console.log('--- Flow 2: SSO Account Linking ---');

  // Logout via navbar button (POST form)
  await hoverAndClick(page.getByRole('button', { name: 'Logout' }), 600);
  await sleep(1500);

  setSsoAccountId(null);

  await page.goto(AURWEB + '/login');
  await sleep(1200);

  // Use CSS selectors for the login form
  const userField = page.locator('input[name="user"]');
  const passField = page.locator('input[name="passwd"]');

  await userField.click();
  await sleep(200);
  await userField.pressSequentially(AUR_USER, { delay: 55 + Math.random() * 40 });
  await sleep(400);
  await passField.click();
  await sleep(200);
  await passField.pressSequentially(AUR_PASS, { delay: 55 + Math.random() * 40 });
  await sleep(600);

  await hoverAndClick(page.getByRole('button', { name: 'Login' }), 400);
  await page.waitForURL(AURWEB + '/**');
  await sleep(1500);

  // Show account page with "Not linked" before linking
  await page.goto(AURWEB + '/account/' + AUR_USER);
  await sleep(1500);
  const notLinked = page.getByText('Not linked');
  await notLinked.scrollIntoViewIfNeeded();
  await sleep(2000);

  await page.goto(AURWEB + '/account/link-sso');
  await sleep(2000);

  await hoverAndClick(page.getByRole('button', { name: 'Link my account to SSO' }), 600);

  // Keycloak will show with prompt=login, pre-filled creds -- just click Sign In
  await handleKeycloak(page);
  await sleep(2500);

  // Make sure we're on the link-sso page showing linked state
  console.log('  Current URL:', page.url());
  if (!page.url().includes('link-sso')) {
    await page.goto(AURWEB + '/account/link-sso');
    await sleep(1500);
  }

  // Show account page with "Linked" after linking
  await page.goto(AURWEB + '/account/' + AUR_USER);
  await sleep(1500);
  const linkedAfter = page.getByText('Linked');
  await linkedAfter.scrollIntoViewIfNeeded();
  await sleep(2000);

  console.log('Flow 2 complete');

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

  await page.goto(AURWEB + '/account/link-sso');
  await sleep(1500);

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

  // Show account page with "Not linked" after unlinking
  await page.goto(AURWEB + '/account/' + AUR_USER);
  await sleep(1500);
  const unlinkedAfter = page.getByText('Not linked');
  await unlinkedAfter.scrollIntoViewIfNeeded();
  await sleep(2000);

  console.log('Flow 3 complete');
  await context.close();
  await browser.close();
  console.log('Done. Video in /tmp/archweb-demo/raw-aurweb/');
})();
