let lastList = [];

function safeText(el) {
  let t = (el.innerText || el.textContent || '').trim();
  if (t.length > 80) t = t.slice(0, 80) + '…';
  return t;
}

function describe(el) {
  let sel = el.id ? '#' + el.id : el.tagName.toLowerCase();
  if (!el.id && el.className && typeof el.className === 'string') {
    sel += '.' + el.className.trim().split(/\s+/).slice(0, 2).join('.');
  }
  const label = el.getAttribute('aria-label') || el.getAttribute('title') || el.getAttribute('name') || '';
  return {
    tag: el.tagName.toLowerCase(),
    selector: sel,
    text: safeText(el),
    label,
    type: el.getAttribute('type') || '',
    disabled: !!el.disabled,
  };
}

export function listClickables() {
  const els = Array.from(
    document.querySelectorAll(
      'button, a[href], input[type=submit], input[type=button], [role=button], [onclick]'
    )
  );
  lastList = els.filter((e) => {
    const r = e.getBoundingClientRect();
    return r.width > 0 && r.height > 0;
  });
  return lastList.map((el, i) => {
    const d = describe(el);
    d.index = i;
    return d;
  });
}

export function clickElement(params) {
  let el;
  if (params.selector) el = document.querySelector(params.selector);
  else if (typeof params.index === 'number') el = lastList[params.index];
  if (!el) return { ok: false, error: 'element not found' };
  if (el.disabled) return { ok: false, error: 'element is disabled' };
  try {
    el.scrollIntoView({ block: 'center' });
    el.click();
    return { ok: true };
  } catch (e) {
    return { ok: false, error: String(e) };
  }
}

export function typeText(params) {
  let el;
  if (params.selector) el = document.querySelector(params.selector);
  else if (typeof params.index === 'number') el = lastList[params.index];
  if (!el) return { ok: false, error: 'element not found' };
  const proto = Object.getPrototypeOf(el);
  const setter = Object.getOwnPropertyDescriptor(proto, 'value');
  try {
    if (setter && setter.set) setter.set.call(el, params.text || '');
    else el.value = params.text || '';
  } catch {
    el.value = params.text || '';
  }
  el.dispatchEvent(new Event('input', { bubbles: true }));
  el.dispatchEvent(new Event('change', { bubbles: true }));
  return { ok: true };
}

export function evalExpr(params) {
  try {
    const r = (0, eval)(params.expr);
    return { ok: true, value: serialize(r) };
  } catch (e) {
    return { ok: false, error: String(e) };
  }
}

export function currentUrl() {
  return { url: location.href, title: document.title };
}

function serialize(v) {
  if (v === undefined) return 'undefined';
  try {
    return JSON.parse(JSON.stringify(v));
  } catch {
    return String(v);
  }
}

export function dispatch(msg) {
  const p = msg.params || {};
  switch (msg.action) {
    case 'list_clickables':
      return listClickables();
    case 'click':
      return clickElement(p);
    case 'eval':
      return evalExpr(p);
    case 'current_url':
      return currentUrl();
    case 'type':
      return typeText(p);
    default:
      return { ok: false, error: 'unknown action: ' + msg.action };
  }
}
