/**
 * Capture README screenshots for the Maintenance Supporter integration.
 *
 * Prerequisites:
 *   docker compose up -d                           # ha-maint
 *   docker compose --profile testing up -d          # playwright
 *   python scripts/setup_demo.py && python scripts/seed_history.py
 *   docker compose restart homeassistant-dev
 *
 * Usage:
 *   cd custom_components/maintenance_supporter/frontend-src
 *   node capture-readme-screenshots.mjs
 *
 * Or with explicit refresh token:
 *   HA_REFRESH_TOKEN=<token> node capture-readme-screenshots.mjs
 */

import { chromium } from "playwright";
import fs from "fs";
import path from "path";
import { fileURLToPath } from "url";

const __dirname = path.dirname(fileURLToPath(import.meta.url));
const HA = "http://homeassistant-dev:8123";
const OUTPUT = path.resolve(__dirname, "../../../docs/images");

// ---------------------------------------------------------------------------
// Access token: env var or auto-extract from docker/.env
// ---------------------------------------------------------------------------
function getAccessToken() {
  if (process.env.HA_TOKEN) return process.env.HA_TOKEN;
  const envPath = path.resolve(__dirname, "../../../docker/.env");
  try {
    const lines = fs.readFileSync(envPath, "utf8").split("\n");
    for (const line of lines) {
      if (line.startsWith("HA_TOKEN=")) return line.split("=")[1].trim();
    }
  } catch { /* fall through */ }
  console.error("Set HA_TOKEN or ensure docker/.env exists with HA_TOKEN=...");
  process.exit(1);
}

const ACCESS_TOKEN = getAccessToken();
fs.mkdirSync(OUTPUT, { recursive: true });

// ---------------------------------------------------------------------------
// Helpers
// ---------------------------------------------------------------------------
function panelJS() {
  return `
    var ha = document.querySelector('home-assistant');
    var main = ha && ha.shadowRoot && ha.shadowRoot.querySelector('home-assistant-main');
    var drawer = main && main.shadowRoot && main.shadowRoot.querySelector('ha-drawer');
    var resolver = drawer && drawer.querySelector('partial-panel-resolver');
    var custom = resolver && resolver.querySelector('ha-panel-custom');
    var p = custom && custom.querySelector('maintenance-supporter-panel');
  `;
}

async function login(page) {
  await page.goto(HA);
  await page.waitForTimeout(1000);
  await page.evaluate((token) => {
    localStorage.setItem("hassTokens", JSON.stringify({
      hassUrl: "http://homeassistant-dev:8123",
      clientId: "http://homeassistant-dev:8123/",
      refresh_token: "",
      access_token: token,
      token_type: "Bearer",
      expires_in: 86400,
      expires: Date.now() + 86400000,
    }));
  }, ACCESS_TOKEN);
  await page.goto(HA + "/maintenance-supporter");
  await page.waitForTimeout(8000);
}

/** Returns true if page is still alive, false if it crashed. */
async function setEnglishDark(page) {
  try {
    await page.evaluate(async () => {
      const ha = document.querySelector("home-assistant");
      const hass = ha && (ha.__hass || ha.hass);
      if (hass && hass.connection) {
        await hass.connection.sendMessagePromise({
          type: "frontend/set_user_data",
          key: "language",
          value: { language: "en", number_format: "language" },
        });
        await hass.connection.sendMessagePromise({
          type: "frontend/set_user_data",
          key: "core",
          value: { selectedTheme: { theme: "default", dark: true } },
        });
      }
    });
    await page.goto(HA + "/maintenance-supporter");
    await page.waitForTimeout(8000);
    return true;
  } catch {
    console.log("  (language/theme change crashed, will recover)");
    return false;
  }
}

async function getObjectData(page, maxWait = 30000) {
  const start = Date.now();
  while (Date.now() - start < maxWait) {
    const raw = await page.evaluate(`{
      ${panelJS()}
      var result = [];
      if (p && p._objects) {
        for (var i = 0; i < p._objects.length; i++) {
          var obj = p._objects[i];
          var tasks = [];
          if (obj.tasks) for (var j = 0; j < obj.tasks.length; j++) {
            tasks.push({ id: obj.tasks[j].id, name: obj.tasks[j].name,
              checklist: obj.tasks[j].checklist || [],
              adaptive: !!(obj.tasks[j].adaptive_config && obj.tasks[j].adaptive_config.enabled) });
          }
          result.push({ entry_id: obj.entry_id, name: obj.object.name, tasks: tasks });
        }
      }
      JSON.stringify(result);
    }`);
    const data = JSON.parse(raw);
    if (data.length > 0) return data;
    await page.waitForTimeout(1000);
  }
  throw new Error("Timed out waiting for panel objects to load");
}

