// ============================================================
// PE GUIDE — smoke tests for the Physical Exam Guide tab
// ============================================================
// Exercises the full rendering path: tab load → age group selection →
// system switching (msk / neuro / resp / cv) → expected per-system
// cards (scales, sounds library for resp, APTM image + innocent
// murmur panel for cv) → step toggle interaction.
//
// Uses the shared fixture so any uncaught JS error or console.error
// fails the test automatically (catches a repeat of the SSO-bug
// class on this page).
// ============================================================

const { test, expect, E2E_BASE } = require('../fixtures');

async function openPEGuide(page) {
  await page.goto(E2E_BASE + '/');
  await page.waitForSelector('button.tab-btn', { timeout: 15000 });
  // On mobile the sidebar collapses behind a hamburger. Open it so the
  // tab button is actually in the viewport before we click it.
  const vp = page.viewportSize();
  if (vp && vp.width <= 768) {
    await page.click('#btn-menu-toggle').catch(() => {});
  }
  await page.click('button.tab-btn[data-tab="peguide"]');
  await page.waitForFunction(() => {
    const el = document.getElementById('peguide-tab');
    return el && el.classList.contains('active') && el.innerHTML.trim().length > 100;
  }, { timeout: 15000 });
}

async function selectAge(page, value) {
  await page.selectOption('#pe-age-group', value);
  // Wait for components to render (at least one card with a step)
  await page.waitForFunction(() => {
    return document.querySelectorAll('#pe-content .pe-step').length > 0;
  }, { timeout: 5000 });
}

async function switchSystem(page, sys) {
  await page.click('button.wv-subtab-btn[data-pesystem="' + sys + '"]');
  // Either steps are there, or the resp/cv cards are (which have no .pe-step)
  await page.waitForFunction((s) => {
    const content = document.getElementById('pe-content');
    if (!content) return false;
    if (s === 'resp') return content.innerHTML.includes('Respiratory sounds library');
    if (s === 'cv')   return content.innerHTML.includes('Auscultation landmarks');
    return content.querySelectorAll('.pe-step').length > 0;
  }, sys, { timeout: 5000 });
}

