import * as vscode from 'vscode';
import * as fs from 'fs';
import * as path from 'path';
import * as http from 'http';
import * as os from 'os';
import * as crypto from 'crypto';
import { handleClipboardAndOpen } from './shared';

const store: { panel: vscode.WebviewPanel | null } = { panel: null };

interface ActiveShare {
  server: http.Server;
  port: number;
  token: string;
  fileBuf: Buffer;
  filename: string;
}

export function openSendToMobile(context: vscode.ExtensionContext) {
  if (store.panel) {
    store.panel.reveal();
    return;
  }

  const panel = vscode.window.createWebviewPanel(
    'hplToolbox.sendToMobile',
    'Send To Mobile',
    vscode.ViewColumn.Active,
    {
      enableScripts: true,
      retainContextWhenHidden: true,
      localResourceRoots: [vscode.Uri.joinPath(context.extensionUri, 'media')],
    }
  );
  store.panel = panel;

  let active: ActiveShare | null = null;

  const stopActive = () => {
    if (active) {
      try { active.server.close(); } catch { /* noop */ }
      active = null;
    }
  };

  panel.onDidDispose(() => {
    stopActive();
    store.panel = null;
  });

  const qrUri = panel.webview.asWebviewUri(
    vscode.Uri.joinPath(context.extensionUri, 'media', 'qrcode.min.js')
  );
  panel.webview.html = getHtml(qrUri.toString());

  panel.webview.onDidReceiveMessage(async (msg) => {
    try {
      if (handleClipboardAndOpen(msg)) return;

      if (msg.type === 'pickFile') {
        const picked = await vscode.window.showOpenDialog({
          canSelectMany: false,
          filters: { HTML: ['html', 'htm'] },
          openLabel: 'Select',
          defaultUri: getPickerDefaultUri(),
        });
        if (picked && picked[0]) {
          const fp = picked[0].fsPath;
          panel.webview.postMessage({
            type: 'fileSelected',
            path: fp,
            name: path.basename(fp),
          });
        }
        return;
      }

      if (msg.type === 'startShare') {
        stopActive();
        const filePath: string = msg.path;
        if (!filePath || !fs.existsSync(filePath)) {
          panel.webview.postMessage({ type: 'error', message: 'File missing.' });
          return;
        }
        const fileBuf = fs.readFileSync(filePath);
        const filename = path.basename(filePath);
        const token = crypto.randomBytes(6).toString('base64url');

        const cfg = vscode.workspace.getConfiguration('hplToolbox.sendToMobile');
        const configuredPort = cfg.get<number>('port') ?? 0;

        const share: ActiveShare = {
          server: http.createServer(),
          port: 0,
          token,
          fileBuf,
          filename,
        };
        share.server.on('request', (req, res) => handleRequest(req, res, share));
        share.server.on('error', (err) => {
          panel.webview.postMessage({ type: 'error', message: 'Server error: ' + err.message });
          stopActive();
        });

        share.server.listen(configuredPort, '0.0.0.0', () => {
          const addr = share.server.address();
          if (!addr || typeof addr === 'string') {
            panel.webview.postMessage({ type: 'error', message: 'Failed to bind server.' });
            return;
          }
          share.port = addr.port;
          active = share;

          const ips = getLanIps();
          if (ips.length === 0) {
            panel.webview.postMessage({
              type: 'error',
              message: 'No non-loopback IPv4 interface found. Are you on a network?',
            });
            stopActive();
            return;
          }
          const urls = ips.map((ip) => ({
            ip: ip.address,
            iface: ip.iface,
            url: `http://${ip.address}:${share.port}/s/${token}/`,
          }));
          panel.webview.postMessage({ type: 'sharing', urls, filename });
        });
        return;
      }

      if (msg.type === 'stopShare') {
        stopActive();
        panel.webview.postMessage({ type: 'stopped' });
        return;
      }
    } catch (err: any) {
      panel.webview.postMessage({ type: 'error', message: err?.message || String(err) });
    }
  });
}

function handleRequest(req: http.IncomingMessage, res: http.ServerResponse, share: ActiveShare) {
  if (req.method !== 'GET' || !req.url) {
    res.statusCode = 404;
    res.end();
    return;
  }
  const prefix = `/s/${share.token}`;
  if (!req.url.startsWith(prefix)) {
    res.statusCode = 404;
    res.end();
    return;
  }
  const rest = req.url.slice(prefix.length).replace(/\?.*$/, '');

  if (rest === '' || rest === '/') {
    const body = chooserPage(share.filename);
    res.writeHead(200, {
      'Content-Type': 'text/html; charset=utf-8',
      'Cache-Control': 'no-store',
    });
    res.end(body);
    return;
  }

  if (rest === '/view') {
    res.writeHead(200, {
      'Content-Type': 'text/html; charset=utf-8',
      'Cache-Control': 'no-store',
    });
    res.end(share.fileBuf);
    return;
  }

  if (rest === '/file') {
    const safeName = share.filename.replace(/[^A-Za-z0-9._-]/g, '_');
    res.writeHead(200, {
      'Content-Type': 'application/octet-stream',
      'Content-Disposition': `attachment; filename="${safeName}"`,
      'Content-Length': String(share.fileBuf.length),
      'Cache-Control': 'no-store',
    });
    res.end(share.fileBuf);
    return;
  }

  res.statusCode = 404;
  res.end();
}

