const BRIDGE_SCRIPT_ID = '__qingyu_adapter_bridge__';
const pendingValidationRequests = new Map();

injectAndroidBridge();

window.addEventListener('message', (event) => {
  if (event.source !== window || !event.data || !event.data.type) {
    return;
  }

  if (event.data.type === 'ANDROID_BRIDGE_CALL') {
    const { method, args, messageId } = event.data;

    chrome.runtime.sendMessage({
      type: 'BRIDGE_CALL_FROM_PAGE',
      method,
      args,
      messageId,
    }).catch((error) => {
      console.error('[AdapterAssistant] Failed to forward bridge call:', error);
    });
    return;
  }

  if (event.data.type === 'VALIDATION_RESULT') {
    const { requestId, validationError } = event.data;
    const callbacks = pendingValidationRequests.get(requestId);
    if (!callbacks) {
      return;
    }
    callbacks.resolveValidation(validationError);
    pendingValidationRequests.delete(requestId);
  }
});

chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
  switch (request?.type) {
    case 'PING':
      sendResponse({ success: true, url: location.href, title: document.title });
      return true;

    case 'GET_PAGE_CONTEXT':
      sendResponse(collectPageContext());
      return true;

    case 'GET_FULL_PAGE_SNAPSHOT':
      sendResponse(collectFullPageSnapshot());
      return true;

    case 'RELOAD_AND_EXECUTE_JS':
      executeFixedJs('school.js');
      sendResponse({ success: true, message: 'school.js 已重新注入页面。' });
      return true;

    case 'SHOW_INLINE_DIALOG':
      showInlineDialog(request.dialogType, request.args, request.messageId)
        .then((result) => {
          console.log('[AdapterAssistant] Inline dialog resolved:', request.dialogType, result);
        })
        .catch((error) => {
          console.error('[AdapterAssistant] Inline dialog failed:', error);
        });
      sendResponse({ success: true });
      return true;

    case 'RESOLVE_PROMISE_IN_PAGE':
      window.postMessage({
        type: 'ANDROID_BRIDGE_PROMISE_RESPONSE',
        messageId: request.messageId,
        value: request.value,
        isError: request.isError,
      }, window.location.origin);
      sendResponse({ success: true });
      return true;

    default:
      return false;
  }
});

function injectAndroidBridge() {
  if (document.getElementById(BRIDGE_SCRIPT_ID)) {
    return;
  }

  const script = document.createElement('script');
  script.id = BRIDGE_SCRIPT_ID;
  script.src = chrome.runtime.getURL('injected_bridge.js');
  script.charset = 'UTF-8';
  (document.documentElement || document.head || document.body).appendChild(script);
  console.log('[AdapterAssistant] AndroidBridge injected into page context.');
}

function executeFixedJs(jsFileName) {
  const scriptUrl = chrome.runtime.getURL(jsFileName);
  const existing = document.querySelector(`script[src="${scriptUrl}"]`);
  if (existing) {
    existing.remove();
  }

  const script = document.createElement('script');
  script.src = scriptUrl;
  script.charset = 'UTF-8';
  (document.documentElement || document.head || document.body).appendChild(script);
  console.log(`[AdapterAssistant] ${jsFileName} loaded and executed in page context.`);

  chrome.runtime.sendMessage({
    type: 'JS_EXECUTION_STATUS',
    success: true,
    message: `${jsFileName} 已注入页面,等待校内脚本执行结果...`,
  }).catch(() => {});
}

