// auxbg.js — Service Worker
// Boundary holder for AUX:
// - identifies eligible AI/local tabs
// - injects auxDetect.js
// - tracks active tab/surface
// - bridges clicked detected items from page context to sidepanel/system
// - owns extension context menus

const MENU_ROOT = 'aux-root';
const MENU_SCAN = 'aux-scan-selection';
const MENU_DROP_IN = 'aux-drop-in-full-file';

let pendingDetectedItems = [];

let activeTabModel = {
  provider: 'IDLE',
  surfaceType: 'UNKNOWN',
  surfaceName: '',
  contractAware: false
};

chrome.sidePanel
  .setPanelBehavior({ openPanelOnActionClick: true })
  .catch(error => console.error('[AUX BG] Sidepanel configuration failed:', error));

// ─────────────────────────────────────────────────────────────
// Context menus
// ─────────────────────────────────────────────────────────────

function upsertMenu(item) {
  chrome.contextMenus.create(item, () => {
    const err = chrome.runtime.lastError;

    if (!err) return;

    if (String(err.message || '').includes('duplicate id')) {
      const { id, ...update } = item;
      chrome.contextMenus.update(id, update, () => void chrome.runtime.lastError);
    }
  });
}

function installContextMenus() {
  chrome.contextMenus.remove('aux-rewrite-file-selection', () => void chrome.runtime.lastError);

  upsertMenu({
    id: MENU_ROOT,
    title: 'AUX',
    contexts: ['all']
  });

  upsertMenu({
    id: MENU_SCAN,
    parentId: MENU_ROOT,
    title: 'Scan Selection',
    contexts: ['all']
  });

  upsertMenu({
    id: MENU_DROP_IN,
    parentId: MENU_ROOT,
    title: 'Drop-In Full File',
    contexts: ['all']
  });
}

chrome.runtime.onInstalled.addListener(installContextMenus);
chrome.runtime.onStartup.addListener(installContextMenus);
chrome.action.onClicked.addListener(installContextMenus);

// ─────────────────────────────────────────────────────────────
// AI / local page detection
// ─────────────────────────────────────────────────────────────

function isAuxChatTargetUrl(url = '') {
  const value = String(url || '').toLowerCase();

  return value.startsWith('https://chatgpt.com/')
    || value.startsWith('https://chat.openai.com/')
    || value.startsWith('https://gemini.google.com/')
    || value.startsWith('https://claude.ai/')
    || value.startsWith('https://copilot.microsoft.com/')
    || value.startsWith('https://aistudio.google.com/');
}
function classifySurface(url = '', title = '') {
  const cleanUrl = String(url || '').toLowerCase();
  const cleanTitle = String(title || '').toLowerCase();

  let host = '';

  try {
    host = url ? new URL(url).hostname.toLowerCase() : '';
  } catch {
    host = '';
  }

  let provider = 'UNKNOWN';
  let surfaceName = 'Unknown AI';
  let contractAware = false;

  if (host.includes('chatgpt.com') || host.includes('chat.openai.com')) {
    const surfaceKey = `${cleanUrl} ${cleanTitle}`.replace(/[^a-z0-9]/g, '');
    const isNodaramaGo = surfaceKey.includes('nodaramago') || surfaceKey.includes('nodarama');

    provider = isNodaramaGo ? 'NODARAMA_GO' : 'CHATGPT';
    surfaceName = isNodaramaGo ? 'Nodarama Go' : 'ChatGPT';
    contractAware = isNodaramaGo;
  } else if (host.includes('gemini.google.com')) {
    provider = 'GEMINI';
    surfaceName = 'Gemini';
  } else if (host.includes('claude.ai')) {
    provider = 'CLAUDE';
    surfaceName = 'Claude';
  } else if (host.includes('copilot.microsoft.com')) {
    provider = 'COPILOT';
    surfaceName = 'Copilot';
  } else if (host.includes('aistudio.google.com')) {
    provider = 'STUDIO_LM';
    surfaceName = 'Studio LM';
  } else if (host.includes('localhost') || host.includes('127.0.0.1')) {
    provider = 'LOCAL';
    surfaceName = 'Local AI';
    contractAware = true;
  }

  return {
    provider,
    surfaceType: provider === 'LOCAL'
      ? 'LOCAL'
      : provider === 'NODARAMA_GO'
        ? 'CUSTOM_GPT'
        : 'GENERAL',
    surfaceName,
    contractAware
  };
}

