import browser from 'webextension-polyfill';
import { loadSettings, saveSettings } from './storage.js';

function byId<T extends HTMLElement>(id: string): T {
  const element = document.getElementById(id);
  if (!element) throw new Error(`Missing options element #${id}.`);
  return element as T;
}

const CHROMIUM_LOOPBACK_PROBE = 'http://127.0.0.1:8764/healthz';
const CHATGPT_ORIGIN = 'https://chatgpt.com/*';

async function renderChatGptPermission(): Promise<void> {
  const granted = await browser.permissions.contains({ origins: [CHATGPT_ORIGIN] });
  byId<HTMLElement>('chatgpt-access-state').textContent = granted
    ? 'Allowed. Managed ChatGPT tabs can receive orchestrator commands.'
    : 'Required. LibreWolf may not grant Manifest V3 site access automatically for a sideloaded extension.';
  byId<HTMLButtonElement>('grant-chatgpt').hidden = granted;
}

async function grantChatGptPermission(): Promise<void> {
  const result = byId<HTMLElement>('grant-chatgpt-result');
  result.textContent = 'Waiting for site-access permission…';
  const granted = await browser.permissions.request({ origins: [CHATGPT_ORIGIN] });
  result.textContent = granted ? 'ChatGPT site access granted.' : 'ChatGPT site access was not granted.';
  await renderChatGptPermission();
}

async function grantChromiumLoopback(): Promise<void> {
  const result = byId<HTMLElement>('grant-loopback-result');
  result.textContent = 'Waiting for Chromium local-network permission…';
  try {
    const response = await fetch(CHROMIUM_LOOPBACK_PROBE, { cache: 'no-store' });
    if (!response.ok) throw new Error(`Loopback health probe returned HTTP ${response.status}.`);
    result.textContent = 'Local executor access granted. The executor connection will retry automatically.';
    const current = await loadSettings();
    await saveSettings({
      endpoint: current.endpoint,
      token: current.token,
      maxConcurrentLaunches: current.maxConcurrentLaunches,
      maxManagedWorkers: current.maxManagedWorkers,
      overlayVisible: current.overlayVisible,
    });
  } catch (error) {
    result.textContent = error instanceof Error
      ? `Local executor access was not granted: ${error.message}`
      : 'Local executor access was not granted.';
  }
}

async function render(): Promise<void> {
  const settings = await loadSettings();
  await renderChatGptPermission();
  byId<HTMLInputElement>('endpoint').value = settings.endpoint;
  const tokenInput = byId<HTMLInputElement>('token');
  tokenInput.value = '';
  tokenInput.placeholder = settings.token ? 'Configured — leave blank to keep' : 'Enter executor token';
  tokenInput.required = !settings.token;
  byId<HTMLInputElement>('max-concurrent-launches').value = String(settings.maxConcurrentLaunches);
  byId<HTMLInputElement>('max-managed-workers').value = String(settings.maxManagedWorkers);
  byId<HTMLInputElement>('overlay-visible').checked = settings.overlayVisible;
  byId<HTMLElement>('executor-id').textContent = settings.executorId;
  byId<HTMLElement>('chromium-local-access').hidden = __TARGET_BROWSER__ !== 'chromium';
}

byId<HTMLFormElement>('settings-form').addEventListener('submit', (event) => {
  event.preventDefault();
  void (async () => {
    const endpoint = byId<HTMLInputElement>('endpoint').value.trim();
    const enteredToken = byId<HTMLInputElement>('token').value.trim();
    const current = await loadSettings();
    const token = enteredToken || current.token;
    const maxConcurrentLaunches = Number.parseInt(byId<HTMLInputElement>('max-concurrent-launches').value, 10);
    const maxManagedWorkers = Number.parseInt(byId<HTMLInputElement>('max-managed-workers').value, 10);
    const overlayVisible = byId<HTMLInputElement>('overlay-visible').checked;
    const url = new URL(endpoint);
    if (!['ws:', 'wss:'].includes(url.protocol)) throw new Error('Endpoint must use ws:// or wss://.');
    if (!['127.0.0.1', 'localhost', '::1'].includes(url.hostname)) throw new Error('v0 only permits a loopback executor endpoint.');
    if (token.length < 16) throw new Error('Executor token must be at least 16 characters.');
    if (!Number.isInteger(maxConcurrentLaunches) || maxConcurrentLaunches < 1 || maxConcurrentLaunches > 16) throw new Error('Concurrent launches must be between 1 and 16.');
    if (!Number.isInteger(maxManagedWorkers) || maxManagedWorkers < 1 || maxManagedWorkers > 64) throw new Error('Managed conversations must be between 1 and 64.');
    if (maxConcurrentLaunches > maxManagedWorkers) throw new Error('Concurrent launches cannot exceed managed conversations.');
    await saveSettings({ endpoint, token, maxConcurrentLaunches, maxManagedWorkers, overlayVisible });
    byId<HTMLElement>('save-result').textContent = 'Saved. The executor connection will restart automatically.';
    await render();
  })().catch((error) => {
    byId<HTMLElement>('save-result').textContent = error instanceof Error ? error.message : 'Settings could not be saved.';
  });
});

byId<HTMLButtonElement>('grant-chatgpt').addEventListener('click', () => { void grantChatGptPermission(); });
byId<HTMLButtonElement>('grant-loopback').addEventListener('click', () => { void grantChromiumLoopback(); });

browser.storage.onChanged.addListener(() => { void render(); });
void render();