function find(objects, objName, taskName) {
  const obj = objects.find((o) => o.name === objName);
  if (!obj) throw new Error(`Object '${objName}' not found`);
  if (!taskName) return { entryId: obj.entry_id, obj };
  const task = obj.tasks.find((t) => t.name === taskName);
  if (!task) throw new Error(`Task '${taskName}' not found in '${objName}'`);
  return { entryId: obj.entry_id, taskId: task.id, task, obj };
}

async function shot(page, name) {
  const filePath = path.join(OUTPUT, name);
  await page.screenshot({ path: filePath });
  console.log(`  ${name}`);
}

// ---------------------------------------------------------------------------
// Main
// ---------------------------------------------------------------------------
const browser = await chromium.connect("ws://localhost:3000");
console.log("Connected to Playwright server\n");

// ======================== DESKTOP (1280×900) ========================
const ctx = await browser.newContext({ viewport: { width: 1280, height: 900 }, locale: "en", colorScheme: "dark" });
let page = await ctx.newPage();
await login(page);
const langOk = await setEnglishDark(page);
if (!langOk) {
  // Language change crashed the page — recreate and re-login
  try { await page.close(); } catch { /* already dead */ }
  page = await ctx.newPage();
  await login(page);
}

const objects = await getObjectData(page);
console.log(`Found ${objects.length} objects: ${objects.map((o) => o.name).join(", ")}\n`);

// 1. Overview
console.log("Desktop screenshots:");
await shot(page, "overview.png");

// 2. Object detail — Electric Car (most tasks)
const ev = find(objects, "Electric Car");
await page.evaluate(`{ ${panelJS()} if (p) p._showObject('${ev.entryId}'); }`);
await page.waitForTimeout(2000);
await shot(page, "object-detail.png");

// 3. Task detail — HVAC Filter Replacement (threshold trigger with sparkline)
const hvac = find(objects, "HVAC System", "Filter Replacement");
await page.evaluate(`{ ${panelJS()} if (p) p._showTask('${hvac.entryId}', '${hvac.taskId}'); }`);
await page.waitForTimeout(5000);
await shot(page, "task-detail.png");

// 3b. Multi-entity trigger — Electric Car Tire Pressure Check (4 sensors, threshold < 2.0 bar)
const tire = find(objects, "Electric Car", "Tire Pressure Check");
await page.evaluate(`{ ${panelJS()} if (p) p._showTask('${tire.entryId}', '${tire.taskId}'); }`);
await page.waitForTimeout(5000);
await shot(page, "multi-entity-trigger.png");

// 3c. Compound trigger — Water Filter System (OR: threshold + counter)
const wf = find(objects, "Water Filter System", "Cartridge Replacement");
await page.evaluate(`{ ${panelJS()} if (p) p._showTask('${wf.entryId}', '${wf.taskId}'); }`);
await page.waitForTimeout(5000);
await shot(page, "compound-trigger.png");

// 4. Task history — Washing Machine Drum Cleaning (8 entries)
const wm = find(objects, "Washing Machine", "Drum Cleaning");
await page.evaluate(`{ ${panelJS()} if (p) p._showTask('${wm.entryId}', '${wm.taskId}'); }`);
await page.waitForTimeout(2000);
// Switch to history tab
await page.evaluate(`{
  ${panelJS()}
  if (p) {
    var tabs = p.shadowRoot && p.shadowRoot.querySelectorAll('.tab');
    if (tabs && tabs.length > 1) tabs[1].click();
  }
}`);
await page.waitForTimeout(1500);
await shot(page, "task-history.png");