async function ensureContentScriptHooks(tabId) {
  if (typeof tabId !== 'number') return false;

  const tab = await chrome.tabs.get(tabId).catch(() => null);
  if (!isAuxChatTargetUrl(tab?.url)) return false;

  try {
    const pong = await chrome.tabs.sendMessage(tabId, { type: 'AUX_PING_CONTENT' });
    if (pong?.ok) return true;
  } catch {}

  try {
    await chrome.scripting.executeScript({
      target: { tabId },
      files: ['auxDetect.js']
    });

    return true;
  } catch {
    return false;
  }
}
function broadcastStateProfile() {
  chrome.runtime
    .sendMessage({
      type: 'AUX_STATE_PROFILE_MUTATED',
      activeTabModel
    })
    .catch(() => {});
}

async function tabBelongsToFocusedAuxWindow(tab = {}) {
  const windowId = Number(tab?.windowId);
  if (!Number.isFinite(windowId)) return false;

  const focused = await chrome.windows.getLastFocused({ populate: false }).catch(() => null);
  return Boolean(focused?.id === windowId && focused?.focused !== false);
}

async function isEligibleAuxScanTab(tab = {}) {
  if (!tab?.id || !isAuxChatTargetUrl(tab.url)) return false;
  return await tabBelongsToFocusedAuxWindow(tab);
}

chrome.tabs.onUpdated?.addListener(async (tabId, changeInfo, tab) => {
  if (changeInfo?.status !== 'complete') return;

  const currentTab = tab?.id ? tab : await chrome.tabs.get(tabId).catch(() => null);
  if (!await isEligibleAuxScanTab(currentTab)) return;

  Object.assign(activeTabModel, classifySurface(currentTab.url, currentTab.title));

  ensureContentScriptHooks(tabId)
    .then(() => broadcastStateProfile())
    .catch(() => false);
});
chrome.tabs.onActivated?.addListener(async info => {
  const tab = await chrome.tabs.get(info.tabId).catch(() => null);

  if (!await isEligibleAuxScanTab(tab)) return;

  Object.assign(activeTabModel, classifySurface(tab.url, tab.title));

  ensureContentScriptHooks(tab.id)
    .then(() => broadcastStateProfile())
    .catch(() => false);
});

// ─────────────────────────────────────────────────────────────
// Runtime bridge
// ─────────────────────────────────────────────────────────────

chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
  if (message?.type === 'AUX_DETECTED_ITEM') {
    bridgeDetectedItem(message, sender, sendResponse);
    return false;
  }

  if (message?.type === 'AUX_DETECTED_ITEMS') {
    bridgeDetectedItems(message, sender, sendResponse);
    return false;
  }

  if (message?.type === 'AUX_SET_CONTRACT_STATE') {
    activeTabModel.contractAware = Boolean(message.aware);
    broadcastStateProfile();
    sendResponse({ ok: true });
    return false;
  }

  if (message?.type === 'AUX_REGISTER_SURFACE') {
    activeTabModel.provider = message.provider || activeTabModel.provider;
    activeTabModel.surfaceType = message.surfaceType || activeTabModel.surfaceType;
    activeTabModel.surfaceName = message.surfaceName || activeTabModel.surfaceName;
    activeTabModel.contractAware = Boolean(message.contractAware);

    broadcastStateProfile();

    sendResponse({ ok: true });
    return false;
  }

  if (message?.type === 'AUX_REQUEST_STATE_PROFILE') {
    resolveStateProfile(sender, sendResponse);
    return true;
  }

  return false;
});

function queuePendingDetectedItems(items = []) {
  const list = Array.isArray(items) ? items : [items];
  list.filter(Boolean).forEach(item => pendingDetectedItems.push(item));
}

function flushPendingDetectedItems() {
  const items = pendingDetectedItems.slice();
  pendingDetectedItems.length = 0;
  return items;
}

