import * as vscode from 'vscode';
import * as fs from 'fs';
import * as path from 'path';
import { File } from 'node:buffer';
import { handleClipboardAndOpen, singletonPanel } from './shared';

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

export function openPlecUpload(_context: vscode.ExtensionContext) {
  const { panel, isNew } = singletonPanel(store, 'hplToolbox.plecUpload', 'PLEC Upload');
  if (!isNew) return;

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

      if (msg.type === 'pickFile') {
        const picked = await vscode.window.showOpenDialog({
          canSelectMany: true,
          filters: { HTML: ['html', 'htm'] },
          openLabel: 'Select',
          defaultUri: getPickerDefaultUri(),
        });
        if (picked && picked.length) {
          panel.webview.postMessage({
            type: 'filesSelected',
            rowId: msg.rowId,
            files: picked.map(u => ({ path: u.fsPath, name: path.basename(u.fsPath) })),
          });
        }
        return;
      }

      if (msg.type === 'upload') {
        await handleUpload(panel, msg.rows);
        return;
      }
    } catch (err: any) {
      panel.webview.postMessage({ type: 'error', message: err?.message || String(err) });
    }
  });
}

interface UploadRow {
  id: string;
  path: string;
  iteration: string;
}

async function handleUpload(panel: vscode.WebviewPanel, rows: UploadRow[]) {
  const cfg = vscode.workspace.getConfiguration('hplToolbox.plec');
  const uploadUrl = cfg.get<string>('uploadUrl')!;
  const originUrl = cfg.get<string>('originUrl')!;

  const valid: UploadRow[] = [];
  for (const r of rows) {
    if (!r.path || !fs.existsSync(r.path)) {
      panel.webview.postMessage({ type: 'rowError', rowId: r.id, message: 'File missing' });
      return;
    }
    if (!r.iteration || !r.iteration.trim()) {
      panel.webview.postMessage({ type: 'rowError', rowId: r.id, message: 'Iteration name required' });
      return;
    }
    if (!/\.html?$/i.test(r.path)) {
      panel.webview.postMessage({ type: 'rowError', rowId: r.id, message: 'Must be .html' });
      return;
    }
    valid.push(r);
  }
  if (valid.length === 0) {
    panel.webview.postMessage({ type: 'error', message: 'Nothing to upload.' });
    return;
  }

  const stamp = timestampSuffix();
  const stampedNames = valid.map((r) => appendTimestamp(path.basename(r.path), stamp));

  panel.webview.postMessage({ type: 'status', message: 'Uploading...' });

  const form = new FormData();
  for (let i = 0; i < valid.length; i++) {
    const r = valid[i];
    const idx = i + 1;
    const buf = fs.readFileSync(r.path);
    const file = new File([buf], stampedNames[i], { type: 'text/html' });
    form.append(`fileUpload_${idx}`, file as any);
    form.append(`iterationNameUpload_${idx}`, encodeURI(r.iteration.replace(/\s+/g, '')));
  }

  let res: Response;
  try {
    res = await fetch(uploadUrl, {
      method: 'POST',
      body: form,
      headers: {
        'Origin': originUrl,
        'Referer': originUrl + '/',
        'User-Agent': 'Mozilla/5.0 (HPL-Toolbox-VSCode)',
        'X-Requested-With': 'XMLHttpRequest',
        'Accept': '*/*',
      },
    });
  } catch (err: any) {
    panel.webview.postMessage({ type: 'error', message: 'Network error: ' + (err?.message || err) });
    return;
  }

  const text = await res.text();
  if (!res.ok) {
    panel.webview.postMessage({
      type: 'error',
      message: `HTTP ${res.status}\n${text.slice(0, 800)}`,
    });
    return;
  }

  let json: any;
  try { json = JSON.parse(text); }
  catch {
    panel.webview.postMessage({
      type: 'error',
      message: `Server returned non-JSON:\n${text.slice(0, 800)}`,
    });
    return;
  }

  const preview = json.preview || json.previewURL || null;
  panel.webview.postMessage({ type: 'result', preview, raw: json, rawText: text });
}

