/**
 * Bombadil spec for Odysseus UI
 */
import { extract, always, eventually, now, actions } from "@antithesishq/bombadil";
export * from "@antithesishq/bombadil/defaults";

// ── Extractors (only place you can access the DOM) ──

const onLoginPage = extract((state) => {
  return state.document.querySelector("#username") !== null;
});

const loginElements = extract((state) => {
  const user = state.document.querySelector("#username") as HTMLElement | null;
  const pass = state.document.querySelector("#password") as HTMLElement | null;
  const btn = state.document.querySelector('button[type="submit"]') as HTMLElement | null;
  if (!user || !pass || !btn) return null;
  const ur = user.getBoundingClientRect();
  const pr = pass.getBoundingClientRect();
  const br = btn.getBoundingClientRect();
  return {
    user: { x: ur.left + ur.width / 2, y: ur.top + ur.height / 2 },
    pass: { x: pr.left + pr.width / 2, y: pr.top + pr.height / 2 },
    btn: { x: br.left + br.width / 2, y: br.top + br.height / 2 },
  };
});

const chatInput = extract((state) => {
  const el = state.document.querySelector("#message") as HTMLElement | null;
  if (!el || (el as any).offsetParent === null) return null;
  const rect = el.getBoundingClientRect();
  return { x: rect.left + rect.width / 2, y: rect.top + rect.height / 2, disabled: (el as any).disabled };
});

const pageHasContent = extract((state) => {
  return state.document.body && state.document.body.children.length > 0;
});

const visibleModals = extract((state) => {
  let count = 0;
  state.document.querySelectorAll(".modal").forEach((m: any) => {
    if (!m.classList.contains("hidden") && m.offsetParent !== null) count++;
  });
  return count;
});

const clickableElements = extract((state) => {
  const els: { name: string; x: number; y: number }[] = [];
  const selectors = "button:not([disabled]),.list-item,.icon-rail-btn,.section-header-flex,.send-btn,.sidebar-brand,input[type=checkbox]";
  state.document.querySelectorAll(selectors).forEach((el: any) => {
    if (el.offsetParent === null) return;
    const rect = el.getBoundingClientRect();
    if (rect.width === 0 || rect.height === 0) return;
    const name = el.id || el.tagName;
    els.push({ name, x: rect.left + rect.width / 2, y: rect.top + rect.height / 2 });
  });
  return els;
});

// ── Login actions ──

export const login = actions(() => {
  const le = loginElements.current;
  if (!le) return [];
  return [
    { Click: { name: "username", point: le.user } },
    { TypeText: { text: "tester", delayMillis: 30 } },
    { Click: { name: "password", point: le.pass } },
    { TypeText: { text: "iloveass123", delayMillis: 30 } },
    { Click: { name: "submit", point: le.btn } },
  ];
});

// ── App exploration ──

export const explore = actions(() => {
  if (onLoginPage.current) return [];
  const acts: any[] = [];

  const els = clickableElements.current || [];
  for (const el of els) {
    acts.push({ Click: { name: el.name, point: { x: el.x, y: el.y } } });
  }

  const input = chatInput.current;
  if (input && !input.disabled) {
    acts.push({ Click: { name: "chat-input", point: { x: input.x, y: input.y } } });
    acts.push({ TypeText: { text: "hello", delayMillis: 50 } });
    acts.push({ PressKey: { code: 13 } });
  }

  acts.push({ ScrollDown: { origin: { x: 512, y: 400 }, distance: 300 } });
  acts.push({ ScrollUp: { origin: { x: 512, y: 400 }, distance: 300 } });
  acts.push("Wait");

  return acts;
});

// ── Properties ──

export const noBlankPage = always(() => pageHasContent.current === true);
export const noModalStacking = always(() => (visibleModals.current || 0) <= 2);
export const chatInputAppears = always(
  now(() => onLoginPage.current === false).implies(
    eventually(() => chatInput.current !== null).within(10, "seconds")
  )
);