function chooserPage(filename: string): string {
  const escName = filename.replace(/[&<>"]/g, (c) =>
    ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;' }[c] as string)
  );
  return `<!DOCTYPE html>
<html><head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Send To Mobile</title>
<style>
  body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
         margin: 0; padding: 24px; background: #111; color: #eee; }
  h1 { font-size: 18px; font-weight: 500; margin: 0 0 4px; opacity: 0.85; }
  .file { font-size: 13px; opacity: 0.6; margin-bottom: 28px; word-break: break-all; }
  a.btn { display: block; padding: 18px; margin-bottom: 14px; border-radius: 10px;
          font-size: 17px; font-weight: 500; text-align: center; text-decoration: none; }
  a.view { background: #2d7dff; color: white; }
  a.dl { background: #2a2a2a; color: #eee; border: 1px solid #3a3a3a; }
</style></head>
<body>
  <h1>HPL Toolbox</h1>
  <div class="file">${escName}</div>
  <a class="btn view" href="view">View in browser</a>
  <a class="btn dl" href="file" download="${escName}">Download .html</a>
</body></html>`;
}

interface LanIp { address: string; iface: string; }

function getLanIps(): LanIp[] {
  const out: LanIp[] = [];
  const ifaces = os.networkInterfaces();
  for (const [name, list] of Object.entries(ifaces)) {
    if (!list) continue;
    for (const info of list) {
      if (info.family === 'IPv4' && !info.internal) {
        out.push({ address: info.address, iface: name });
      }
    }
  }
  return out;
}

function getPickerDefaultUri(): vscode.Uri | undefined {
  const folders = vscode.workspace.workspaceFolders;
  if (!folders || folders.length === 0) return undefined;
  const root = folders[0].uri.fsPath;
  const dist = path.join(root, 'dist');
  if (fs.existsSync(dist) && fs.statSync(dist).isDirectory()) {
    return vscode.Uri.file(dist);
  }
  return vscode.Uri.file(root);
}

function getHtml(qrScriptUri: string): string {
  return `<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<style>
  body { font-family: var(--vscode-font-family); color: var(--vscode-foreground); padding: 16px; }
  h2 { margin-top: 0; }
  .row { margin-bottom: 14px; }
  .file-cell { display: flex; align-items: center; gap: 8px; }
  .file-name { opacity: 0.85; font-size: 12px; word-break: break-all; }
  button {
    background: var(--vscode-button-background); color: var(--vscode-button-foreground);
    border: none; padding: 6px 12px; border-radius: 2px; cursor: pointer;
  }
  button:hover { background: var(--vscode-button-hoverBackground); }
  button.secondary {
    background: var(--vscode-button-secondaryBackground);
    color: var(--vscode-button-secondaryForeground);
  }
  button.secondary:hover { background: var(--vscode-button-secondaryHoverBackground); }
  button:disabled { opacity: 0.5; cursor: not-allowed; }
  .iface-list { display: flex; flex-direction: column; gap: 4px; margin-top: 6px; }
  .iface-list label { font-size: 12px; cursor: pointer; }
  .iface-list .meta { opacity: 0.6; margin-left: 6px; }
  #qr { margin-top: 14px; background: white; padding: 12px; display: inline-block; border-radius: 4px; }
  #qr svg, #qr img { display: block; }
  .url {
    margin-top: 10px; padding: 8px;
    background: var(--vscode-textBlockQuote-background);
    border-left: 3px solid var(--vscode-textBlockQuote-border);
    font-family: var(--vscode-editor-font-family, monospace); font-size: 12px; word-break: break-all;
  }
  .url-actions { margin-top: 6px; display: flex; gap: 6px; }
  #status { margin-top: 12px; min-height: 18px; }
  .err { color: var(--vscode-errorForeground); white-space: pre-wrap; }
  .ok { color: var(--vscode-testing-iconPassed, var(--vscode-foreground)); }
  .hint { font-size: 12px; opacity: 0.7; margin-top: 8px; }
</style>
<script src="${qrScriptUri}"></script>
</head>
<body>
<h2>Send To Mobile</h2>
<p style="opacity:0.8;font-size:12px;margin-top:0;">
  Pick an HTML file, then start sharing. Scan the QR with a phone on the same WiFi.
  The phone gets a choice of <strong>View</strong> or <strong>Download</strong>.
</p>

<div class="row">
  <div class="file-cell">
    <button id="pick" class="secondary">Choose...</button>
    <span class="file-name" id="fileName">(no file)</span>
  </div>
  <input type="hidden" id="filePath" />
</div>

<div class="row">
  <button id="start">Start sharing</button>
  <button id="stop" class="secondary" disabled>Stop</button>
</div>

<div id="ifaceWrap" class="row" style="display:none;">
  <div style="font-size:12px;opacity:0.8;">Multiple network interfaces found. Pick the one your phone can reach:</div>
  <div class="iface-list" id="ifaceList"></div>
</div>

<div id="shareInfo" style="display:none;">
  <div id="qr"></div>
  <div class="url" id="urlText"></div>
  <div class="url-actions">
    <button id="copyUrl" class="secondary">Copy URL</button>
    <button id="openUrl" class="secondary">Open in browser</button>
  </div>
  <div class="hint">
    First run on Windows may show a firewall prompt — allow access for "Private networks".
    Sharing stops automatically when this panel is closed.
  </div>
</div>

<div id="status"></div>

<script>
  const vscode = acquireVsCodeApi();
  const pickBtn = document.getElementById('pick');
  const startBtn = document.getElementById('start');
  const stopBtn = document.getElementById('stop');
  const fileNameEl = document.getElementById('fileName');
  const filePathEl = document.getElementById('filePath');
  const statusEl = document.getElementById('status');
  const shareInfo = document.getElementById('shareInfo');
  const ifaceWrap = document.getElementById('ifaceWrap');
  const ifaceList = document.getElementById('ifaceList');
  const qrEl = document.getElementById('qr');
  const urlTextEl = document.getElementById('urlText');

  let currentUrls = [];
  let selectedIdx = 0;

  pickBtn.addEventListener('click', () => vscode.postMessage({ type: 'pickFile' }));

  startBtn.addEventListener('click', () => {
    statusEl.innerHTML = '';
    const path = filePathEl.value;
    if (!path) {
      statusEl.innerHTML = '<span class="err">Pick an HTML file first.</span>';
      return;
    }
    startBtn.disabled = true;
    statusEl.textContent = 'Starting server...';
    vscode.postMessage({ type: 'startShare', path });
  });

  stopBtn.addEventListener('click', () => {
    vscode.postMessage({ type: 'stopShare' });
  });

  document.getElementById('copyUrl').addEventListener('click', () => {
    vscode.postMessage({ type: 'copy', text: currentUrls[selectedIdx]?.url || '' });
  });
  document.getElementById('openUrl').addEventListener('click', () => {
    vscode.postMessage({ type: 'open', text: currentUrls[selectedIdx]?.url || '' });
  });

  function renderQr(url) {
    qrEl.innerHTML = '';
    urlTextEl.textContent = url;
    try {
      const qr = qrcode(0, 'M');
      qr.addData(url);
      qr.make();
      qrEl.innerHTML = qr.createSvgTag({ cellSize: 5, margin: 2, scalable: true });
      const svg = qrEl.querySelector('svg');
      if (svg) { svg.setAttribute('width', '240'); svg.setAttribute('height', '240'); }
    } catch (e) {
      qrEl.textContent = 'QR render failed: ' + e.message;
    }
  }

  function renderIfaces(urls) {
    ifaceList.innerHTML = '';
    if (urls.length <= 1) {
      ifaceWrap.style.display = 'none';
      return;
    }
    ifaceWrap.style.display = '';
    urls.forEach((u, i) => {
      const id = 'iface_' + i;
      const label = document.createElement('label');
      label.innerHTML = '<input type="radio" name="iface" id="' + id + '"' +
        (i === selectedIdx ? ' checked' : '') + ' /> ' +
        u.ip + '<span class="meta">(' + u.iface + ')</span>';
      label.querySelector('input').addEventListener('change', () => {
        selectedIdx = i;
        renderQr(urls[i].url);
      });
      ifaceList.appendChild(label);
    });
  }

  window.addEventListener('message', (e) => {
    const m = e.data;
    if (m.type === 'fileSelected') {
      filePathEl.value = m.path;
      fileNameEl.textContent = m.name;
    } else if (m.type === 'sharing') {
      currentUrls = m.urls;
      selectedIdx = 0;
      statusEl.innerHTML = '<span class="ok">Sharing: ' + m.filename + '</span>';
      shareInfo.style.display = '';
      renderIfaces(m.urls);
      renderQr(m.urls[0].url);
      startBtn.disabled = true;
      stopBtn.disabled = false;
    } else if (m.type === 'stopped') {
      statusEl.textContent = 'Stopped.';
      shareInfo.style.display = 'none';
      currentUrls = [];
      startBtn.disabled = false;
      stopBtn.disabled = true;
    } else if (m.type === 'error') {
      statusEl.innerHTML = '<span class="err">' + (m.message || 'Error').replace(/</g, '&lt;') + '</span>';
      startBtn.disabled = false;
    }
  });
</script>
</body>
</html>`;
}