function timestampSuffix(d: Date = new Date()): string {
  const pad = (n: number, w = 2) => String(n).padStart(w, '0');
  return (
    d.getFullYear().toString() +
    pad(d.getMonth() + 1) +
    pad(d.getDate()) +
    pad(d.getHours()) +
    pad(d.getMinutes()) +
    pad(d.getSeconds())
  );
}

function appendTimestamp(filename: string, stamp: string): string {
  const ext = path.extname(filename);
  const base = ext ? filename.slice(0, -ext.length) : filename;
  return `${base}_${stamp}${ext}`;
}

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(): 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; }
  table { width: 100%; border-collapse: collapse; margin-bottom: 12px; }
  th, td { padding: 6px 8px; text-align: left; vertical-align: middle; border-bottom: 1px solid var(--vscode-panel-border); }
  th { font-weight: 600; font-size: 12px; text-transform: uppercase; opacity: 0.7; }
  input[type=text] {
    width: 100%; padding: 4px 6px;
    background: var(--vscode-input-background); color: var(--vscode-input-foreground);
    border: 1px solid var(--vscode-input-border, transparent);
    border-radius: 2px;
  }
  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); }
  .file-cell { display: flex; align-items: center; gap: 8px; }
  .file-name { opacity: 0.85; font-size: 12px; word-break: break-all; }
  .row-error { color: var(--vscode-errorForeground); font-size: 12px; margin-top: 4px; }
  .actions { margin-top: 12px; display: flex; gap: 8px; }
  #status { margin-top: 12px; min-height: 20px; }
  .err { color: var(--vscode-errorForeground); white-space: pre-wrap; }
  .ok { color: var(--vscode-testing-iconPassed, var(--vscode-foreground)); }
  .result {
    margin-top: 12px; padding: 10px;
    background: var(--vscode-textBlockQuote-background);
    border-left: 3px solid var(--vscode-textBlockQuote-border);
    word-break: break-all;
  }
  .result a { color: var(--vscode-textLink-foreground); }
  .result-actions { margin-top: 8px; display: flex; gap: 8px; }
  .remove-btn { background: transparent; color: var(--vscode-foreground); padding: 4px 8px; }
</style>
</head>
<body>
<h2>PLEC Upload</h2>
<p style="opacity:0.8;font-size:12px;margin-top:0;">Pick HTML files, give each an iteration name, then upload. The preview link is returned by the server.</p>

<table id="rows">
  <thead>
    <tr>
      <th style="width:45%">HTML File</th>
      <th style="width:45%">Iteration Name</th>
      <th></th>
    </tr>
  </thead>
  <tbody></tbody>
</table>

<div class="actions">
  <button id="addRow" class="secondary">+ Add Row</button>
  <button id="upload">Upload</button>
</div>

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

