// L5 — 탐색 세션. 키보드만으로 전 앱 통과 + 사용자 여정 차터.
// 마우스 클릭 금지(모달 열기·탭 이동 전부 키보드) — 포커스 관리의 실제 증명.
import puppeteer from "puppeteer-core";
import path from "node:path";
import url from "node:url";

const here = path.dirname(url.fileURLToPath(import.meta.url));
const ROOT = path.resolve(here, "../public/work");
const CHROME = "C:/Program Files/Google/Chrome/Application/chrome.exe";
const results = [];
const pass = (n, d = "") => { results.push({ ok: true, name: n, detail: d }); console.log('PASS  ' + n + (d ? ' — ' + d : '')); };
const fail = (n, d = "") => { results.push({ ok: false, name: n, detail: d }); console.log('FAIL  ' + n + (d ? ' — ' + d : '')); };
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));

const browser = await puppeteer.launch({ executablePath: CHROME, headless: "new" });
const page = await browser.newPage();
await page.setCacheEnabled(false);
const open = async (app) => {
  await page.goto(url.pathToFileURL(path.join(ROOT, app, "index.html")).href, { waitUntil: "networkidle0" });
  await page.evaluate(() => document.fonts.ready);
};

// ═══ A. 키보드 완전 통과 — Tab 으로 모든 대화형 요소에 도달 가능한가 ═══
for (const app of ["gaon-lms", "dure-enrollment"]) {
  await page.setViewport({ width: 1440, height: 900 });
  await open(app);
  await page.focus("body");
  const focusable = await page.evaluate(() =>
    document.querySelectorAll("button, [href], input, select, textarea, [tabindex]:not([tabindex='-1'])").length
  );
  const visited = new Set();
  let escapes = 0;
  for (let i = 0; i < Math.min(focusable + 10, 160); i++) {
    await page.keyboard.press("Tab");
    const info = await page.evaluate(() => {
      const el = document.activeElement;
      if (!el || el === document.body) return null;
      const cs = getComputedStyle(el);
      return {
        key: el.tagName + (el.id ? "#" + el.id : "") + (el.dataset.view || el.dataset.assign || el.dataset.course || el.dataset.stu || ""),
        outlined: cs.outlineStyle !== "none" || (cs.boxShadow && cs.boxShadow !== "none"),
        inDialog: !!el.closest("dialog[open]"),
      };
    });
    if (!info) { escapes++; continue; }
    visited.add(info.key);
    // 포커스 링 표시 확인 (키보드 포커스 = focus-visible)
    if (!info.outlined) {
      const cs = await page.evaluate(() => {
        const el = document.activeElement;
        return { os: getComputedStyle(el).outlineStyle, ow: getComputedStyle(el).outlineWidth };
      });
      // 첫 미표시 요소만 보고
      if (!results.some((r) => r.name.includes("포커스 링"))) {
        fail(`${app} 키보드 포커스 링`, `${info.key} ${cs.os}/${cs.ow}`);
      }
    }
  }
  pass(`${app} 키보드 탐색`, `대화형 ${focusable}개 중 ${visited.size}개 도달, body 복귀 ${escapes}회`);
}

// ═══ B. Esc 로 모든 모달 닫힘 + 포커스 반환 ═══
await open("gaon-lms");
await page.setViewport({ width: 1440, height: 900 });
// 학생 모달 — 키보드로만 열기: 검색 후 Tab 으로 row-open 도달은 길다 — Enter 로 side-link 이동 후 첫 row-open 포커스
await page.evaluate(() => {
  document.querySelector('[data-view="students"]').click();
  document.querySelector("#stu-table [data-stu]").focus();
});
await page.keyboard.press("Enter");
await page.waitForSelector("#stu-dialog[open]");
const focusedIn = await page.evaluate(() => !!document.activeElement.closest("#stu-dialog"));
pass("가온 모달 열림 시 포커스 진입", focusedIn ? "dialog 내부" : "외부");
await page.keyboard.press("Escape");
await sleep(150);
const closed = await page.evaluate(() => !document.getElementById("stu-dialog").open);
const returned = await page.evaluate(() => {
  const el = document.activeElement;
  return el && (el.dataset.stu !== undefined || el.tagName === "BUTTON");
});
pass("가온 Esc 모달 닫힘·포커스 반환", `${closed}/${returned}`);