// 5. Complete dialog — use a task with checklist if possible
const pool = find(objects, "Swimming Pool", "pH Test");
await page.evaluate(`{ ${panelJS()} if (p) p._showTask('${pool.entryId}', '${pool.taskId}'); }`);
await page.waitForTimeout(2000);
await page.evaluate(`{
  ${panelJS()}
  if (p) p._openCompleteDialog('${pool.entryId}', '${pool.taskId}', 'pH Test',
    ${JSON.stringify(pool.task.checklist)}, ${pool.task.adaptive});
}`);
await page.waitForTimeout(1500);
await shot(page, "complete-dialog.png");
// Close dialog
await page.keyboard.press("Escape");
await page.waitForTimeout(500);

// 6. QR dialog
await page.evaluate(`{
  ${panelJS()}
  if (p) p._openQrForTask('${hvac.entryId}', '${hvac.taskId}', 'HVAC System', 'Filter Replacement');
}`);
await page.waitForTimeout(3000);
await shot(page, "qr-dialog.png");
await page.keyboard.press("Escape");
await page.waitForTimeout(500);

// 7. Config flow — integration page
await page.goto(HA + "/config/integrations/integration/maintenance_supporter");
await page.waitForTimeout(4000);
await shot(page, "config-flow.png");

// 8. Lovelace card — create temp dashboard via REST then screenshot
try {
  // Create dashboard via lovelace WS — must return a promise
  const created = await page.evaluate(() => {
    return new Promise((resolve, reject) => {
      const ha = document.querySelector("home-assistant");
      const hass = ha && (ha.__hass || ha.hass);
      if (!hass || !hass.connection) { reject(new Error("no hass")); return; }
      hass.connection.sendMessagePromise({
        type: "lovelace/dashboards/create",
        url_path: "maintenance-demo",
        title: "Maintenance Demo",
        mode: "storage",
      }).then(() => resolve(true)).catch((e) => {
        // Dashboard may already exist, try saving config directly
        resolve(true);
      });
    });
  });
  // Save config to the dashboard
  await page.evaluate(() => {
    return new Promise((resolve) => {
      const ha = document.querySelector("home-assistant");
      const hass = ha && (ha.__hass || ha.hass);
      if (!hass) { resolve(); return; }
      hass.connection.sendMessagePromise({
        type: "lovelace/config/save",
        url_path: "maintenance-demo",
        config: {
          title: "Maintenance Demo",
          views: [{
            title: "Overview",
            cards: [{
              type: "custom:maintenance-supporter-card",
              title: "Maintenance Overview",
              show_header: true,
              show_actions: true,
            }],
          }],
        },
      }).then(() => resolve()).catch(() => resolve());
    });
  });
  await page.goto(HA + "/maintenance-demo/0");
  await page.waitForTimeout(6000);
  await shot(page, "lovelace-card.png");
  // Cleanup
  await page.evaluate(() => {
    const ha = document.querySelector("home-assistant");
    const hass = ha && (ha.__hass || ha.hass);
    if (hass) {
      hass.connection.sendMessagePromise({
        type: "lovelace/dashboards/delete",
        dashboard_id: "maintenance-demo",
      }).catch(() => {});
    }
  });
} catch (e) {
  console.log("  lovelace-card.png SKIPPED:", e.message);
}

// 9. Calendar — show month view with maintenance events
await page.goto(HA + "/calendar");
await page.waitForTimeout(5000);
// Enable the maintenance calendar checkbox
try {
  // Pre-select the maintenance calendar in localStorage so the panel shows it
  await page.evaluate(() => {
    // HA stores selected calendars in hass-panel-calendar-selected per-user
    // Try to find and click the checkbox through shadow DOM
    const ha = document.querySelector("home-assistant");
    const main = ha?.shadowRoot?.querySelector("home-assistant-main");
    const drawer = main?.shadowRoot?.querySelector("ha-drawer");
    const resolver = drawer?.querySelector("partial-panel-resolver");
    const calPanel = resolver?.querySelector("ha-panel-calendar");
    const sr = calPanel?.shadowRoot;
    if (!sr) return "no-shadow-root";
    // Try ha-check-list-item or ha-checkbox or mwc-checkbox
    const checkItems = sr.querySelectorAll("ha-check-list-item, ha-checkbox-list-item");
    for (const item of checkItems) {
      if (item.textContent?.includes("Maintenance")) {
        if (!item.selected && !item.checked) item.click();
        return "clicked";
      }
    }
    // Try ha-calendar-list-item approach
    const calList = sr.querySelector("ha-sidebar-calendars, .calendars");
    if (calList) {
      const labels = calList.querySelectorAll("label, li, div");
      for (const lbl of labels) {
        if (lbl.textContent?.includes("Maintenance")) {
          const cb = lbl.querySelector("input[type=checkbox], ha-checkbox");
          if (cb && !cb.checked) cb.click();
          return "clicked-inner";
        }
      }
    }
    // Dump what we find for debugging
    return "items:" + sr.innerHTML.substring(0, 500);
  }).then(r => console.log("  calendar checkbox:", r));
  await page.waitForTimeout(3000);
} catch (e) { console.log("  calendar checkbox error:", e.message); }

