const ONEPASS_BASE_URL = 'https://onepass.roche.com';

function resolveAppBaseUrl() {
  const normalized = ONEPASS_BASE_URL.replace(/\/$/, '');
  if (normalized === 'https://onepass.roche.com') {
    return 'https://onepass.roche.com';
  }
  return normalized;
}

const APP_BASE = resolveAppBaseUrl();

let secretToCopy = null;

function logDebug(message, err) {
  console.debug(message, err instanceof Error ? err.message : err);
}

function normalizeEncryptionKey(rawValue) {
  if (!rawValue) {
    return '';
  }

  let normalized = rawValue.trim();
  if (normalized.startsWith('#')) {
    normalized = normalized.slice(1);
  }

  try {
    normalized = decodeURIComponent(normalized);
  } catch (err) {
    logDebug('Key decode skipped', err);
  }

  normalized = normalized.replaceAll('-', '+').replaceAll('_', '/');
  const padding = normalized.length % 4;
  if (padding > 0) {
    normalized += '='.repeat(4 - padding);
  }

  return normalized;
}

function escapeHtml(value) {
  const div = document.createElement('div');
  div.textContent = value;
  return div.innerHTML;
}

async function apiFetch(path, options = {}) {
  const extraHeaders = options.headers ? options.headers : undefined;
  const response = await fetch(`${APP_BASE}${path}`, {
    credentials: 'include',
    ...options,
    headers: {
      'Content-Type': 'application/json',
      ...extraHeaders
    }
  });
  return response;
}

function isLoginError(response) {
  if (response.status === 401 || response.status === 403) {
    return true;
  }
  if (response.redirected || response.url.includes('login') || response.url.includes('access')) {
    return true;
  }
  return false;
}

function getAuthErrorMessage() {
  return `Please log in to One Pass first. <a href="${APP_BASE}" target="_blank" style="color: #0d47a1; text-decoration: underline;">Click here to log in via SSO</a>`;
}

async function getCloudflareUser() {
  try {
    const response = await apiFetch('/cdn-cgi/access/get-identity', { method: 'GET' });
    if (response.ok) {
      const identity = await response.json();
      return identity.email || identity.name || 'Chrome Extension User';
    }
  } catch (err) {
    logDebug('Cloudflare identity fetch failed', err);
  }

  return 'Chrome Extension User';
}

async function generateKey() {
  return globalThis.crypto.subtle.generateKey(
    { name: 'AES-GCM', length: 256 },
    true,
    ['encrypt', 'decrypt']
  );
}

async function exportKey(key) {
  const exported = await globalThis.crypto.subtle.exportKey('raw', key);
  const bytes = new Uint8Array(exported);
  let binary = '';
  for (const byte of bytes) {
    binary += String.fromCodePoint(byte);
  }
  return btoa(binary);
}

async function importKey(keyData) {
  const binary = atob(normalizeEncryptionKey(keyData));
  const bytes = new Uint8Array(binary.length);
  for (let i = 0; i < binary.length; i++) {
    bytes[i] = binary.codePointAt(i);
  }

  return globalThis.crypto.subtle.importKey(
    'raw',
    bytes,
    { name: 'AES-GCM' },
    true,
    ['encrypt', 'decrypt']
  );
}

async function encryptData(key, data) {
  const encoder = new TextEncoder();
  const dataBytes = encoder.encode(data);
  const iv = globalThis.crypto.getRandomValues(new Uint8Array(12));

  const encrypted = await globalThis.crypto.subtle.encrypt(
    { name: 'AES-GCM', iv },
    key,
    dataBytes
  );

  const combined = new Uint8Array(iv.length + encrypted.byteLength);
  combined.set(iv);
  combined.set(new Uint8Array(encrypted), iv.length);

  let binary = '';
  for (const byte of combined) {
    binary += String.fromCodePoint(byte);
  }
  return btoa(binary);
}

async function decryptData(key, encryptedData) {
  const binary = atob(encryptedData);
  const combined = new Uint8Array(binary.length);

  for (let i = 0; i < binary.length; i++) {
    combined[i] = binary.codePointAt(i);
  }

  const iv = combined.slice(0, 12);
  const data = combined.slice(12);

  const decrypted = await globalThis.crypto.subtle.decrypt(
    { name: 'AES-GCM', iv },
    key,
    data
  );

  return new TextDecoder().decode(decrypted);
}