function collectPageContext() {
  const pageText = normalizeSpace(document.body?.innerText || '').slice(0, 2400);
  const headings = Array.from(document.querySelectorAll('h1, h2, h3'))
    .slice(0, 12)
    .map((node) => normalizeSpace(node.textContent || ''))
    .filter(Boolean);

  const forms = Array.from(document.forms)
    .slice(0, 8)
    .map((form, index) => ({
      index,
      id: form.id || '',
      name: form.getAttribute('name') || '',
      method: (form.getAttribute('method') || 'GET').toUpperCase(),
      action: form.getAttribute('action') || '',
      fieldCount: form.elements?.length || 0,
      fields: Array.from(form.elements || [])
        .slice(0, 12)
        .map((element, fieldIndex) => ({
          index: fieldIndex,
          tag: element.tagName?.toLowerCase() || '',
          type: element.getAttribute?.('type') || '',
          name: element.getAttribute?.('name') || '',
          id: element.id || '',
          placeholder: element.getAttribute?.('placeholder') || '',
          text: normalizeSpace(
            element.getAttribute?.('aria-label') ||
              element.getAttribute?.('title') ||
              element.labels?.[0]?.textContent ||
              element.textContent || ''
          ).slice(0, 80),
        })),
    }));

  const tables = Array.from(document.querySelectorAll('table'))
    .slice(0, 8)
    .map((table, index) => {
      const rows = Array.from(table.rows || []);
      const headerCells = Array.from(table.querySelectorAll('th')).map((cell) => normalizeSpace(cell.textContent || ''));
      const fallbackHeaders = rows[0]
        ? Array.from(rows[0].cells || []).map((cell) => normalizeSpace(cell.textContent || ''))
        : [];
      const previewRows = rows.slice(0, 4).map((row) =>
        Array.from(row.cells || []).map((cell) => normalizeSpace(cell.textContent || '').slice(0, 48))
      );

      return {
        index,
        id: table.id || '',
        className: table.className || '',
        rowCount: rows.length,
        columnCount: rows[0]?.cells?.length || 0,
        headers: headerCells.filter(Boolean).length ? headerCells.filter(Boolean).slice(0, 12) : fallbackHeaders.filter(Boolean).slice(0, 12),
        previewRows,
      };
    });

  const resources = (performance.getEntriesByType('resource') || [])
    .slice(-24)
    .map((entry) => ({
      name: entry.name,
      initiatorType: entry.initiatorType || '',
      duration: Math.round(entry.duration || 0),
    }));

  const links = Array.from(document.querySelectorAll('a[href]'))
    .slice(0, 12)
    .map((link) => ({
      text: normalizeSpace(link.textContent || '').slice(0, 60),
      href: link.href,
    }));

  return {
    url: location.href,
    title: document.title,
    readyState: document.readyState,
    headings,
    forms,
    tables,
    links,
    resources,
    pageText,
    capturedAt: new Date().toISOString(),
  };
}

function collectFullPageSnapshot() {
  const htmlLimit = 120000;
  const iframeLimit = 30000;
  const html = (document.documentElement?.outerHTML || '').slice(0, htmlLimit);
  const courseLikeTextBlocks = Array.from(document.querySelectorAll('div, td, li, span'))
    .map((node, index) => ({
      index,
      tag: node.tagName?.toLowerCase() || '',
      className: node.className || '',
      text: normalizeSpace(node.textContent || ''),
    }))
    .filter((item) =>
      item.text &&
      item.text.length >= 6 &&
      item.text.length <= 240 &&
      (/(?:周|星期)[一二三四五六日天]/.test(item.text) ||
        /\d+(?:-\d+)?周/.test(item.text) ||
        /第?\s*\d{1,2}\s*[-~—至]?\s*\d{0,2}\s*节/.test(item.text))
    )
    .slice(0, 24);
  const absolutePositionedNodes = Array.from(document.querySelectorAll('[style*="position:absolute"], [style*="position: absolute"]'))
    .map((node, index) => ({
      index,
      tag: node.tagName?.toLowerCase() || '',
      className: node.className || '',
      text: normalizeSpace(node.textContent || '').slice(0, 200),
    }))
    .filter((item) => item.text)
    .slice(0, 24);
  const scripts = Array.from(document.scripts || [])
    .slice(0, 12)
    .map((script, index) => ({
      index,
      src: script.src || '',
      type: script.type || '',
      inlinePreview: (script.textContent || '').slice(0, 800),
    }));
  const sameOriginIframes = Array.from(document.querySelectorAll('iframe'))
    .slice(0, 6)
    .map((iframe, index) => {
      try {
        const iframeDoc = iframe.contentDocument;
        return {
          index,
          src: iframe.src || '',
          title: iframe.title || '',
          html: (iframeDoc?.documentElement?.outerHTML || '').slice(0, iframeLimit),
          textPreview: normalizeSpace(iframeDoc?.body?.innerText || '').slice(0, 1200),
          tableCount: iframeDoc?.querySelectorAll('table')?.length || 0,
          scriptCount: iframeDoc?.scripts?.length || 0,
          absolutePositionedNodeCount: iframeDoc?.querySelectorAll?.('[style*="position:absolute"], [style*="position: absolute"]')?.length || 0,
        };
      } catch (error) {
        return {
          index,
          src: iframe.src || '',
          title: iframe.title || '',
          inaccessible: true,
        };
      }
    });

  return {
    ...collectPageContext(),
    html,
    scripts,
    sameOriginIframes,
    structureSummary: {
      tableCount: document.querySelectorAll('table').length,
      iframeCount: document.querySelectorAll('iframe').length,
      scriptCount: document.scripts.length,
      absolutePositionedNodeCount: document.querySelectorAll('[style*="position:absolute"], [style*="position: absolute"]').length,
      courseLikeTextBlocks,
      absolutePositionedNodes,
    },
  };
}

