<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>N2Usenet Gateway v2.7 Nym</title>
  <link rel="icon" href="/favicon.ico" sizes="any">
  <link rel="shortcut icon" href="/favicon.ico">
  <style>
    :root {
      --background: #f9f9f9;
      --card-bg: #fff;
      --text: #333;
      --border: #ccc;
      --primary: #4caf50;
      --primary-hover: #45a049;
      --tab-bg: #eee;
      --input-bg: #fff;
      --input-readonly: #eee;
      --progress-bg: #ddd;
      --success: #28a745;
      --warning: #ffc107;
      --error: #dc3545;
    }

    .dark-theme {
      --background: #1a1a1a;
      --card-bg: #2c2c2c;
      --text: #e0e0e0;
      --border: #444;
      --primary: #5cbb60;
      --primary-hover: #4caf50;
      --tab-bg: #333;
      --input-bg: #3c3c3c;
      --input-readonly: #2a2a2a;
      --progress-bg: #444;
    }

    body {
      background: var(--background);
      color: var(--text);
      font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
      margin: 0;
      padding: 0;
      transition: background 0.3s ease;
    }

    .container {
      max-width: 800px;
      margin: auto;
      padding: 20px;
    }

    header {
      display: flex;
      justify-content: space-between;
      align-items: center;
      margin-bottom: 20px;
    }

    .theme-toggle {
      display: flex;
      align-items: center;
      gap: 8px;
    }

    .toggle {
      position: relative;
      width: 60px;
      height: 30px;
      background: #ccc;
      border-radius: 30px;
      padding: 4px;
      cursor: pointer;
      transition: 0.3s;
    }

    .toggle:before {
      content: '';
      position: absolute;
      width: 26px;
      height: 26px;
      border-radius: 50%;
      background: white;
      top: 2px;
      left: 2px;
      transition: 0.3s;
    }

    input[type="checkbox"]:checked + .toggle {
      background: #4caf50;
    }

    input[type="checkbox"]:checked + .toggle:before {
      transform: translateX(30px);
    }

    input[type="checkbox"] {
      display: none;
    }

    .notification {
      position: fixed;
      top: 20px;
      right: 20px;
      max-width: 400px;
      padding: 15px 20px;
      border-radius: 8px;
      box-shadow: 0 4px 12px rgba(0,0,0,0.3);
      z-index: 10000;
      animation: slideIn 0.3s ease;
      display: flex;
      align-items: center;
      gap: 10px;
    }

    .notification.success { background: var(--success); color: white; }
    .notification.error { background: var(--error); color: white; }
    .notification.warning { background: var(--warning); color: #333; }
    .notification.info { background: #007bff; color: white; }

    @keyframes slideIn {
      from { transform: translateX(400px); opacity: 0; }
      to { transform: translateX(0); opacity: 1; }
    }

    @keyframes pulse {
      0% { box-shadow: 0 0 0 0 rgba(156, 39, 176, 0.7); }
      50% { box-shadow: 0 0 0 15px rgba(156, 39, 176, 0); }
      100% { box-shadow: 0 0 0 0 rgba(156, 39, 176, 0); }
    }

    .notification-icon { font-size: 1.5em; }
    .notification-close { margin-left: auto; cursor: pointer; font-size: 1.2em; opacity: 0.8; }
    .notification-close:hover { opacity: 1; }

    .section-info {
      background: var(--card-bg);
      border-left: 4px solid var(--primary);
      padding: 10px 15px;
      margin-bottom: 15px;
      border-radius: 0 4px 4px 0;
      box-shadow: 0 2px 4px rgba(0,0,0,0.1);
    }

    .tabs {
      display: flex;
      flex-direction: column;
      gap: 8px;
      margin-bottom: 15px;
    }

    .tabs button {
      display: flex;
      align-items: center;
      justify-content: space-between;
      width: 100%;
      padding: 12px 15px;
      border: none;
      background: var(--tab-bg);
      color: var(--text);
      cursor: pointer;
      border-radius: 4px;
      font-weight: bold;
      transition: background 0.2s, transform 0.1s;
      position: relative;
    }

    .tabs button:hover { background: var(--primary); color: white; }
    .tabs button:active { transform: scale(0.98); }

    .tabs button.completed::after {
      content: '✓';
      position: absolute;
      right: 15px;
      background: var(--success);
      color: white;
      width: 24px;
      height: 24px;
      border-radius: 50%;
      display: flex;
      align-items: center;
      justify-content: center;
      font-size: 0.9em;
    }

    .tab-content {
      display: none !important;
      padding: 20px;
      background: var(--card-bg);
      border: 1px solid var(--border);
      border-radius: 4px;
      box-shadow: 0 2px 8px rgba(0,0,0,0.1);
      margin-bottom: 20px;
    }

    .tab-content.active {
      display: block !important;
    }

    label {
      display: block;
      margin-top: 15px;
      font-weight: bold;
      margin-bottom: 5px;
    }

    input, textarea, select {
      width: 100%;
      padding: 10px;
      margin-top: 5px;
      box-sizing: border-box;
      border: 1px solid var(--border);
      border-radius: 4px;
      background: var(--input-bg);
      color: var(--text);
      font-family: inherit;
    }

    input:focus, textarea:focus, select:focus {
      outline: none;
      border-color: var(--primary);
      box-shadow: 0 0 0 2px rgba(76, 175, 80, 0.2);
    }

    input.error, textarea.error { border-color: var(--error); }

    input[readonly], textarea[readonly] {
      background: var(--input-readonly);
      cursor: not-allowed;
      border: 2px solid #999;
    }

    input.prefilled {
      background: #e8f5e9;
      border: 2px solid var(--primary);
    }

    .dark-theme input.prefilled {
      background: #1b3d1b;
    }

    button {
      margin-top: 15px;
      padding: 12px 20px;
      background: var(--primary);
      color: white;
      border: none;
      border-radius: 4px;
      cursor: pointer;
      font-weight: bold;
      transition: background 0.2s, opacity 0.2s;
      font-family: inherit;
    }

    button:hover:not(:disabled) { background: var(--primary-hover); }
    button:disabled { opacity: 0.6; cursor: not-allowed; }

    .btn-secondary {
      background: #6c757d;
    }
    .btn-secondary:hover:not(:disabled) { background: #5a6268; }

    .progress-bar {
      width: 100%;
      background: var(--progress-bg);
      border-radius: 5px;
      overflow: hidden;
      height: 20px;
      margin-top: 10px;
    }

    .progress-bar-inner {
      height: 100%;
      width: 0;
      background: var(--primary);
      text-align: center;
      color: white;
      line-height: 20px;
      transition: width 0.3s;
      font-size: 0.85em;
    }

    .output-field {
      margin-top: 15px;
      padding: 10px;
      background: var(--input-readonly);
      border: 1px solid var(--border);
      border-radius: 4px;
      word-break: break-all;
      min-height: 30px;
      font-family: monospace;
      font-size: 0.9em;
    }

    .output-field.empty { color: #999; font-style: italic; }

    .gateway-info {
      background: var(--card-bg);
      border: 1px solid var(--border);
      padding: 15px;
      margin: 15px 0;
      border-radius: 4px;
      border-left: 4px solid #007bff;
    }

    .gateway-item {
      display: flex;
      align-items: center;
      padding: 8px 0;
      border-bottom: 1px solid var(--border);
    }

    .gateway-item:last-child { border-bottom: none; }

    .gateway-priority {
      background: #007bff;
      color: white;
      padding: 2px 8px;
      border-radius: 12px;
      font-size: 0.8em;
      margin-right: 10px;
      min-width: 70px;
      text-align: center;
    }

    .gateway-address {
      font-family: monospace;
      background: var(--input-readonly);
      padding: 4px 8px;
      border-radius: 4px;
      flex: 1;
      font-size: 0.85em;
    }

    .prefill-banner {
      background: linear-gradient(135deg, #4caf50 0%, #45a049 100%);
      color: white;
      padding: 12px 15px;
      border-radius: 4px;
      margin-bottom: 15px;
      display: flex;
      align-items: center;
      gap: 10px;
      box-shadow: 0 2px 8px rgba(76, 175, 80, 0.3);
    }

    .prefill-banner.reply {
      background: linear-gradient(135deg, #007bff 0%, #0056b3 100%);
    }

    .prefill-banner-icon { font-size: 1.5em; }
    .prefill-banner-text { flex: 1; }
    .prefill-banner-text strong { display: block; margin-bottom: 2px; }
    .prefill-banner-text small { opacity: 0.9; }

    .keypair-actions {
      display: flex;
      gap: 10px;
      flex-wrap: wrap;
      margin-top: 15px;
    }

    .keypair-actions button {
      flex: 1;
      min-width: 150px;
    }

    .identity-loaded {
      background: #d4edda;
      border: 1px solid #c3e6cb;
      padding: 10px 15px;
      border-radius: 4px;
      margin-top: 15px;
      display: flex;
      align-items: center;
      gap: 10px;
    }

    .dark-theme .identity-loaded {
      background: #1e3d1e;
      border-color: #2e5d2e;
    }

    .identity-loaded-icon { font-size: 1.5em; }
    .identity-loaded-text { flex: 1; }

    .identicon-preview {
      display: inline-block;
      vertical-align: middle;
      margin-left: 10px;
    }

    .identicon-preview img {
      width: 32px;
      height: 32px;
      image-rendering: pixelated;
      border: 1px solid var(--border);
      border-radius: 4px;
    }

    .identicon-section {
      background: var(--card-bg);
      border: 1px solid var(--border);
      border-left: 4px solid #9c27b0;
      padding: 15px;
      margin: 15px 0;
      border-radius: 0 4px 4px 0;
      text-align: center;
    }

    .identicon-section h4 {
      margin: 0 0 15px 0;
      color: #9c27b0;
    }

    .identicon-large-preview {
      margin: 15px 0;
    }

    .identicon-hash {
      font-size: 0.8em;
      color: #666;
      word-break: break-all;
      margin: 10px 0;
    }

    .identicon-hash code {
      background: var(--input-readonly);
      padding: 4px 8px;
      border-radius: 4px;
      display: inline-block;
      max-width: 100%;
      overflow-x: auto;
    }

    .identicon-actions {
      display: flex;
      gap: 10px;
      justify-content: center;
      flex-wrap: wrap;
      margin: 15px 0;
    }

    .identicon-actions button {
      margin: 0;
      padding: 8px 15px;
      font-size: 0.9em;
    }

    .identicon-tip {
      background: #f3e5f5;
      padding: 10px;
      border-radius: 4px;
      margin-top: 10px;
    }

    .dark-theme .identicon-tip {
      background: #2d1f30;
    }

    footer {
      text-align: center;
      margin-top: 40px;
      padding-top: 20px;
      border-top: 1px solid var(--border);
      font-size: 0.9em;
      color: #888;
    }

    .footer-links {
      display: flex;
      justify-content: center;
      gap: 20px;
      margin-top: 10px;
    }

    .footer-links a {
      color: var(--primary);
      text-decoration: none;
      transition: color 0.2s;
    }

    .footer-links a:hover {
      color: var(--primary-hover);
      text-decoration: underline;
    }

    @media (max-width: 600px) {
      .container { padding: 10px; }
      .tab-content { padding: 15px 10px; }
      .footer-links { flex-direction: column; gap: 10px; }
      .gateway-item { flex-direction: column; align-items: flex-start; gap: 5px; }
      .gateway-address { width: 100%; }
      .notification { right: 10px; left: 10px; max-width: none; }
      .keypair-actions { flex-direction: column; }
      .keypair-actions button { min-width: 100%; }
    }
  </style>
  <script src="/static/nacl.min.js"></script>
  <script src="/static/nacl-util.min.js"></script>
</head>
<body>
<div class="container">
  <header>
    <h1>N2Usenet Gateway v2.7 Nym</h1>
    <div class="theme-toggle">
      <span>🌞</span>
      <input type="checkbox" id="themeToggle">
      <label for="themeToggle" class="toggle"></label>
      <span>🌙</span>
    </div>
  </header>

  <div id="prefillBanner" class="prefill-banner" style="display: none;">
    <span class="prefill-banner-icon">📝</span>
    <div class="prefill-banner-text">
      <strong id="prefillTitle">New Post</strong>
      <small id="prefillDetails">Fields pre-filled from Onion Newsreader</small>
    </div>
  </div>

  <div class="tabs">
    <button id="tabBtn1" onclick="showTab('pow')">
      <span>1. Generate Hashcash Token</span>
    </button>
    <button id="tabBtn2" onclick="showTab('sign')">
      <span>2. Sign Message (Identity)</span>
    </button>
    <button id="tabBtn3" onclick="showTab('send')">
      <span>3. Send Message</span>
    </button>
  </div>

  <div id="pow" class="tab-content active">
    <h2>1. Load Identity or Start Fresh</h2>
    
    <div class="identity-loader" style="background: var(--card-bg); border: 2px dashed var(--primary); border-radius: 8px; padding: 20px; margin-bottom: 20px; text-align: center;">
      <p style="margin: 0 0 15px 0;"><strong>🔑 Have a saved identity?</strong> Load it to auto-fill all fields.</p>
      <button id="loadIdentityBtn" class="btn-primary" style="font-size: 1.1em; padding: 12px 30px;">📂 Load Identity File</button>
      <input type="file" id="identityFileInput" accept=".json" style="display:none;">
      <p style="margin: 15px 0 0 0; font-size: 0.9em; color: var(--text); opacity: 0.7;">Or fill the fields below to create a new identity.</p>
    </div>
    
    <div id="identityLoadedPow" class="identity-loaded" style="display:none; margin-bottom: 20px;">
      <span class="identity-loaded-icon">✅</span>
      <div class="identity-loaded-text">
        <strong id="loadedIdentityName">Identity Loaded</strong>
        <small id="loadedIdentityEmail">email@example.com</small>
      </div>
      <div class="identicon-preview">
        <img id="identiconPreviewPow" alt="Your identicon" style="width: 48px; height: 48px; image-rendering: pixelated; border-radius: 4px;">
      </div>
    </div>
    
    <div class="section-info">
      <p><strong>About N2Usenet:</strong> A privacy-focused standalone gateway that posts to Usenet newsgroups over Nym to the TCPReset Mail2News and NNTP infrastructure. No access logs are kept. To post you must first create, or load, a <strong>VFACE pseudonymous identity</strong>: an Ed25519 keypair whose public key deterministically generates your identicon. Same key &rarr; same identicon &rarr; same person over time.</p>
      <p><strong>What is Proof-of-Work?</strong> This step generates a hashcash token that prevents spam by requiring your computer to perform some calculations.</p>
    </div>
    
    <label>Username (your pseudonym): <input type="text" id="fromName" placeholder="YourPseudonym" autocomplete="off" autocapitalize="off" autocorrect="off" spellcheck="false" required></label>
    <label>Email (for identity hash): <input type="email" id="hcEmail" placeholder="your@email.example" autocomplete="off" autocapitalize="off" autocorrect="off" spellcheck="false" required></label>
    <label>Difficulty (bits):
      <select id="hcBits">
        <option value="16">16 bits (very fast, ~instant - recommended for hardened browsers)</option>
        <option value="20" selected>20 bits (fast, ~few seconds)</option>
        <option value="24">24 bits (medium, ~30-60 seconds)</option>
        <option value="28">28 bits (slow, ~several minutes)</option>
      </select>
    </label>
    <button id="genTokenBtn">Generate Token</button>
    <div class="progress-bar"><div id="tokenProgress" class="progress-bar-inner">Ready</div></div>
    <label>Generated Token:</label>
    <div id="tokenOutput" class="output-field empty">Token will appear here after generation</div>
  </div>

  <div id="sign" class="tab-content">
    <h2>2. Sign Your Message</h2>
    
    <div id="identiconSection" class="identicon-section" style="display:none;">
      <h4>🎨 Your Visual Identity</h4>
      <div style="display: flex; align-items: center; gap: 20px; flex-wrap: wrap;">
        <div class="identicon-large-preview">
          <img id="identiconPreviewLarge" alt="Your identicon" style="width:96px;height:96px;image-rendering:pixelated;border:2px solid var(--border);border-radius:8px;">
        </div>
        <div style="flex: 1; min-width: 200px;">
          <p style="margin: 0 0 5px 0;"><strong id="identityUsername">Username</strong></p>
          <p style="margin: 0 0 10px 0; font-size: 0.9em; color: var(--text); opacity: 0.8;" id="identityEmail">email@example.com</p>
          <p class="identicon-hash" style="margin: 0;">Hash: <code id="identityHashDisplay"></code></p>
        </div>
      </div>
      <p style="margin-top: 15px; text-align: center; font-size: 0.95em;">Identity material stays only in browser memory for this tab and is wiped after a successful send.</p>
      <p style="margin-top: 15px; text-align: center; font-size: 0.9em;">
        <a href="https://identicons.virebent.art" target="_blank" rel="noopener noreferrer" style="color: #9c27b0; text-decoration: none;">🔐 VFACE Verifier - Verify an identity</a>
      </p>
    </div>
    
    <div class="section-info">
      <p><strong>What is this?</strong> Your keypair is generated and your message is signed <strong>locally in your browser</strong> with the self-hosted TweetNaCl (<code>nacl</code>) library, and your Ed25519 secret key never leaves your device. Only the public identity (username, email, public key) is sent, to render the identicon. The signature proves you authored this post.</p>
      <p><strong>VFACE / Face Header:</strong> Your identicon is produced by the original <code>identicons-cli</code> engine, the same backend as <code>identicons.virebent.art</code>, so it is fully deterministic: the same key always yields the same identicon. It is embedded as a folded <code>Face:</code> header (RFC&nbsp;4021/2822) alongside <code>X-Ed25519-Pub</code> and <code>X-Ed25519-Sig</code>, visible in newsreaders like Newsgrouper and re-verifiable by any reader from your public key.</p>
    </div>

    <label>Email (from PoW):</label>
    <input type="text" id="readonlyEmailSign" readonly>
    
    <label>Message to Sign:</label>
    <textarea id="messageToSign" rows="6" placeholder="Write your message here..." autocomplete="off" autocapitalize="off" autocorrect="off" spellcheck="false" required></textarea>
    
    <div class="keypair-actions">
      <button id="genKeyBtn">🔑 Generate New Keypair</button>
    </div>
    <input type="file" id="keyFileInput" accept=".json" style="display:none;">
    
    <button id="signMsgBtn" disabled>✍️ Sign Message</button>
    
    <label>Public Key:</label>
    <div id="pubKeyOutput" class="output-field empty">Public key will appear here</div>
    <label>Signature:</label>
    <div id="signatureOutput" class="output-field empty">Signature will appear here</div>
  </div>

  <div id="send" class="tab-content">
    <h2>Send Message</h2>
    <div class="section-info">
      <p><strong>What is this?</strong> This final step sends your signed message to Usenet via Nym, Mail2News, and the <code>news.tcpreset.net</code> NNTP service.</p>
      <div class="gateway-info">
        <h4>🔐 Nym to TCPReset Posting Path</h4>
        <p style="margin-bottom: 15px; font-size: 0.95em;">Your message is submitted over HTTPS, then relayed from this server through Nym to the Mail2News gateway and finally into <code>news.tcpreset.net</code> NNTP:</p>
        
        <div class="gateway-item">
          <span class="gateway-priority">Step 1</span>
          <div style="flex: 1;">
            <strong>Nym SMTP transport</strong>
            <p style="font-size: 0.85em; margin: 5px 0 0 0; color: #666;">Nym SOCKS5/requester transport to the TCPReset Mail2News SMTP gateway.</p>
          </div>
        </div>
        <details style="margin-top: 8px; font-size: 0.8em;">
          <summary style="cursor: pointer; color: #007bff;">Show relay nodes</summary>
          <ul style="margin: 8px 0; padding-left: 20px; font-family: monospace; color: #555;">
            <li><strong>SMTP:</strong> mail2news.tcpreset.net:587 STARTTLS via Nym SOCKS5</li>
          </ul>
        </details>
        
        <div class="gateway-item">
          <span class="gateway-priority">Step 2</span>
          <div style="flex: 1;">
            <strong>Mail2News Gateway</strong>
            <div class="gateway-address" style="margin-top: 5px;">mail2news@mail2news.tcpreset.net</div>
            <p style="font-size: 0.85em; margin: 5px 0 0 0; color: #666;">Converts the signed email payload into a Usenet post for the TCPReset news service.</p>
          </div>
        </div>
        
        <div class="gateway-item">
          <span class="gateway-priority">Step 3</span>
          <div style="flex: 1;">
            <strong>TCPReset NNTP</strong>
            <div class="gateway-address" style="margin-top: 5px;">nntp://news.tcpreset.net</div>
            <p style="font-size: 0.85em; margin: 5px 0 0 0; color: #666;">Final posting target for the standalone N2Usenet path.</p>
          </div>
        </div>
        
        <p style="margin-top: 15px; padding: 10px; background: rgba(0,123,255,0.1); border-radius: 4px; font-size: 0.9em;">
          <strong>🔒 Privacy Guarantee:</strong> The browser-to-server hop is HTTPS. The server-to-Mail2News hop uses Nym plus SMTP TLS. Mail2News then posts into <code>news.tcpreset.net</code> NNTP.
        </p>
      </div>
    </div>

    <label>Email used for PoW:</label>
    <input type="text" id="readonlyEmailSend" readonly>
    <form id="sendForm" method="POST" action="/submit" autocomplete="off">
      <input type="hidden" name="csrf_token" value="{{.CSRFToken}}">
      <label>From (Name):</label>
      <input type="text" id="readonlyFromName" readonly>
      <input type="hidden" name="from" id="fromFull">
      <label>Newsgroups (max 3, comma separated):
        <input type="text" name="newsgroups" id="newsgroups" autocomplete="off" autocapitalize="off" autocorrect="off" spellcheck="false" required placeholder="e.g. alt.privacy, comp.security">
      </label>
      <label>Subject: <input type="text" name="subject" id="subject" autocomplete="off" autocapitalize="off" autocorrect="off" spellcheck="false" required placeholder="Message Subject"></label>
      <label>References (optional): <input type="text" name="references" id="references" autocomplete="off" autocapitalize="off" autocorrect="off" spellcheck="false" placeholder="Message-ID of post you're replying to"></label>
      <label>X-Hashcash Token: <input type="text" name="xhashcash" id="hcToken" required readonly></label>
      <label>Message:</label>
      <textarea name="message" id="messageContent" rows="8" autocomplete="off" autocapitalize="off" autocorrect="off" spellcheck="false" required placeholder="Your message will appear here after signing..."></textarea>
      <input type="hidden" name="x-ed25519-pub" id="x-ed25519-pub">
      <input type="hidden" name="x-ed25519-sig" id="x-ed25519-sig">
      <button type="submit" id="sendBtn">Send Message</button>
    </form>
  </div>

  <footer>
    <div>N2Usenet Gateway v2.7.0 © 2025 - Privacy-focused Usenet posting via Nym</div>
    <div class="footer-links">
      <a href="https://yamn.virebent.art">Home</a>
      <a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;%69%6E%66%6F%40%76%69%72%65%62%65%6E%74%2E%61%72%74">Contact</a>
      <a href="https://github.com/gabrix73/m2usenet-go">Code</a>
    </div>
  </footer>
</div>

<script>
// ============================================================================
// GLOBAL FUNCTIONS - MUST BE DEFINED FIRST
// ============================================================================

function showTab(id) {
  document.querySelectorAll('.tab-content').forEach(el => el.classList.remove('active'));
  document.getElementById(id).classList.add('active');
}

function showNotification(message, type, duration) {
  type = type || 'info';
  duration = duration === undefined ? 5000 : duration;
  const icons = { success: '✓', error: '✗', warning: '⚠', info: 'ℹ' };
  const notification = document.createElement('div');
  notification.className = `notification ${type}`;
  notification.innerHTML = `
    <span class="notification-icon">${icons[type] || icons.info}</span>
    <span class="notification-message">${message}</span>
    <span class="notification-close" onclick="this.parentElement.remove()">×</span>
  `;
  document.body.appendChild(notification);
  if (duration > 0) {
    setTimeout(() => { if (notification.parentElement) notification.remove(); }, duration);
  }
}

// ============================================================================
// STATE MANAGEMENT
// ============================================================================

const appState = {
  step1Complete: false,
  step2Complete: false,
  step3Complete: false,
  prefillMode: null
};

function updateTabIndicators() {
  document.getElementById('tabBtn1').classList.toggle('completed', appState.step1Complete);
  document.getElementById('tabBtn2').classList.toggle('completed', appState.step2Complete);
  document.getElementById('tabBtn3').classList.toggle('completed', appState.step3Complete);
}

let keyPair = null;
let workersSupported = true;

function setOutputField(id, value, emptyText) {
  const el = document.getElementById(id);
  if (!el) return;
  if (value) {
    el.innerText = value;
    el.classList.remove('empty');
    return;
  }
  el.innerText = emptyText;
  el.classList.add('empty');
}

function resetEphemeralState(messageID) {
  if (keyPair) {
    if (keyPair.secretKey && typeof keyPair.secretKey.fill === 'function') keyPair.secretKey.fill(0);
    if (keyPair.publicKey && typeof keyPair.publicKey.fill === 'function') keyPair.publicKey.fill(0);
  }
  keyPair = null;
  currentIdenticonData = null;

  appState.step1Complete = false;
  appState.step2Complete = false;
  appState.step3Complete = false;
  updateTabIndicators();

  [
    'fromName', 'hcEmail', 'readonlyEmailSign', 'readonlyEmailSend',
    'readonlyFromName', 'fromFull', 'newsgroups', 'subject', 'references',
    'hcToken', 'messageToSign', 'messageContent', 'x-ed25519-pub',
    'x-ed25519-sig'
  ].forEach((id) => {
    const el = document.getElementById(id);
    if (el) el.value = '';
  });

  ['identityFileInput', 'keyFileInput'].forEach((id) => {
    const el = document.getElementById(id);
    if (el) el.value = '';
  });

  document.querySelectorAll('input, textarea').forEach((el) => {
    el.classList.remove('error', 'prefilled');
  });

  const hcBits = document.getElementById('hcBits');
  if (hcBits) hcBits.value = '20';

  setOutputField('tokenOutput', '', 'Token will appear here after generation');
  setOutputField('pubKeyOutput', '', 'Public key will appear here');
  setOutputField('signatureOutput', '', 'Signature will appear here');

  const tokenProgress = document.getElementById('tokenProgress');
  if (tokenProgress) {
    tokenProgress.style.width = '0';
    tokenProgress.textContent = 'Ready';
  }

  const identityLoaded = document.getElementById('identityLoadedPow');
  if (identityLoaded) identityLoaded.style.display = 'none';
  const identiconSection = document.getElementById('identiconSection');
  if (identiconSection) identiconSection.style.display = 'none';
  const prefillBanner = document.getElementById('prefillBanner');
  if (prefillBanner) {
    prefillBanner.style.display = 'none';
    prefillBanner.classList.remove('reply');
  }

  ['identiconPreviewPow', 'identiconPreviewLarge'].forEach((id) => {
    const img = document.getElementById(id);
    if (img) img.removeAttribute('src');
  });
  const identityHash = document.getElementById('identityHashDisplay');
  if (identityHash) identityHash.textContent = '';
  const loadedName = document.getElementById('loadedIdentityName');
  if (loadedName) loadedName.textContent = 'Identity Loaded';
  const loadedEmail = document.getElementById('loadedIdentityEmail');
  if (loadedEmail) loadedEmail.textContent = 'Identity kept only in memory';
  const identityUsername = document.getElementById('identityUsername');
  if (identityUsername) identityUsername.textContent = 'Username';
  const identityEmail = document.getElementById('identityEmail');
  if (identityEmail) identityEmail.textContent = 'email@example.com';

  const genKeyBtn = document.getElementById('genKeyBtn');
  if (genKeyBtn) {
    genKeyBtn.disabled = false;
    genKeyBtn.textContent = '🔑 Generate New Keypair';
  }
  const signBtn = document.getElementById('signMsgBtn');
  if (signBtn) signBtn.disabled = true;
  const sendBtn = document.getElementById('sendBtn');
  if (sendBtn) {
    sendBtn.disabled = false;
    sendBtn.textContent = 'Send Message';
    sendBtn.style.opacity = '';
    sendBtn.style.cursor = '';
  }
  const progressDiv = document.getElementById('sending-progress');
  if (progressDiv) progressDiv.remove();

  if (window.history && window.history.replaceState) {
    window.history.replaceState({}, document.title, window.location.pathname);
  }

  showTab('pow');

  if (messageID) {
    showNotification(`✓ Message sent. Message-ID: ${messageID}. Identity and form data cleared from memory.`, 'success', 12000);
  }
}

try {
  if (typeof Worker === 'undefined') {
    workersSupported = false;
  }
} catch (e) {
  workersSupported = false;
}

// ============================================================================
// THEME TOGGLE
// ============================================================================

document.getElementById('themeToggle').addEventListener('change', function() {
  document.body.classList.toggle('dark-theme', this.checked);
});

// ============================================================================
// IDENTICON GENERATION (client-side)
// ============================================================================

let currentIdenticonData = null;

async function generateIdenticon(username, email, pubkeyBase64) {
  // Generate the identicon with the ORIGINAL identicons-cli engine (server-side),
  // the same backend used by identicons.virebent.art (Ch1ffr3punk algorithm).
  // Only PUBLIC data leaves the browser (username|email|ed25519-pubkey).
  const body = new URLSearchParams({ username: username, email: email, pubkey: pubkeyBase64 });
  const resp = await fetch('identicon.php', {
    method: 'POST',
    headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
    body: body.toString()
  });
  if (!resp.ok) throw new Error('identicon engine error ' + resp.status);
  const r = await resp.json();
  if (!r.face48 || !r.preview) throw new Error('identicon engine returned no data');

  currentIdenticonData = {
    dataUrl: r.preview,        // 256x256 PNG dataurl (display/download)
    hash: r.hash,             // sha256(username|email|pubkey)
    face48: r.face48,         // raw base64 PNG (48x48) -> Face: header
    faceHeader: r.faceHeader, // folded "Face: ..." header (RFC 2822)
    username: username,
    email: email,
    pubkey: pubkeyBase64,
    claim: JSON.stringify({
      version: 2,
      type: 'n2usenet-identity',
      username: username,
      email: email,
      pubkey: pubkeyBase64,
      identityHash: r.hash,
      created: new Date().toISOString(),
      algorithm: 'identicons-cli sha256(username|email|pubkey) [VFACE]'
    }, null, 2)
  };
  return r.preview;
}

async function updateIdenticonPreview() {
  if (!keyPair) return;
  
  const pubB64 = nacl.util.encodeBase64(keyPair.publicKey);
  const username = document.getElementById('fromName').value || 'Anonymous';
  const email = document.getElementById('hcEmail').value || 'anonymous@n2usenet.local';
  
  try {
    const identiconUrl = await generateIdenticon(username, email, pubB64);
    
    document.getElementById('identiconPreviewPow').src = identiconUrl;
    document.getElementById('identiconPreviewLarge').src = identiconUrl;
    document.getElementById('identityHashDisplay').textContent = currentIdenticonData.hash;
    document.getElementById('identityUsername').textContent = username;
    document.getElementById('identityEmail').textContent = email;
    document.getElementById('identiconSection').style.display = 'block';
    
  } catch (e) {
    console.error('Identicon generation failed:', e);
  }
}

// ============================================================================
// INITIALIZATION
// ============================================================================

document.addEventListener('DOMContentLoaded', function() {
  if (typeof nacl === 'undefined') {
    showNotification('Cryptography library failed to load. Please refresh the page.', 'error', 0);
    return;
  }

  if (typeof nacl.util === 'undefined') {
    nacl.util = {
      decodeUTF8: function(str) { return new TextEncoder().encode(str); },
      encodeUTF8: function(arr) { return new TextDecoder().decode(arr); },
      encodeBase64: function(arr) {
        return btoa(Array.from(new Uint8Array(arr)).map(byte => String.fromCharCode(byte)).join(''));
      },
      decodeBase64: function(b64) {
        const bin = atob(b64);
        const arr = new Uint8Array(bin.length);
        for (let i = 0; i < bin.length; i++) arr[i] = bin.charCodeAt(i);
        return arr;
      }
    };
  }

  showTab('pow');
  showNotification('N2Usenet Gateway v2.7.0 ready. No identity or message data is persisted.', 'success', 4000);
});

// ============================================================================
// SHA-1 IMPLEMENTATION
// ============================================================================

function sha1(str) {
  function rotate_left(n, s) { return (n << s) | (n >>> (32 - s)); }
  function cvt_hex(val) {
    let str = '';
    for (let i = 7; i >= 0; i--) {
      const v = (val >>> (i * 4)) & 0x0f;
      str += v.toString(16);
    }
    return str;
  }
  function utf8Encode(str) { return unescape(encodeURIComponent(str)); }

  let blockstart, i, j;
  const W = new Array(80);
  let H0 = 0x67452301, H1 = 0xEFCDAB89, H2 = 0x98BADCFE, H3 = 0x10325476, H4 = 0xC3D2E1F0;
  let A, B, C, D, E, temp;

  str = utf8Encode(str);
  const str_len = str.length;
  const word_array = [];
  
  for (i = 0; i < str_len - 3; i += 4) {
    j = str.charCodeAt(i) << 24 | str.charCodeAt(i + 1) << 16 | str.charCodeAt(i + 2) << 8 | str.charCodeAt(i + 3);
    word_array.push(j);
  }

  switch (str_len % 4) {
    case 0: i = 0x080000000; break;
    case 1: i = str.charCodeAt(str_len - 1) << 24 | 0x0800000; break;
    case 2: i = str.charCodeAt(str_len - 2) << 24 | str.charCodeAt(str_len - 1) << 16 | 0x08000; break;
    case 3: i = str.charCodeAt(str_len - 3) << 24 | str.charCodeAt(str_len - 2) << 16 | str.charCodeAt(str_len - 1) << 8 | 0x80; break;
  }

  word_array.push(i);
  while ((word_array.length % 16) != 14) word_array.push(0);
  word_array.push(str_len >>> 29);
  word_array.push((str_len << 3) & 0x0ffffffff);

  for (blockstart = 0; blockstart < word_array.length; blockstart += 16) {
    for (i = 0; i < 16; i++) W[i] = word_array[blockstart + i];
    for (i = 16; i <= 79; i++) W[i] = rotate_left(W[i - 3] ^ W[i - 8] ^ W[i - 14] ^ W[i - 16], 1);

    A = H0; B = H1; C = H2; D = H3; E = H4;

    for (i = 0; i <= 19; i++) {
      temp = (rotate_left(A, 5) + ((B & C) | (~B & D)) + E + W[i] + 0x5A827999) & 0x0ffffffff;
      E = D; D = C; C = rotate_left(B, 30); B = A; A = temp;
    }
    for (i = 20; i <= 39; i++) {
      temp = (rotate_left(A, 5) + (B ^ C ^ D) + E + W[i] + 0x6ED9EBA1) & 0x0ffffffff;
      E = D; D = C; C = rotate_left(B, 30); B = A; A = temp;
    }
    for (i = 40; i <= 59; i++) {
      temp = (rotate_left(A, 5) + ((B & C) | (B & D) | (C & D)) + E + W[i] + 0x8F1BBCDC) & 0x0ffffffff;
      E = D; D = C; C = rotate_left(B, 30); B = A; A = temp;
    }
    for (i = 60; i <= 79; i++) {
      temp = (rotate_left(A, 5) + (B ^ C ^ D) + E + W[i] + 0xCA62C1D6) & 0x0ffffffff;
      E = D; D = C; C = rotate_left(B, 30); B = A; A = temp;
    }

    H0 = (H0 + A) & 0x0ffffffff;
    H1 = (H1 + B) & 0x0ffffffff;
    H2 = (H2 + C) & 0x0ffffffff;
    H3 = (H3 + D) & 0x0ffffffff;
    H4 = (H4 + E) & 0x0ffffffff;
  }

  return cvt_hex(H0) + cvt_hex(H1) + cvt_hex(H2) + cvt_hex(H3) + cvt_hex(H4);
}

function mineSingleThread(prefix, targetZeros, progressCallback, foundCallback) {
  const target = '0'.repeat(targetZeros);
  let nonce = 0, checked = 0;
  const batchSize = 100;

  function mineNextBatch() {
    const endNonce = nonce + batchSize;
    while (nonce < endNonce) {
      const token = prefix + nonce;
      const hash = sha1(token);
      checked++;
      if (hash.startsWith(target)) {
        foundCallback(nonce, checked);
        return;
      }
      nonce++;
    }
    progressCallback(checked);
    setTimeout(mineNextBatch, 0);
  }
  mineNextBatch();
}

// ============================================================================
// STEP 1: HASHCASH TOKEN GENERATION
// ============================================================================

document.getElementById('genTokenBtn').onclick = () => {
  const email = document.getElementById('hcEmail').value.trim();
  const bits = parseInt(document.getElementById('hcBits').value);

  if (!email) {
    showNotification('⚠ Please enter your email address first!', 'warning');
    document.getElementById('hcEmail').classList.add('error');
    document.getElementById('hcEmail').focus();
    return;
  }

  const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
  if (!emailRegex.test(email)) {
    showNotification('⚠ Please enter a valid email address!', 'warning');
    document.getElementById('hcEmail').classList.add('error');
    document.getElementById('hcEmail').focus();
    return;
  }

  document.getElementById('hcEmail').classList.remove('error');
  showNotification(`🔨 Starting token generation (${bits} bits)...`, 'info');

  const btn = document.getElementById('genTokenBtn');
  btn.disabled = true;
  btn.textContent = 'Mining Token...';

  const now = new Date();
  const timestamp = now.getUTCFullYear().toString().slice(2) +
                    ("0"+(now.getUTCMonth()+1)).slice(-2) +
                    ("0"+now.getUTCDate()).slice(-2) +
                    ("0"+now.getUTCHours()).slice(-2) +
                    ("0"+now.getUTCMinutes()).slice(-2) +
                    ("0"+now.getUTCSeconds()).slice(-2);
  const ext = "";
  const rand = Math.floor(Math.random()*1e6);
  const prefix = `1:${bits}:${timestamp}:${email}:${ext}:${rand}:`;
  const zeros = bits/4;

  const progBar = document.getElementById('tokenProgress');
  progBar.style.width = '0%';
  progBar.innerText = 'Mining...';

  let totalChecked = 0;
  let startTime = Date.now();

  function updateProgress(checked) {
    totalChecked += checked;
    const elapsed = (Date.now() - startTime) / 1000;
    const hashRate = Math.round(totalChecked / elapsed);
    progBar.style.width = Math.min(95, (totalChecked / 10000)) + '%';
    progBar.innerText = `${totalChecked} hashes (${hashRate}/s)`;
  }

  function onFound(nonce, totalHashes) {
    const token = prefix + nonce;
    const outputField = document.getElementById('tokenOutput');
    outputField.innerText = token;
    outputField.classList.remove('empty');
    document.getElementById('hcToken').value = token;

    const fromName = document.getElementById('fromName').value || 'Anonymous';
    document.getElementById('fromFull').value = `${fromName} <${email}>`;
    document.getElementById('readonlyFromName').value = fromName;
    document.getElementById('readonlyEmailSign').value = email;
    document.getElementById('readonlyEmailSend').value = email;

    btn.disabled = false;
    btn.textContent = 'Generate Token';
    progBar.style.width = '100%';
    progBar.innerText = `Complete! (${totalHashes} hashes)`;

    appState.step1Complete = true;
    updateTabIndicators();

    const elapsed = ((Date.now() - startTime) / 1000).toFixed(1);
    showNotification(`✓ Token generated in ${elapsed}s!`, 'success', 8000);

    setTimeout(() => showTab('sign'), 2000);
  }

  if (workersSupported) {
    try {
      const cores = navigator.hardwareConcurrency || 2;
      let found = false;
      let coreChecked = Array(cores).fill(0);
      const workers = [];

      function updateCombinedProgress() {
        const sum = coreChecked.reduce((a,b)=>a+b,0);
        updateProgress(sum - totalChecked);
      }

      for (let i = 0; i < cores; i++) {
        try {
          const w = new Worker('/static/powWorker.js');
          w.postMessage({ prefix, targetZeros: zeros, startNonce: i, step: cores });

          w.onmessage = e => {
            if (found) return;
            if (e.data.type === 'found') {
              found = true;
              workers.forEach(x => x.terminate());
              onFound(e.data.nonce, e.data.checked);
            }
            if (e.data.type === 'progress') {
              coreChecked[i] = e.data.checked;
              updateCombinedProgress();
            }
          };

          w.onerror = (err) => {
            if (i === 0) {
              workers.forEach(x => x.terminate());
              mineSingleThread(prefix, zeros, updateProgress, onFound);
            }
          };

          workers.push(w);
        } catch (err) {
          if (i === 0) {
            mineSingleThread(prefix, zeros, updateProgress, onFound);
            return;
          }
        }
      }

    } catch (err) {
      mineSingleThread(prefix, zeros, updateProgress, onFound);
    }
  } else {
    mineSingleThread(prefix, zeros, updateProgress, onFound);
  }
};

// ============================================================================
// STEP 2: ED25519 SIGNATURE + KEYPAIR MANAGEMENT
// ============================================================================

document.getElementById('genKeyBtn').onclick = async function() {
  try {
    showNotification('🔐 Generating Ed25519 key pair...', 'info');
    keyPair = nacl.sign.keyPair();

    const pubB64 = nacl.util.encodeBase64(keyPair.publicKey);

    const pubOutput = document.getElementById('pubKeyOutput');
    pubOutput.innerText = pubB64;
    pubOutput.classList.remove('empty');
    document.getElementById('x-ed25519-pub').value = pubB64;
    document.getElementById('signMsgBtn').disabled = false;

    const username = document.getElementById('fromName').value || 'Anonymous';
    const email = document.getElementById('hcEmail').value || '';
    document.getElementById('identityLoadedPow').style.display = 'flex';
    document.getElementById('loadedIdentityName').textContent = username;
    document.getElementById('loadedIdentityEmail').textContent = email || 'Identity active only in memory';
    
    await updateIdenticonPreview();
    showNotification('✓ Identity generated in memory. Now write and sign your message.', 'success', 6000);
  } catch (error) {
    showNotification('✗ Error: ' + error.message, 'error');
  }
};

document.getElementById('loadIdentityBtn').onclick = function() {
  document.getElementById('identityFileInput').click();
};

document.getElementById('identityFileInput').onchange = async function(e) {
  const file = e.target.files[0];
  if (!file) return;

  try {
    const text = await file.text();
    const data = JSON.parse(text);

    if (!data.publicKey || !data.secretKey) {
      throw new Error('Invalid identity file format');
    }

    const pubKey = nacl.util.decodeBase64(data.publicKey);
    const secKey = nacl.util.decodeBase64(data.secretKey);

    if (pubKey.length !== 32 || secKey.length !== 64) {
      throw new Error('Invalid key lengths');
    }

    keyPair = { publicKey: pubKey, secretKey: secKey };

    const pubB64 = data.publicKey;
    const pubOutput = document.getElementById('pubKeyOutput');
    pubOutput.innerText = pubB64;
    pubOutput.classList.remove('empty');
    document.getElementById('x-ed25519-pub').value = pubB64;
    document.getElementById('signMsgBtn').disabled = false;

    if (data.username) {
      document.getElementById('fromName').value = data.username;
      document.getElementById('readonlyFromName').value = data.username;
    }
    if (data.email) {
      document.getElementById('hcEmail').value = data.email;
      const fromName = document.getElementById('fromName').value || 'Anonymous';
      document.getElementById('fromFull').value = `${fromName} <${data.email}>`;
      document.getElementById('readonlyEmailSign').value = data.email;
      document.getElementById('readonlyEmailSend').value = data.email;
    }

    const username = data.username || 'Anonymous';
    const email = data.email || '';
    document.getElementById('identityLoadedPow').style.display = 'flex';
    document.getElementById('loadedIdentityName').textContent = username;
    document.getElementById('loadedIdentityEmail').textContent = email;
    
    await updateIdenticonPreview();
    
    if (currentIdenticonData && currentIdenticonData.dataUrl) {
      document.getElementById('identiconPreviewPow').src = currentIdenticonData.dataUrl;
    }

    document.getElementById('genKeyBtn').textContent = '🔑 Replace Keypair';
    showNotification('✓ Identity loaded into memory only. Now generate PoW token.', 'success', 6000);
  } catch (error) {
    showNotification('✗ Failed to load identity: ' + error.message, 'error');
  }

  e.target.value = '';
};

// Usenet line-wrap convention (RFC 1855 Netiquette Guidelines): wrap plain-text
// body lines at ~72 columns for compatibility with old-style newsreaders.
// Must run BEFORE signing, not after, so the Ed25519 signature covers the
// exact bytes that end up posted to Usenet.
function wrapUsenetText(text, width) {
  width = width || 72;
  return text.split('\n').map(function(line) {
    if (line.length === 0 || line.startsWith('>')) return line;
    const words = line.split(' ');
    const wrapped = [];
    let current = '';
    for (const word of words) {
      if (current === '') {
        current = word;
      } else if ((current + ' ' + word).length <= width) {
        current += ' ' + word;
      } else {
        wrapped.push(current);
        current = word;
      }
    }
    wrapped.push(current);
    return wrapped.join('\n');
  }).join('\n');
}

document.getElementById('signMsgBtn').onclick = function() {
  try {
    if (!keyPair) {
      showNotification('⚠ Please generate or load a key pair first!', 'warning');
      return;
    }

    const msg = wrapUsenetText(document.getElementById('messageToSign').value.trim());
    if (!msg) {
      showNotification('⚠ Please write a message!', 'warning');
      document.getElementById('messageToSign').classList.add('error');
      document.getElementById('messageToSign').focus();
      return;
    }

    if (msg.length < 10) {
      showNotification('⚠ Message too short (min 10 characters)', 'warning');
      return;
    }

    document.getElementById('messageToSign').classList.remove('error');
    showNotification('✍ Signing message...', 'info');

    const msgBytes = nacl.util.decodeUTF8(msg);
    const sig = nacl.sign.detached(msgBytes, keyPair.secretKey);
    const sigB64 = nacl.util.encodeBase64(sig);

    const sigOutput = document.getElementById('signatureOutput');
    sigOutput.innerText = sigB64;
    sigOutput.classList.remove('empty');
    document.getElementById('x-ed25519-sig').value = sigB64;

    document.getElementById('messageContent').value = msg + "\n\n--- Digital Signature ---\n" + sigB64;

    appState.step2Complete = true;
    updateTabIndicators();
    showNotification('✓ Message signed with your in-memory identity.', 'success', 8000);
    setTimeout(() => showTab('send'), 1200);
  } catch (error) {
    showNotification('✗ Error: ' + error.message, 'error');
  }
};

document.getElementById('fromName').addEventListener('input', function() {
  const email = document.getElementById('hcEmail').value;
  document.getElementById('readonlyFromName').value = this.value;
  if (email) {
    document.getElementById('fromFull').value = `${this.value} <${email}>`;
  }
  if (keyPair) {
    updateIdenticonPreview();
  }
});

// ============================================================================
// STEP 3: SEND FORM
// ============================================================================

document.getElementById('sendForm').addEventListener('submit', async function(e) {
  e.preventDefault();

  const requiredFields = [
    {id: 'fromFull', name: 'From'},
    {id: 'newsgroups', name: 'Newsgroups'},
    {id: 'subject', name: 'Subject'},
    {id: 'hcToken', name: 'Hashcash Token'},
    {id: 'messageContent', name: 'Message'},
    {id: 'x-ed25519-pub', name: 'Public Key'},
    {id: 'x-ed25519-sig', name: 'Signature'}
  ];

  const missing = [];
  requiredFields.forEach(field => {
    const el = document.getElementById(field.id);
    if (!el.value.trim()) {
      missing.push(field.name);
      el.classList.add('error');
    } else {
      el.classList.remove('error');
    }
  });

  if (missing.length > 0) {
    showNotification(`⚠ Missing: ${missing.join(', ')}`, 'warning', 8000);
    return;
  }

  const messageLen = document.getElementById('messageContent').value.length;
  if (messageLen < 10) {
    showNotification('⚠ Message too short', 'warning');
    return;
  }

  const newsgroups = document.getElementById('newsgroups').value.split(',').map(g => g.trim()).filter(g => g);
  if (newsgroups.length === 0) {
    showNotification('⚠ Enter at least one newsgroup!', 'warning');
    return;
  }

  if (newsgroups.length > 3) {
    showNotification('⚠ Max 3 newsgroups!', 'warning');
    return;
  }

  const confirmMsg = `Send message?\n\nNewsgroups: ${newsgroups.join(', ')}\nSubject: ${document.getElementById('subject').value}\nLength: ${messageLen} chars\n\nDelivery via Nym may take up to 120 seconds.`;

  if (!confirm(confirmMsg)) {
    return;
  }

  showNotification('📤 Sending message...', 'info', 0);
  const sendBtn = document.getElementById('sendBtn');
  sendBtn.disabled = true;
  sendBtn.textContent = 'Sending...';
  sendBtn.style.opacity = '0.6';
  sendBtn.style.cursor = 'not-allowed';

  const progressDiv = document.createElement('div');
  progressDiv.id = 'sending-progress';
  progressDiv.style.cssText = 'margin-top: 10px; padding: 10px; background: #fff3cd; border-left: 4px solid #ffc107; color: #856404;';
  progressDiv.innerHTML = '<strong>⏳ Sending message...</strong><br>This may take up to 120 seconds via Nym. Please wait.';
  sendBtn.parentNode.insertBefore(progressDiv, sendBtn.nextSibling);

  try {
    const resp = await fetch('/submit', {
      method: 'POST',
      headers: {
        'Accept': 'application/json',
        'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8'
      },
      body: new URLSearchParams(new FormData(this)).toString(),
      credentials: 'same-origin',
      cache: 'no-store'
    });
    let data = {};
    try {
      data = await resp.json();
    } catch (err) {}
    if (!resp.ok) {
      throw new Error(data.error || 'Delivery failed.');
    }
    appState.step3Complete = true;
    updateTabIndicators();
    resetEphemeralState(data.messageId || '');
  } catch (error) {
    if (progressDiv.parentNode) progressDiv.remove();
    sendBtn.disabled = false;
    sendBtn.textContent = 'Send Message';
    sendBtn.style.opacity = '';
    sendBtn.style.cursor = '';
    showNotification('✗ ' + error.message, 'error', 10000);
  }
});

// ============================================================================
// ONION-NEWSREADER INTEGRATION
// ============================================================================

(function() {
  function decode(s) {
    if (!s) return '';
    try {
      return decodeURIComponent(s.replace(/\+/g, ' '));
    } catch(e) {
      return s;
    }
  }

  function fillField(id, value, highlight) {
    highlight = highlight !== false;
    const field = document.getElementById(id);
    if (field && value) {
      field.value = value;
      if (highlight) field.classList.add('prefilled');
      return true;
    }
    return false;
  }

  function showPrefillBanner(isReply, details) {
    const banner = document.getElementById('prefillBanner');
    const title = document.getElementById('prefillTitle');
    const detailsEl = document.getElementById('prefillDetails');
    
    if (banner) {
      banner.style.display = 'flex';
      if (isReply) {
        banner.classList.add('reply');
        title.textContent = '💬 Reply Mode';
      } else {
        title.textContent = '📝 New Post';
      }
      detailsEl.textContent = details;
    }
  }

  let prefillData = null;
  let prefillSource = null;
  const params = new URLSearchParams(window.location.search);
  const action = params.get('action');
  
  if (action === 'new' || action === 'reply' || params.has('newsgroups')) {
    prefillData = {
      newsgroups: decode(params.get('newsgroups') || ''),
      subject: decode(params.get('subject') || ''),
      references: decode(params.get('references') || ''),
      body: decode(params.get('body') || '')
    };
    prefillSource = 'URL';
  }

  if (prefillData) {
    let filledFields = [];
    
    if (prefillData.newsgroups) {
      fillField('newsgroups', prefillData.newsgroups);
      filledFields.push('Newsgroups');
    }
    
    if (prefillData.subject) {
      fillField('subject', prefillData.subject);
      filledFields.push('Subject');
    }
    
    if (prefillData.references) {
      fillField('references', prefillData.references);
      filledFields.push('References');
    }
    
    if (prefillData.body) {
      fillField('messageToSign', prefillData.body);
      filledFields.push('Quoted message');
    }

    const isReply = !!(prefillData.references || 
                       (prefillData.subject && prefillData.subject.toLowerCase().startsWith('re:')));

    if (filledFields.length > 0) {
      const details = `Pre-filled: ${filledFields.join(', ')} (from ${prefillSource})`;
      showPrefillBanner(isReply, details);
      
      if (isReply) {
        showNotification(`💬 Reply mode: ${prefillData.newsgroups}`, 'info', 5000);
      } else {
        showNotification(`📝 New post to: ${prefillData.newsgroups}`, 'success', 5000);
      }
    }

    setTimeout(() => showTab('pow'), 300);
  }
})();
</script>

</body>
</html>
