const ext = globalThis.browser || globalThis.chrome;
const csrfCache = new Map();

function arrayBufferToBase64(buffer) {
  const bytes = new Uint8Array(buffer);
  const chunkSize = 0x8000;
  let binary = '';
  for (let offset = 0; offset < bytes.length; offset += chunkSize) binary += String.fromCharCode(...bytes.subarray(offset, offset + chunkSize));
  return btoa(binary);
}

async function getCsrf(serverUrl) {
  if (csrfCache.has(serverUrl)) return csrfCache.get(serverUrl);
  const response = await fetch(`${serverUrl}/api/me`, { credentials: 'include', cache: 'no-store' });
  if (!response.ok) return '';
  const data = await response.json();
  const token = data.csrf || '';
  csrfCache.set(serverUrl, token);
  return token;
}

ext.runtime.onMessage.addListener((msg, _sender, sendResponse) => {
  if (msg.type === 'api') {
    (async () => {
      try {
        const { serverUrl, path, method = 'GET', body } = msg;
        const opts = { method, headers: {}, credentials: 'include', cache: 'no-store' };
        if (body !== undefined) { opts.headers['Content-Type'] = 'application/json'; opts.body = JSON.stringify(body); }
        if (!['GET', 'HEAD', 'OPTIONS'].includes(method)) {
          const csrf = await getCsrf(serverUrl);
          if (csrf) opts.headers['X-CSRF-Token'] = csrf;
        }
        let response = await fetch(`${serverUrl}${path}`, opts);
        if (response.status === 403 && !['GET', 'HEAD', 'OPTIONS'].includes(method)) {
          csrfCache.delete(serverUrl);
          const csrf = await getCsrf(serverUrl);
          if (csrf) opts.headers['X-CSRF-Token'] = csrf;
          response = await fetch(`${serverUrl}${path}`, opts);
        }
        const contentType = response.headers.get('content-type') || '';
        const data = contentType.includes('application/json') ? await response.json() : { error: await response.text() };
        sendResponse({ ok: response.ok, status: response.status, data });
      } catch (error) { sendResponse({ ok: false, status: 0, error: error.message }); }
    })();
    return true;
  }
  if (msg.type === 'fetch-image') {
    (async () => {
      try {
        const response = await fetch(msg.url, { cache: 'no-store', credentials: 'include' });
        if (!response.ok) throw new Error(`HTTP ${response.status}`);
        const blob = await response.blob();
        if (!blob.type.startsWith('image/')) throw new Error('Antwort ist kein Bild');
        const buffer = await blob.arrayBuffer();
        sendResponse({ ok: true, dataUrl: `data:${blob.type};base64,${arrayBufferToBase64(buffer)}`, mime: blob.type, size: blob.size });
      } catch (error) { sendResponse({ ok: false, error: error.message }); }
    })();
    return true;
  }
});