// Advance the calendar by one month — with a freshly-seeded demo setup most
// tasks' next_due dates are 30-90 days out, so the default "current month"
// view typically renders empty. Attempt a pixel-click on the "Next" chevron
// in HA's calendar toolbar (approx. (650, 85) at 1280×900); fall through
// quietly if the click misses.  If the resulting screenshot lands in an
// empty month, prefer keeping the previously committed calendar.png over
// overwriting it — `git checkout HEAD -- docs/images/calendar.png`.
try {
  await page.mouse.click(650, 85);
  await page.waitForTimeout(2500);
} catch (e) { console.log("  calendar next-month error:", e.message); }

await shot(page, "calendar.png");

// 10. Sensor attributes — Developer Tools States filtered to show one entity with all attributes
await page.goto(HA + "/developer-tools/state");
await page.waitForTimeout(4000);
try {
  // Filter entities by typing into the search field
  // The filter input is deep in shadow DOM; use evaluate to find and focus it
  await page.evaluate(() => {
    const ha = document.querySelector("home-assistant");
    const main = ha && ha.shadowRoot && ha.shadowRoot.querySelector("home-assistant-main");
    const drawer = main && main.shadowRoot && main.shadowRoot.querySelector("ha-drawer");
    const resolver = drawer && drawer.querySelector("partial-panel-resolver");
    const devTools = resolver && resolver.querySelector("ha-panel-developer-tools");
    if (!devTools || !devTools.shadowRoot) return;
    const statesPanel = devTools.shadowRoot.querySelector("developer-tools-state");
    if (!statesPanel || !statesPanel.shadowRoot) return;
    // Find the entity filter input (search field in the table header)
    const searchInputs = statesPanel.shadowRoot.querySelectorAll("search-input, ha-search-input, input[type=search]");
    // Also try generic inputs
    const allInputs = statesPanel.shadowRoot.querySelectorAll("input");
    const target = searchInputs[0] || allInputs[0];
    if (target) {
      target.focus();
      target.value = "sensor.hvac_system";
      target.dispatchEvent(new Event("input", { bubbles: true }));
      target.dispatchEvent(new Event("change", { bubbles: true }));
    }
  });
  await page.waitForTimeout(1000);
  // Fallback: use keyboard to type into whatever is focused
  await page.keyboard.type("sensor.hvac_system", { delay: 30 });
  await page.waitForTimeout(2000);
} catch { /* filter may not work */ }
await shot(page, "entity-attributes.png");

await ctx.close();

// ======================== MOBILE (375×812) ========================
console.log("\nMobile screenshots:");
try {
  const mCtx = await browser.newContext({ viewport: { width: 375, height: 812 }, locale: "en", isMobile: true, colorScheme: "dark" });
  const mPage = await mCtx.newPage();
  await login(mPage);
  // Skip setEnglishDark for mobile — sendMessage can crash mobile contexts

  const mObjects = await getObjectData(mPage);

  // 11. Mobile overview
  await shot(mPage, "mobile-overview.png");

  // 12. Mobile task detail
  const mHvac = find(mObjects, "HVAC System", "Filter Replacement");
  await mPage.evaluate(`{ ${panelJS()} if (p) p._showTask('${mHvac.entryId}', '${mHvac.taskId}'); }`);
  await mPage.waitForTimeout(2000);
  await shot(mPage, "mobile-task.png");

  await mCtx.close();
} catch (e) {
  console.log("  mobile screenshots SKIPPED:", e.message);
}