function motionCommandForButton(button = '', classification = '') {
  const clean = String(button || '').trim().toLowerCase();
  const kind = String(classification || '').trim().toUpperCase();

  if (clean === 'codeaux') return 'codetoaux';
  if (clean === 'jsonaux') return 'jsontoaux';
  if (clean === 'jsonvrbm') return 'jsontovrbm';
  if (clean === 'inqaux') return 'inqtoaux';
  if (clean === 'inqvrbm') return 'inqtovrbm';
  if (clean === 'inqdirect') return 'inqautoreply';

  if (clean === 'aux' && kind === 'CODE') return 'codetoaux';
  if (clean === 'aux' && kind === 'JSON') return 'jsontoaux';
  if (clean === 'vrbm' && kind === 'JSON') return 'jsontovrbm';
  if (clean === 'aux' && kind === 'INQUIRY') return 'inqtoaux';
  if (clean === 'vrbm' && kind === 'INQUIRY') return 'inqtovrbm';
  if ((clean === 'auto' || clean === 'direct') && kind === 'INQUIRY') return 'inqautoreply';

  return '';
}
function routedClickedItem(item = {}) {
  const button = String(item.button || item.action || '').trim();
  const classification = String(item.classification || item.stream || item.belt || '').trim().toUpperCase();
  const command = motionCommandForButton(button, classification);

  if (!button || !command) {
    return {
      ...item,
      routeError: 'unknown_button',
      classification,
      button,
      command: '',
      action: ''
    };
  }

  return {
    ...item,
    classification,
    stream: classification || item.stream,
    button,
    command,
    action: command,
    sourceButton: button
  };
}
function bridgeDetectedItem(message, sender, sendResponse) {
  if (!sender.tab?.id) {
    sendResponse({
      ok: false,
      msg: 'Chat command did not come from a tab'
    });

    return;
  }

  if (sender.tab?.windowId) {
    chrome.sidePanel.open({ windowId: sender.tab.windowId }).catch(() => {});
  }

  const item = routedClickedItem(message.item);

  chrome.runtime.sendMessage({
    type: 'AUX_DETECTED_ITEM_TO_SYSTEM',
    item,
    sourceTab: tabSummary(sender.tab)
  }, () => {
    if (chrome.runtime.lastError) {
      queuePendingDetectedItems(item);
    }
  });

  sendResponse({ ok: true, relayed: true });
}
function bridgeDetectedItems(message, sender, sendResponse) {
  if (!sender.tab?.id) {
    sendResponse({
      ok: false,
      msg: 'Chat commands did not come from a tab'
    });

    return;
  }

  if (sender.tab?.windowId) {
    chrome.sidePanel.open({ windowId: sender.tab.windowId }).catch(() => {});
  }

  const items = (Array.isArray(message.items) ? message.items : []).map(item => routedClickedItem(item));

  chrome.runtime.sendMessage({
    type: 'AUX_DETECTED_ITEMS_TO_SYSTEM',
    items,
    sourceTab: tabSummary(sender.tab)
  }, () => {
    if (chrome.runtime.lastError) {
      queuePendingDetectedItems(items);
    }
  });

  sendResponse({ ok: true, relayed: true });
}
async function resolveStateProfile(sender, sendResponse) {
  const currentTab = sender.tab
    || await chrome.tabs.query({ active: true, currentWindow: true })
      .then(tabs => tabs[0])
      .catch(() => null)
    || {};

  if (currentTab.url && isAuxChatTargetUrl(currentTab.url)) {
    Object.assign(activeTabModel, classifySurface(currentTab.url, currentTab.title));
  }

  sendResponse({
    ...activeTabModel,
    pendingDetectedItems: flushPendingDetectedItems()
  });
}
function tabSummary(tab = {}) {
  return {
    id: tab.id,
    url: tab.url || '',
    title: tab.title || '',
    windowId: tab.windowId
  };
}

// ─────────────────────────────────────────────────────────────
// Context menu actions
// ─────────────────────────────────────────────────────────────

chrome.contextMenus.onClicked.addListener(async (info, activeTab) => {
  if (info.menuItemId !== MENU_SCAN && info.menuItemId !== MENU_DROP_IN) return;

  if (activeTab?.windowId) {
    chrome.sidePanel.open({ windowId: activeTab.windowId }).catch(() => {});
  }

  const text = String(info.selectionText || '').trim();
  if (!text) return;

  if (info.menuItemId === MENU_SCAN) {
    await ensureContentScriptHooks(activeTab.id);

    chrome.tabs
      .sendMessage(activeTab.id, {
        type: 'AUX_MANUAL_ELEMENT_SCRAPE',
        text
      })
      .catch(() => {});

    return;
  }

  if (info.menuItemId === MENU_DROP_IN) {
    chrome.runtime
      .sendMessage({
        type: 'AUX_CONTEXT_DROP_IN_FULL_FILE',
        payload: {
          text,
          url: activeTab?.url || '',
          at: Date.now()
        }
      })
      .catch(() => {});
  }
});