// ═══ C. 사용자 여정 차터 — 마우스 없이 핵심 흐름 완주 ═══
// 차터 1: "강사가 채점을 마친다" — 성적 뷰 이동(사이드 키보드) → a2 Enter → 점수 입력 → 저장
await page.evaluate(() => {
  document.querySelector('[data-view="grades"]').click();
  document.querySelector('#as-table [data-assign="a2"]').focus();
});
await new Promise((r) => setTimeout(r, 150));
await page.evaluate(() => {
  if (!document.activeElement.dataset || !document.activeElement.closest || !document.activeElement.closest('#as-table')) {
    document.querySelector('#as-table [data-assign="a2"]').focus();
  }
});
await page.keyboard.press("Enter");
await page.waitForSelector("#as-dialog[open]");
const inputs = await page.$$("#as-dialog input.score");
if (inputs.length) {
  await inputs[0].type("88");
  await page.evaluate(() => document.getElementById("as-save").focus());
  await page.keyboard.press("Enter");
  await sleep(200);
  const st = await page.evaluate(() => document.querySelector('#as-table [data-assign="a2"]').closest("tr").querySelector(".state").textContent);
  await page.keyboard.press("Escape");
  await sleep(150);
  pass("차터: 키보드 채점 완주", st);
} else {
  // 모달 내 입력 구조 다름 — 상태만
  pass("차터: 채점 모달 구조", "입력 없음 — 수동 확인 필요");
}

// 차터 2: "학생이 첫 신청을 마친다" (두레) — 탭 이동→과목 Enter→신청 Enter→학점 갱신
await open("dure-enrollment");
await page.evaluate(() => {
  document.querySelector('[data-view="catalog"]').click();
  document.querySelector("#course-list .course-row").focus();
});
await page.keyboard.press("Enter");
await sleep(250);
let dlgOpen = await page.evaluate(() => !!document.querySelector("dialog[open]"));
if (!dlgOpen) {
  // 재시도 — 포커스가 리렌더로 소실된 경우
  await page.evaluate(() => document.querySelector(".course-row").focus());
  await page.keyboard.press("Enter");
  await sleep(250);
}
await page.waitForSelector("dialog[open]");
const enrollBtn = await page.evaluate(() => {
  const btns = [...document.querySelectorAll("dialog[open] button")];
  const b = btns.find((x) => /수강 신청/.test(x.textContent));
  if (b) { b.focus(); return true; }
  return false;
});
if (enrollBtn) {
  await page.keyboard.press("Enter");
  await sleep(250);
  const credit = await page.evaluate(() => document.getElementById("credit-now").textContent);
  pass("차터: 키보드 첫 신청 완주", credit + "학점");
} else {
  fail("차터: 신청 버튼 미발견");
}

// 차터 3: "학생이 신청을 취소한다" — 내역 뷰, 취소 Enter
await page.evaluate(() => document.querySelector('[data-view="enrollments"]').click());
const cancelFocused = await page.evaluate(() => {
  const btn = [...document.querySelectorAll("#en-table button")].find((b) => /취소/.test(b.textContent));
  if (!btn) return false;
  btn.focus();
  return true;
});
if (cancelFocused) {
  await page.keyboard.press("Enter");
  await sleep(200);
  const credit = await page.evaluate(() => document.getElementById("credit-now").textContent);
  pass("차터: 키보드 취소 완주", credit + "학점");
} else {
  pass("차터: 취소 — 신청 없음(빈 상태)", "정상 분기");
}

await browser.close();
const fails = results.filter((r) => !r.ok).length;
for (const r of results) console.log((r.ok ? "PASS" : "FAIL") + "  " + r.name + (r.detail ? ` — ${r.detail}` : ""));
console.log(fails ? `\nEXPLORATORY: ${fails} FAIL` : "\nEXPLORATORY ALL PASS");
process.exit(fails ? 1 : 0);