// ======================== NOTIFICATION MOCKUP (375×812) ========================
// Rendered as pure HTML/CSS — no HA login needed, own context for stability
console.log("\nNotification mockup:");
const nCtx = await browser.newContext({ viewport: { width: 375, height: 812 }, locale: "en" });
const notifPage = await nCtx.newPage();
await notifPage.setContent(`
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=375, initial-scale=1">
<style>
  * { margin: 0; padding: 0; box-sizing: border-box; }
  body {
    width: 375px; height: 812px;
    background: linear-gradient(135deg, #0a0a2e 0%, #1a1a3e 30%, #0d2137 70%, #0a1628 100%);
    font-family: -apple-system, BlinkMacSystemFont, "SF Pro Display", "Helvetica Neue", sans-serif;
    -webkit-font-smoothing: antialiased;
    display: flex; flex-direction: column; align-items: center;
    overflow: hidden; position: relative;
  }
  /* Lock screen clock */
  .lock-time {
    margin-top: 120px;
    font-size: 76px; font-weight: 700; letter-spacing: 1px;
    color: #fff;
    text-align: center; line-height: 1;
  }
  .lock-date {
    font-size: 20px; font-weight: 400; color: rgba(255,255,255,0.7);
    margin-top: 6px; text-align: center;
  }
  /* Notification card */
  .notif-card {
    margin-top: 60px; width: 345px;
    background: rgba(255,255,255,0.15);
    backdrop-filter: blur(40px); -webkit-backdrop-filter: blur(40px);
    border-radius: 16px;
    overflow: hidden;
  }
  .notif-header {
    display: flex; align-items: center; gap: 8px;
    padding: 12px 14px 0 14px;
  }
  .notif-icon {
    width: 22px; height: 22px; border-radius: 5px;
    background: #038fc7;
    display: flex; align-items: center; justify-content: center;
    flex-shrink: 0;
  }
  .notif-icon svg { width: 14px; height: 14px; }
  .notif-app {
    font-size: 13px; font-weight: 500; color: rgba(255,255,255,0.6);
    flex: 1;
  }
  .notif-time {
    font-size: 13px; color: rgba(255,255,255,0.45);
  }
  .notif-body { padding: 6px 14px 14px 14px; }
  .notif-title {
    font-size: 15px; font-weight: 600; color: #fff;
    margin-bottom: 3px;
  }
  .notif-message {
    font-size: 15px; font-weight: 400; color: rgba(255,255,255,0.85);
    line-height: 1.35;
  }
  /* Action buttons */
  .notif-actions {
    display: flex;
    border-top: 0.5px solid rgba(255,255,255,0.15);
  }
  .notif-action {
    flex: 1;
    padding: 13px 0;
    text-align: center;
    font-size: 15px; font-weight: 500;
    color: #64d2ff;
    cursor: pointer;
  }
  .notif-action:not(:last-child) {
    border-right: 0.5px solid rgba(255,255,255,0.15);
  }
  /* Home bar indicator */
  .home-bar {
    position: absolute; bottom: 8px;
    width: 134px; height: 5px;
    background: rgba(255,255,255,0.3);
    border-radius: 3px;
  }
</style>
</head>
<body>
  <div class="lock-time">9:41</div>
  <div class="lock-date">Saturday, March 7</div>

  <div class="notif-card">
    <div class="notif-header">
      <div class="notif-icon">
        <svg viewBox="0 0 24 24" fill="white">
          <path d="M12 3L4 9v12h5v-7h6v7h5V9l-8-6z"/>
        </svg>
      </div>
      <span class="notif-app">HOME ASSISTANT</span>
      <span class="notif-time">now</span>
    </div>
    <div class="notif-body">
      <div class="notif-title">Maintenance Overdue!</div>
      <div class="notif-message">Oil Change for Family Car is 3 day(s) overdue!</div>
    </div>
    <div class="notif-actions">
      <div class="notif-action">\u2705 Complete</div>
      <div class="notif-action">\u23ed\ufe0f Skip</div>
      <div class="notif-action">\ud83d\udca4 Snooze</div>
    </div>
  </div>

  <div class="home-bar"></div>
</body>
</html>
`, { waitUntil: "networkidle" });
await notifPage.waitForTimeout(500);
await shot(notifPage, "notification-actions.png");
await notifPage.close();
await nCtx.close();

await browser.close();

console.log(`\nAll screenshots saved to ${OUTPUT}`);
