// Injected into a facebook.com page inside the app's WebView. Ports the CORE of
// content/fb-content.js (desktop) — open composer, type, publish, detect outcome —
// adapted to run standalone and resolve a JSON result the Kotlin side awaits.
//
// v1: TEXT posts only. Media / colored / poll / feeling / mentions are later, same
// as the desktop selectors. The SELECTORS block is the thing to tweak when FB's DOM
// shifts — kept byte-compatible with the desktop content script on purpose.
(function () {
  if (window.__oaiFbReady) return;
  window.__oaiFbReady = true;

  const SELECTORS = {
    composerOpen: [
      '[role="button"][aria-label*="כאן כותבים"]',
      '[role="button"][aria-label*="Write something" i]',
      '[role="button"][aria-label*="Create" i][aria-label*="post" i]',
      '[role="button"][aria-label*="כתב"]',
      '[role="button"][aria-label*="הוסיפו פוסט"]',
      '[role="button"][aria-label*="צור פוסט"]',
    ],
    dialog: '[role="dialog"]',
    editable: [
      '[role="dialog"] [contenteditable="true"][role="textbox"]',
      '[role="dialog"] [contenteditable="true"]',
    ],
    submit: [
      '[role="dialog"] [aria-label="פרסום"]',
      '[role="dialog"] [aria-label="פרסם"]',
      '[role="dialog"] [aria-label="Post"]',
      '[role="dialog"] [aria-label="Publish"]',
    ],
  };

  const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
  const rand = (a, b) => a + Math.floor(Math.random() * (b - a));

  function qsAny(selectors, root) {
    root = root || document;
    for (const sel of selectors) { const el = root.querySelector(sel); if (el) return el; }
    return null;
  }

  function findComposerByText() {
    const cands = document.querySelectorAll('[role="button"],div[role="button"],[role="textbox"]');
    for (const el of cands) {
      const t = (el.innerText || el.getAttribute('aria-label') || '');
      if (/כאן כותבים|write something|כתוב משהו|צור פוסט|הוסיפו פוסט/i.test(t)) return el;
    }
    return null;
  }

  function waitFor(selectors, timeout) {
    return new Promise((resolve, reject) => {
      const deadline = Date.now() + (timeout || 15000);
      const tick = () => {
        const el = qsAny(selectors);
        if (el) return resolve(el);
        if (Date.now() > deadline) return reject(new Error('timeout: ' + selectors[0]));
        setTimeout(tick, 250);
      };
      tick();
    });
  }

  // Character-by-character insert that FB's React composer actually accepts.
  function typeChar(el, ch) {
    const kc = ch.length === 1 ? ch.charCodeAt(0) : 0;
    const opts = { key: ch === '\n' ? 'Enter' : ch, keyCode: kc, which: kc, bubbles: true, cancelable: true, composed: true };
    el.dispatchEvent(new KeyboardEvent('keydown', opts));
    el.dispatchEvent(new InputEvent('beforeinput', { inputType: 'insertText', data: ch, bubbles: true, cancelable: true, composed: true }));
    const ok = document.execCommand && document.execCommand('insertText', false, ch);
    if (!ok) el.dispatchEvent(new InputEvent('input', { inputType: 'insertText', data: ch, bubbles: true, cancelable: true, composed: true }));
    el.dispatchEvent(new KeyboardEvent('keyup', opts));
  }

  async function typeInto(el, text) {
    el.focus();
    el.dispatchEvent(new MouseEvent('mousedown', { bubbles: true }));
    el.dispatchEvent(new MouseEvent('mouseup', { bubbles: true }));
    el.dispatchEvent(new MouseEvent('click', { bubbles: true }));
    for (const ch of text) { typeChar(el, ch); await sleep(rand(25, 90)); }
  }

  // Strongly biased toward success — FB shows a visible error on real failure.
  async function detectOutcome(dialog, snippet, timeout) {
    const deadline = Date.now() + (timeout || 12000);
    const failWords = ['try again', 'נסה שוב', 'משהו השתבש', 'something went wrong', 'לא ניתן', "couldn't", 'תקן'];
    while (Date.now() < deadline) {
      const body = (document.body.innerText || '').toLowerCase();
      for (const w of failWords) if (body.includes(w.toLowerCase())) return { ok: false, signal: 'error-text: ' + w };
      if (dialog && !document.body.contains(dialog)) return { ok: true, signal: 'dialog-removed' };
      if (snippet && snippet.length > 12 && body.includes(snippet.toLowerCase().slice(0, 40))) return { ok: true, signal: 'post-visible' };
      await sleep(400);
    }
    // No error surfaced within the window → treat as success (matches desktop).
    return { ok: true, signal: 'no-error-timeout' };
  }

  // The public entry the Kotlin side calls. Returns a Promise<{ok, signal, error}>.
  window.__oaiPublishFacebook = async function (text) {
    try {
      if (!text || !text.trim()) return { ok: false, error: 'empty text' };
      let opener = qsAny(SELECTORS.composerOpen) || findComposerByText();
      if (!opener) { try { opener = await waitFor(SELECTORS.composerOpen, 8000); } catch (e) {} }
      if (!opener) return { ok: false, error: 'composer button not found' };
      await sleep(rand(800, 2200));
      opener.click();

      await waitFor([SELECTORS.dialog], 10000);
      await sleep(800);
      const editable = await waitFor(SELECTORS.editable, 8000);
      await sleep(rand(400, 1200));
      await typeInto(editable, text);

      const dialog = document.querySelector(SELECTORS.dialog);
      const submit = await waitFor(SELECTORS.submit, 8000);
      await sleep(rand(600, 1500));
      submit.click();

      const outcome = await detectOutcome(dialog, text, 12000);
      return outcome.ok ? { ok: true, signal: outcome.signal } : { ok: false, error: outcome.signal };
    } catch (e) {
      return { ok: false, error: String((e && e.message) || e) };
    }
  };
})();