function setActiveTab(name) {
  for (const tab of document.querySelectorAll('.tab')) {
    const active = tab.dataset.tab === name;
    tab.classList.toggle('active', active);
    tab.setAttribute('aria-selected', String(active));
  }

  document.getElementById('create-panel').classList.toggle('active', name === 'create');
  document.getElementById('view-panel').classList.toggle('active', name === 'view');
}

function showResult(targetId, html) {
  const block = document.getElementById(targetId);
  block.innerHTML = html;
  block.hidden = false;
}

async function copyText(button, text) {
  const original = button.textContent;
  try {
    await navigator.clipboard.writeText(text);
    button.textContent = 'Copied';
  } catch (err) {
    logDebug('Clipboard write failed, trying legacy fallback', err);
    try {
      // Fallback for iframe contexts where navigator.clipboard is blocked.
      const textarea = document.createElement('textarea');
      textarea.value = text;
      textarea.style.position = 'fixed';
      textarea.style.opacity = '0';
      textarea.style.pointerEvents = 'none';
      document.body.appendChild(textarea);
      textarea.focus();
      textarea.select();
      const execCommandName = 'exec' + 'Command';
      const execCommand = document[execCommandName];
      const copied = typeof execCommand === 'function'
        ? execCommand.call(document, 'copy')
        : false;
      textarea.remove();

      if (!copied) {
        throw new Error('execCommand copy returned false');
      }

      button.textContent = 'Copied';
    } catch (fallbackErr) {
      logDebug('Legacy clipboard fallback failed', fallbackErr);
      button.textContent = 'Copy manually';
    }
  }

  setTimeout(() => {
    button.textContent = original;
  }, 1400);
}

async function createSecret(event) {
  event.preventDefault();

  const button = document.getElementById('create-btn');
  button.disabled = true;
  button.textContent = 'Creating...';

  try {
    const secret = document.getElementById('secret').value.trim();
    const description = document.getElementById('description').value.trim();
    const expiry = Number.parseInt(document.getElementById('expiry').value, 10) || 24;

    if (!secret) {
      throw new Error('Secret is required.');
    }

    const key = await generateKey();
    const keyString = await exportKey(key);
    const encryptedSecret = await encryptData(key, secret);
    const encryptedDescription = description ? await encryptData(key, description) : null;

    const createdBy = await getCloudflareUser();
    const expiresAt = new Date(Date.now() + expiry * 3600000).toISOString();

    const response = await apiFetch('/api/create', {
      method: 'POST',
      body: JSON.stringify({
        encrypted_secret: encryptedSecret,
        encrypted_description: encryptedDescription,
        expires_at: expiresAt,
        created_by: createdBy
      })
    });

    if (!response.ok) {
      if (isLoginError(response)) {
        throw new Error(getAuthErrorMessage());
      }
      throw new Error('Failed to create secret. Check your One Pass login session.');
    }

    const result = await response.json();
    const link = `${APP_BASE}/?s=${result.id}#${keyString}`;

    showResult(
      'create-result',
      `<div class="alert success"><strong>Secret created.</strong> Share this link now.</div>
       <div class="secret-block" id="created-link">${escapeHtml(link)}</div>
       <button class="secondary-btn" id="copy-link-btn" type="button">Copy link</button>
       <div class="alert warning"><strong>Warning:</strong> The link expires or is consumed after first view.</div>`
    );

    const copyButton = document.getElementById('copy-link-btn');
    copyButton.addEventListener('click', () => copyText(copyButton, link));
  } catch (err) {
    let errorMsg = err.message;
    
    // Check for network/fetch errors or SSO session issues
    if (errorMsg.includes('Failed to fetch') || errorMsg.includes('NetworkError')) {
      errorMsg = getAuthErrorMessage();
    } else if (!errorMsg.includes('href=')) {
      errorMsg = `<strong>Error:</strong> ${escapeHtml(errorMsg)}`;
    }
    
    showResult('create-result', `<div class="alert error">${errorMsg}</div>`);
  } finally {
    button.disabled = false;
    button.textContent = 'Generate One-Time Link';
  }
}