test.describe('PE Guide — smoke', () => {

  test('tab loads with empty-state message before age group selected', async ({ authedPage: _, page }) => {
    await openPEGuide(page);
    await expect(page.locator('#pe-content')).toContainText(/Select an age group/i);
  });

  test('MSK (default) renders with overview and grading scales for adolescent', async ({ authedPage: _, page }) => {
    await openPEGuide(page);
    await selectAge(page, 'adolescent');
    await expect(page.locator('#pe-content')).toContainText('Musculoskeletal');
    await expect(page.locator('#pe-content')).toContainText(/Scoliometer|Beighton/);
    // At least one step card present
    await expect(page.locator('.pe-step').first()).toBeVisible();
  });

  test('switches to Neuro and shows MRC scale + teaching pearl', async ({ authedPage: _, page }) => {
    await openPEGuide(page);
    await selectAge(page, 'adolescent');
    await switchSystem(page, 'neuro');
    await expect(page.locator('#pe-content')).toContainText('Neurologic');
    await expect(page.locator('#pe-content')).toContainText(/MRC strength/i);
    // Teaching pearl rendered (amber block)
    await expect(page.locator('#pe-content')).toContainText(/Pronator drift/i);
  });

  test('Respiratory system shows the 7-sound library, all with real audio players', async ({ authedPage: _, page }) => {
    await openPEGuide(page);
    await selectAge(page, 'adolescent');
    await switchSystem(page, 'resp');
    await expect(page.locator('#pe-content')).toContainText('Respiratory sounds library');
    // All 7 sounds must render as native <audio controls> elements (pause/seek available)
    const audioPlayers = page.locator('#pe-content .pe-audio');
    await expect(audioPlayers).toHaveCount(7);
    // Every one has a src attribute pointing at /audio/respiratory/*.ogg (no synth fallbacks)
    const srcs = await audioPlayers.evaluateAll(els => els.map(e => e.getAttribute('src')));
    for (const src of srcs) {
      expect(src, 'respiratory audio src').toMatch(/^\/audio\/respiratory\/.+\.ogg$/);
    }
    // Grunting entry must NOT appear in the SOUND LIBRARY (removed — no openly-licensed
    // recording). The phrase "expiratory grunting" still appears in clinical teaching
    // steps, which is fine; just assert the sounds library has no grunting card.
    const libraryText = await page
      .locator('#pe-content .card')
      .filter({ hasText: /Respiratory sounds library/i })
      .innerText();
    expect(libraryText).not.toMatch(/Grunting/i);
    // RR scale renders
    await expect(page.locator('#pe-content')).toContainText(/Respiratory rate/i);
    // Observation-first inspection card present
    await expect(page.locator('#pe-content')).toContainText(/Inspection/i);
  });

  test('Cardiovascular system shows APTM image + all 5 landmarks + innocent murmur panel', async ({ authedPage: _, page }) => {
    await openPEGuide(page);
    await selectAge(page, 'adolescent');
    await switchSystem(page, 'cv');
    // APTM diagram image loaded
    const aptmImg = page.locator('img[src*="aptm.png"]');
    await expect(aptmImg).toBeVisible();
    // Wait for it to actually have painted pixels (naturalWidth > 0 = fetched successfully)
    await expect.poll(async () => {
      return await aptmImg.evaluate(el => el.naturalWidth);
    }, { timeout: 10000 }).toBeGreaterThan(0);
    // All 5 landmark letters in the legend
    for (const letter of ['A', 'P', 'E', 'T', 'M']) {
      await expect(page.locator('#pe-content')).toContainText(letter);
    }
    // Innocent murmur panel
    await expect(page.locator('#pe-content')).toContainText(/Innocent murmurs/i);
    await expect(page.locator('#pe-content')).toContainText(/Still.s/i);
    await expect(page.locator('#pe-content')).toContainText(/Venous hum/i);
    // 7 "S" criteria footer
    await expect(page.locator('#pe-content')).toContainText(/7.*S/);
  });

  test('each age group has resp + cv data (no "no data" empty state)', async ({ authedPage: _, page }) => {
    await openPEGuide(page);
    const ages = ['newborn', 'infant', 'toddler', 'preschool', 'school', 'adolescent'];
    for (const age of ages) {
      await selectAge(page, age);
      for (const sys of ['resp', 'cv']) {
        await switchSystem(page, sys);
        // Must NOT show the "no data" placeholder
        const content = await page.locator('#pe-content').innerText();
        expect(content, `${age}/${sys} should have data`).not.toMatch(/No data for this combination/i);
        // Should have at least one component card with at least one step
        const stepCount = await page.locator('.pe-step').count();
        expect(stepCount, `${age}/${sys} should have at least 1 step`).toBeGreaterThan(0);
      }
    }
  });

  test('step toggle cycles Normal → Abnormal → Skip and updates visual state', async ({ authedPage: _, page }) => {
    await openPEGuide(page);
    await selectAge(page, 'adolescent');
    await switchSystem(page, 'neuro');
    const firstStep = page.locator('.pe-step').first();
    // Click Normal (✓) button
    await firstStep.locator('button[data-pe-status="normal"]').click();
    // Background should turn green (#ecfdf5)
    await expect.poll(async () => {
      return await firstStep.evaluate(el => el.style.background);
    }).toMatch(/rgb\(236, 253, 245\)|#ecfdf5/);
    // Click Abnormal (✗) — note field should appear
    await firstStep.locator('button[data-pe-status="abnormal"]').click();
    await expect(firstStep.locator('.pe-note')).toBeVisible();
    // Click Skip (—) — note field hides
    await firstStep.locator('button[data-pe-status="skip"]').click();
    await expect(firstStep.locator('.pe-note')).toBeHidden();
  });

  test('grading scales card is collapsible and expands on click', async ({ authedPage: _, page }) => {
    await openPEGuide(page);
    await selectAge(page, 'adolescent');
    await switchSystem(page, 'neuro');
    // <details> element with "Grading scales" summary
    const details = page.locator('details').filter({ hasText: /Grading scales/ });
    await expect(details).toBeVisible();
    // Open it
    await details.locator('summary').click();
    // Should now see at least one scale title
    await expect(details).toContainText(/MRC strength/);
  });
});