function normalizeSpace(value) {
  return String(value || '').replace(/\s+/g, ' ').trim();
}

function generatePromiseId() {
  return `${Date.now()}-${Math.random().toString(36).slice(2, 12)}`;
}

function showInlineDialog(dialogType, args, messageId) {
  return new Promise((resolve) => {
    const existingOverlay = document.getElementById('android-bridge-dialog-overlay');
    if (existingOverlay) {
      existingOverlay.remove();
    }

    const overlay = document.createElement('div');
    overlay.id = 'android-bridge-dialog-overlay';
    overlay.style.cssText = `
      position: fixed;
      inset: 0;
      background: rgba(0, 0, 0, 0.45);
      display: flex;
      align-items: center;
      justify-content: center;
      z-index: 999999;
      padding: 16px;
      box-sizing: border-box;
    `;

    const dialog = document.createElement('div');
    dialog.id = 'android-bridge-dialog-container';
    dialog.style.cssText = `
      width: min(420px, 100%);
      max-height: min(80vh, 620px);
      overflow: auto;
      background: #fff;
      border-radius: 14px;
      box-shadow: 0 20px 60px rgba(0,0,0,0.22);
      padding: 18px;
      display: flex;
      flex-direction: column;
      gap: 12px;
      color: #182033;
      font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
    `;

    let titleText = '';
    let contentText = '';
    let confirmText = '确定';
    let cancelText = '取消';
    let defaultValue = '';
    let validatorFnName = '';
    let options = [];
    let selectedOptionIndex = -1;

    if (dialogType === 'alert') {
      titleText = args?.[0] || '提示';
      contentText = args?.[1] || '';
      confirmText = args?.[2] || '确定';
    } else if (dialogType === 'prompt') {
      titleText = args?.[0] || '请输入';
      contentText = args?.[1] || '';
      defaultValue = args?.[2] || '';
      validatorFnName = args?.[3] || '';
    } else if (dialogType === 'singleselection') {
      titleText = args?.[0] || '请选择';
      try {
        options = JSON.parse(args?.[1] || '[]');
        if (!Array.isArray(options)) {
          options = [];
        }
      } catch (_) {
        options = [];
      }
      selectedOptionIndex = Number.isInteger(Number(args?.[2])) ? Number(args[2]) : -1;
    }

    const title = document.createElement('div');
    title.textContent = titleText;
    title.style.cssText = 'font-size: 18px; font-weight: 700;';

    const message = document.createElement('div');
    message.textContent = contentText;
    message.style.cssText = 'font-size: 14px; line-height: 1.5; color: #4b5a73; white-space: pre-wrap;';

    const error = document.createElement('div');
    error.style.cssText = 'display:none; color:#c62828; font-size:12px;';

    dialog.append(title, message, error);

    let input = null;
    if (dialogType === 'prompt') {
      input = document.createElement('input');
      input.type = 'text';
      input.value = defaultValue;
      input.placeholder = contentText;
      input.style.cssText = 'width:100%; padding:10px 12px; border:1px solid #d8dee8; border-radius:10px; font:inherit;';
      dialog.appendChild(input);
    }

    if (dialogType === 'singleselection') {
      const list = document.createElement('div');
      list.style.cssText = 'display:flex; flex-direction:column; gap:8px;';
      options.forEach((optionText, index) => {
        const optionButton = document.createElement('button');
        optionButton.type = 'button';
        optionButton.textContent = optionText;
        optionButton.style.cssText = buttonStyle(index === selectedOptionIndex, true);
        optionButton.addEventListener('click', () => {
          selectedOptionIndex = index;
          Array.from(list.children).forEach((child, childIndex) => {
            child.style.cssText = buttonStyle(childIndex === selectedOptionIndex, true);
          });
        });
        list.appendChild(optionButton);
      });
      dialog.appendChild(list);
    }

    const footer = document.createElement('div');
    footer.style.cssText = 'display:flex; justify-content:flex-end; gap:10px; margin-top:6px;';

    if (dialogType !== 'alert') {
      const cancelButton = document.createElement('button');
      cancelButton.type = 'button';
      cancelButton.textContent = cancelText;
      cancelButton.style.cssText = buttonStyle(false, false);
      cancelButton.addEventListener('click', () => closeDialog(null));
      footer.appendChild(cancelButton);
    }

    const confirmButton = document.createElement('button');
    confirmButton.type = 'button';
    confirmButton.textContent = confirmText;
    confirmButton.style.cssText = buttonStyle(true, false);
    confirmButton.addEventListener('click', async () => {
      let result = true;

      if (dialogType === 'prompt') {
        const inputValue = input.value;
        if (validatorFnName) {
          const validationRequestId = generatePromiseId();
          const validationPromise = new Promise((resolveValidation) => {
            pendingValidationRequests.set(validationRequestId, { resolveValidation });
          });

          window.postMessage({
            type: 'VALIDATE_PROMPT_INPUT',
            validatorFnName,
            inputValue,
            requestId: validationRequestId,
          }, window.location.origin);

          const validationError = await validationPromise.catch(() => '内部错误:验证失败');
          if (validationError) {
            error.textContent = validationError;
            error.style.display = 'block';
            input.focus();
            return;
          }
        }
        result = inputValue;
      } else if (dialogType === 'singleselection') {
        result = selectedOptionIndex >= 0 ? selectedOptionIndex : null;
      }

      closeDialog(result);
    });
    footer.appendChild(confirmButton);
    dialog.appendChild(footer);

    overlay.appendChild(dialog);
    document.body.appendChild(overlay);
    input?.focus();

    const escHandler = (event) => {
      if (event.key === 'Escape' && dialogType !== 'alert') {
        closeDialog(null);
      }
    };
    document.addEventListener('keydown', escHandler);

    function closeDialog(value) {
      chrome.runtime.sendMessage({
        type: 'INLINE_DIALOG_RESULT',
        dialogType,
        messageId,
        value,
      }).catch(() => {});

      document.removeEventListener('keydown', escHandler);
      overlay.remove();
      resolve(value);
    }
  });
}

function buttonStyle(primary, block) {
  return [
    block ? 'width:100%; text-align:left;' : '',
    'padding:10px 14px;',
    'border:none;',
    'border-radius:10px;',
    'cursor:pointer;',
    'font:inherit;',
    primary ? 'background:#2b72ff; color:#fff;' : 'background:#eef2f8; color:#182033;',
  ].join(' ');
}