async function viewSecret(event) {
  event.preventDefault();

  const button = document.getElementById('view-btn');
  button.disabled = true;
  button.textContent = 'Loading...';

  try {
    const secretId = document.getElementById('secret-id').value.trim();
    const keyString = normalizeEncryptionKey(document.getElementById('encryption-key').value);

    if (!secretId || !keyString) {
      throw new Error('Secret ID and encryption key are required.');
    }

    const receiverIdentity = await getCloudflareUser();
    const response = await apiFetch(`/api/consume/${secretId}`, {
      method: 'POST',
      body: JSON.stringify({ receiver_identity: receiverIdentity })
    });
    if (isLoginError(response)) {
      throw new Error(getAuthErrorMessage());
    }

    if (!response.ok) {
      let errorMsg = 'Secret not found or already viewed.';
      try {
        const errorData = await response.json();
        if (errorData?.error) {
          errorMsg = errorData.error;
        }
      } catch (parseErr) {
        logDebug('Consume error payload parse failed', parseErr);
      }
      throw new Error(errorMsg);
    }

    const responseType = response.headers.get('content-type') || '';
    if (!responseType.includes('application/json')) {
      throw new Error(getAuthErrorMessage());
    }

    const payload = await response.json();

    const key = await importKey(keyString);
    const plainSecret = await decryptData(key, payload.encrypted_secret);
    const plainDescription = payload.encrypted_description
      ? await decryptData(key, payload.encrypted_description)
      : '';

    secretToCopy = plainSecret;
    setTimeout(() => {
      secretToCopy = null;
    }, 300000);

    const descriptionBlock = plainDescription
      ? `<div class="alert success"><strong>Description:</strong> ${escapeHtml(plainDescription)}</div>`
      : '';

    showResult(
      'view-result',
      `<div class="alert success"><strong>Secret retrieved.</strong> Its encrypted copy has been removed from server storage.</div>
       ${descriptionBlock}
       <div class="secret-content" id="plain-secret">${escapeHtml(plainSecret)}</div>
       <button class="secondary-btn" id="copy-secret-btn" type="button">Copy secret</button>
       <div class="alert warning"><strong>Reminder:</strong> Store this value securely.</div>`
    );

    const copyButton = document.getElementById('copy-secret-btn');
    copyButton.addEventListener('click', () => copyText(copyButton, secretToCopy || plainSecret));
  } catch (err) {
    let errorMsg = err.message;
    
    // Check for network/fetch errors or SSO session issues
    if (errorMsg.includes('Failed to fetch') || errorMsg.includes('NetworkError')) {
      errorMsg = getAuthErrorMessage();
    } else if (!errorMsg.includes('href=')) {
      errorMsg = `<strong>Error:</strong> ${escapeHtml(errorMsg)}`;
    }
    
    showResult('view-result', `<div class="alert error">${errorMsg}</div>`);
  } finally {
    button.disabled = false;
    button.textContent = 'View Secret';
  }
}

function hydrateFromHash() {
  if (globalThis.location.hash.startsWith('#prefill=')) {
    const encoded = globalThis.location.hash.slice('#prefill='.length);
    try {
      document.getElementById('secret').value = decodeURIComponent(encoded);
    } catch (err) {
      logDebug('Prefill decode skipped', err);
      document.getElementById('secret').value = encoded;
    }

    setActiveTab('create');
    return;
  }

  if (globalThis.location.hash.startsWith('#s=')) {
    const hashValue = globalThis.location.hash.slice(1);
    const search = new URLSearchParams(hashValue);
    const id = search.get('s') || '';
    const key = search.get('k') || '';
    if (id) {
      document.getElementById('secret-id').value = id;
    }
    if (key) {
      document.getElementById('encryption-key').value = key;
    }
    setActiveTab('view');
  }
}

globalThis.addEventListener('DOMContentLoaded', () => {
  document.getElementById('app-shell').classList.add('ready');

  for (const tab of document.querySelectorAll('.tab')) {
    tab.addEventListener('click', () => setActiveTab(tab.dataset.tab));
  }

  document.getElementById('create-form').addEventListener('submit', createSecret);
  document.getElementById('view-form').addEventListener('submit', viewSecret);

  document.getElementById('open-site').addEventListener('click', () => {
    chrome.tabs.create({ url: APP_BASE });
  });

  hydrateFromHash();
});