<script>
  const vscode = acquireVsCodeApi();
  let nextId = 1;
  const tbody = document.querySelector('#rows tbody');

  function parseIterationName(filename) {
    const base = filename.replace(/\\.html?$/i, '');
    const tokens = base.split('_');
    for (const t of tokens) {
      if (/^(full|\\d+clk|\\d+s(?:ec)?)$/i.test(t)) return t.toLowerCase();
    }
    return base;
  }
  const statusEl = document.getElementById('status');
  const resultsEl = document.getElementById('results');

  function addRow() {
    const id = 'r' + (nextId++);
    const tr = document.createElement('tr');
    tr.dataset.id = id;
    tr.innerHTML = \`
      <td>
        <div class="file-cell">
          <button class="pick secondary">Choose...</button>
          <span class="file-name" data-name>(no file)</span>
        </div>
        <input type="hidden" data-path />
        <div class="row-error" data-error></div>
      </td>
      <td><input type="text" data-iter placeholder="iteration name" /></td>
      <td><button class="remove-btn" title="Remove">×</button></td>
    \`;
    tr.querySelector('.pick').addEventListener('click', () => {
      vscode.postMessage({ type: 'pickFile', rowId: id });
    });
    tr.querySelector('.remove-btn').addEventListener('click', () => {
      tr.remove();
      if (!tbody.children.length) addRow();
    });
    tbody.appendChild(tr);
  }

  document.getElementById('addRow').addEventListener('click', addRow);

  document.getElementById('upload').addEventListener('click', () => {
    clearErrors();
    statusEl.textContent = '';
    resultsEl.innerHTML = '';
    const rows = [...tbody.querySelectorAll('tr')].map(tr => ({
      id: tr.dataset.id,
      path: tr.querySelector('[data-path]').value,
      iteration: tr.querySelector('[data-iter]').value,
    })).filter(r => r.path || r.iteration);
    if (rows.length === 0) {
      statusEl.innerHTML = '<span class="err">Add at least one row with a file and iteration name.</span>';
      return;
    }
    vscode.postMessage({ type: 'upload', rows });
  });

  function clearErrors() {
    document.querySelectorAll('[data-error]').forEach(el => el.textContent = '');
  }

  window.addEventListener('message', (e) => {
    const m = e.data;
    if (m.type === 'filesSelected') {
      const firstTr = tbody.querySelector('tr[data-id="' + m.rowId + '"]');
      const affected = [];
      m.files.forEach(function(f, i) {
        let tr;
        if (i === 0) {
          tr = firstTr;
        } else {
          addRow();
          tr = tbody.lastElementChild;
        }
        if (!tr) return;
        tr.querySelector('[data-path]').value = f.path;
        tr.querySelector('[data-name]').textContent = f.name;
        const iter = tr.querySelector('[data-iter]');
        if (!iter.value) iter.value = parseIterationName(f.name);
        affected.push(tr);
      });
      if (affected.length > 1) {
        const iters = affected.map(r => r.querySelector('[data-iter]').value);
        if (iters[0] !== '' && iters.every(n => n === iters[0])) {
          affected.forEach((r, i) => {
            r.querySelector('[data-iter]').value = String(i + 1).padStart(2, '0') + '_' + iters[0];
          });
        }
      }
    } else if (m.type === 'status') {
      statusEl.textContent = m.message;
      statusEl.className = '';
    } else if (m.type === 'error') {
      statusEl.innerHTML = '';
      const div = document.createElement('div');
      div.className = 'err';
      div.textContent = m.message;
      statusEl.appendChild(div);
    } else if (m.type === 'rowError') {
      const tr = tbody.querySelector('tr[data-id="' + m.rowId + '"]');
      if (tr) tr.querySelector('[data-error]').textContent = m.message;
      statusEl.innerHTML = '<span class="err">Fix row errors and retry.</span>';
    } else if (m.type === 'result') {
      statusEl.innerHTML = '<span class="ok">Upload complete.</span>';
      const wrap = document.createElement('div');
      wrap.className = 'result';
      if (m.preview) {
        wrap.innerHTML = '<div><strong>Preview:</strong> <a href="' + m.preview + '">' + m.preview + '</a></div>';
        const actions = document.createElement('div');
        actions.className = 'result-actions';
        const copy = document.createElement('button');
        copy.textContent = 'Copy';
        copy.onclick = () => vscode.postMessage({ type: 'copy', text: m.preview });
        const open = document.createElement('button');
        open.textContent = 'Open';
        open.className = 'secondary';
        open.onclick = () => vscode.postMessage({ type: 'open', text: m.preview });
        const showRaw = document.createElement('button');
        showRaw.textContent = 'Show server response';
        showRaw.className = 'secondary';
        showRaw.onclick = () => {
          const pre = document.createElement('pre');
          pre.style.marginTop = '8px';
          pre.style.whiteSpace = 'pre-wrap';
          pre.textContent = m.rawText || JSON.stringify(m.raw, null, 2);
          wrap.appendChild(pre);
          showRaw.disabled = true;
        };
        actions.appendChild(copy); actions.appendChild(open); actions.appendChild(showRaw);
        wrap.appendChild(actions);
      } else {
        wrap.innerHTML = '<div>No preview field in response. Raw JSON:</div><pre>' +
          (m.rawText || JSON.stringify(m.raw, null, 2)).replace(/</g, '&lt;') + '</pre>';
      }
      resultsEl.innerHTML = '';
      resultsEl.appendChild(wrap);
    }
  });

  addRow();
</script>
</body>
</html>`;
}
