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 openApplovinUpload(_context: vscode.ExtensionContext) {
  const { panel, isNew } = singletonPanel(store, 'hplToolbox.applovinUpload', 'AppLovin Demo Upload');
  if (!isNew) return;

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

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

      if (msg.type === 'upload') {
        await handleUpload(panel, msg.paths);
        return;
      }

      if (msg.type === 'saveQr') {
        await handleSaveQr(panel, msg.url, msg.name);
        return;
      }

      if (msg.type === 'saveAllQrs') {
        await handleSaveAllQrs(panel, msg.items || []);
        return;
      }
    } catch (err: any) {
      panel.webview.postMessage({ type: 'error', message: err?.message || String(err) });
    }
  });
}

const USER_AGENTS = [
  'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36',
  'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36',
  'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36 Edg/129.0.0.0',
  'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36',
  'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.6 Safari/605.1.15',
  'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:131.0) Gecko/20100101 Firefox/131.0',
  'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36',
];

function pickUserAgent(randomize: boolean): string {
  if (!randomize) return USER_AGENTS[0];
  return USER_AGENTS[Math.floor(Math.random() * USER_AGENTS.length)];
}

function sleep(ms: number): Promise<void> {
  return new Promise(resolve => setTimeout(resolve, ms));
}

async function handleUpload(panel: vscode.WebviewPanel, filePaths: string[]) {
  const cfg = vscode.workspace.getConfiguration('hplToolbox.applovin');
  const cookie = (cfg.get<string>('cookie') || '').trim();
  const delayMs = Math.max(0, cfg.get<number>('delayMs') ?? 1500);
  const randomizeUA = cfg.get<boolean>('randomizeUserAgent') ?? true;

  const paths = Array.isArray(filePaths) ? filePaths : [filePaths];
  if (!paths.length) {
    panel.webview.postMessage({ type: 'error', message: 'No files selected.' });
    return;
  }

  const buildHeaders = (): Record<string, string> => {
    const headers: Record<string, string> = {
      'Accept': 'application/json, text/javascript, */*; q=0.01',
      'Origin': 'https://p.applov.in',
      'Referer': 'https://p.applov.in/playablePreview?create=1&qr=1',
      'X-Requested-With': 'XMLHttpRequest',
      'User-Agent': pickUserAgent(randomizeUA),
    };
    if (cookie) headers['Cookie'] = `__Host-APPLOVINID=${cookie}`;
    return headers;
  };

  const buildForm = (filePath: string): FormData => {
    const buf = fs.readFileSync(filePath);
    const file = new File([buf], path.basename(filePath), { type: 'text/html' });
    const form = new FormData();
    form.append('file', file as any);
    return form;
  };

  panel.webview.postMessage({ type: 'start', total: paths.length });

  for (let i = 0; i < paths.length; i++) {
    const filePath = paths[i];
    const fileName = path.basename(filePath);
    const idx = i + 1;
    const reportError = (message: string) => {
      panel.webview.postMessage({ type: 'fileError', name: fileName, message });
    };

    if (!filePath || !fs.existsSync(filePath)) { reportError('File missing'); continue; }
    if (!/\.html?$/i.test(filePath)) { reportError('Must be .html'); continue; }

    if (i > 0 && delayMs > 0) {
      panel.webview.postMessage({ type: 'status', message: `[${idx}/${paths.length}] Waiting ${delayMs}ms before ${fileName}...` });
      await sleep(delayMs);
    }

    panel.webview.postMessage({ type: 'status', message: `[${idx}/${paths.length}] Validating ${fileName}...` });

    let res: Response;
    try {
      res = await fetch('https://p.applov.in/validateHTMLContent', {
        method: 'POST', body: buildForm(filePath), headers: buildHeaders(),
      });
    } catch (err: any) { reportError('Network error (validate): ' + (err?.message || err)); continue; }
    const validateText = await res.text();
    if (!res.ok) { reportError(`Validate HTTP ${res.status}: ${validateText.slice(0, 300)}`); continue; }
    let validateJson: any;
    try { validateJson = JSON.parse(validateText); } catch { validateJson = null; }
    if (validateJson && validateJson.code && validateJson.code !== 200) {
      reportError(`Validation failed: ${validateText.slice(0, 300)}`); continue;
    }

    panel.webview.postMessage({ type: 'status', message: `[${idx}/${paths.length}] Uploading ${fileName}...` });

    try {
      res = await fetch('https://p.applov.in/getCachedAdURL', {
        method: 'POST', body: buildForm(filePath), headers: buildHeaders(),
      });
    } catch (err: any) { reportError('Network error (cache): ' + (err?.message || err)); continue; }
    const cacheText = await res.text();
    if (!res.ok) { reportError(`Cache HTTP ${res.status}: ${cacheText.slice(0, 300)}`); continue; }
    let cacheJson: any;
    try { cacheJson = JSON.parse(cacheText); }
    catch { reportError(`Non-JSON response: ${cacheText.slice(0, 300)}`); continue; }
    const hash = cacheJson.results;
    if (!hash) { reportError(`No hash in response: ${cacheText.slice(0, 300)}`); continue; }

    panel.webview.postMessage({
      type: 'fileResult',
      name: fileName,
      hash,
      previewUrl: `https://p.applov.in/getPreviewHTML?preview=${hash}`,
      pageUrl: `https://p.applov.in/playablePreview?preview=${hash}&qr=1`,
      qrImg: `https://api.qrserver.com/v1/create-qr-code/?size=250x250&data=${encodeURIComponent(hash)}`,
    });
  }

  panel.webview.postMessage({ type: 'done' });
}

function qrBaseName(name: string): string {
  return (name || 'qr').replace(/\.html?$/i, '').replace(/[\\/:*?"<>|]/g, '_') || 'qr';
}

async function downloadQr(url: string, destPath: string): Promise<void> {
  const res = await fetch(url);
  if (!res.ok) throw new Error(`HTTP ${res.status}`);
  const buf = Buffer.from(await res.arrayBuffer());
  await fs.promises.writeFile(destPath, buf);
}

async function handleSaveQr(panel: vscode.WebviewPanel, url: string, name: string) {
  if (!url) return;
  const base = qrBaseName(name);
  const defaultUri = vscode.Uri.file(path.join(require('os').homedir(), 'Downloads', `${base}.png`));
  const target = await vscode.window.showSaveDialog({
    defaultUri,
    filters: { 'PNG Image': ['png'] },
    saveLabel: 'Save QR',
  });
  if (!target) return;
  try {
    await downloadQr(url, target.fsPath);
    panel.webview.postMessage({ type: 'status', message: `Saved QR: ${target.fsPath}` });
  } catch (err: any) {
    panel.webview.postMessage({ type: 'error', message: 'Save QR failed: ' + (err?.message || err) });
  }
}

async function handleSaveAllQrs(panel: vscode.WebviewPanel, items: Array<{ name: string; url: string }>) {
  if (!items.length) return;
  const picked = await vscode.window.showOpenDialog({
    canSelectFiles: false,
    canSelectFolders: true,
    canSelectMany: false,
    openLabel: 'Save QRs Here',
  });
  if (!picked || !picked.length) return;
  const dir = picked[0].fsPath;
  let saved = 0;
  const errors: string[] = [];
  for (const it of items) {
    const base = qrBaseName(it.name);
    let dest = path.join(dir, `${base}.png`);
    let n = 1;
    while (fs.existsSync(dest)) {
      dest = path.join(dir, `${base} (${n++}).png`);
    }
    try {
      await downloadQr(it.url, dest);
      saved++;
    } catch (err: any) {
      errors.push(`${it.name}: ${err?.message || err}`);
    }
  }
  if (errors.length) {
    panel.webview.postMessage({ type: 'error', message: `Saved ${saved}/${items.length}. Errors:\n` + errors.join('\n') });
  } else {
    panel.webview.postMessage({ type: 'status', message: `Saved ${saved} QR${saved === 1 ? '' : 's'} to ${dir}` });
  }
}

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; }
  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; }
  .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 {
    padding: 10px;
    background: var(--vscode-textBlockQuote-background);
    border-left: 3px solid var(--vscode-textBlockQuote-border);
    word-break: break-all;
  }
  .result-actions { margin-top: 8px; display: flex; gap: 8px; }
  #results { margin-top: 12px; display: grid; grid-template-columns: repeat(auto-fill,minmax(280px,1fr)); gap: 12px; }
</style>
</head>
<body>
<h2>AppLovin Playable Preview (QR)</h2>
<p style="opacity:0.8;font-size:12px;margin-top:0;">Upload HTML files to p.applov.in and get QR codes to scan with the AppLovin Playable Preview app (iOS/Android).</p>

<div class="file-cell" style="margin-bottom:8px;">
  <button id="pick" class="secondary">Add files...</button>
  <button id="clear" class="secondary" style="display:none;">Clear</button>
  <span class="file-name" id="fileName">(no files)</span>
</div>
<div id="fileList" style="margin-bottom:8px;font-size:12px;opacity:0.85;"></div>
<div class="actions">
  <button id="upload">Upload to AppLovin</button>
  <button id="saveAll" class="secondary" style="display:none;">Save All QRs...</button>
  <button id="regenAll" class="secondary" style="display:none;">Regenerate QRs</button>
</div>
<div id="status"></div>
<div id="results"></div>

<script>
  const vscode = acquireVsCodeApi();
  const pickBtn = document.getElementById('pick');
  const clearBtn = document.getElementById('clear');
  const uploadBtn = document.getElementById('upload');
  const fileNameEl = document.getElementById('fileName');
  const fileListEl = document.getElementById('fileList');
  const statusEl = document.getElementById('status');
  const resultsEl = document.getElementById('results');
  const saveAllBtn = document.getElementById('saveAll');
  const regenAllBtn = document.getElementById('regenAll');
  let selectedPaths = [];
  let resultItems = [];

  function basename(p) {
    const i = Math.max(p.lastIndexOf('/'), p.lastIndexOf('\\\\'));
    return i >= 0 ? p.slice(i + 1) : p;
  }
  function renderSelection() {
    if (!selectedPaths.length) {
      fileNameEl.textContent = '(no files)';
      fileListEl.innerHTML = '';
      clearBtn.style.display = 'none';
      return;
    }
    fileNameEl.textContent = selectedPaths.length + ' file' + (selectedPaths.length === 1 ? '' : 's');
    fileListEl.innerHTML = selectedPaths.map(p => '<div>' + escapeHtml(basename(p)) + '</div>').join('');
    clearBtn.style.display = '';
  }

  saveAllBtn.addEventListener('click', () => {
    if (!resultItems.length) return;
    vscode.postMessage({ type: 'saveAllQrs', items: resultItems });
  });

  regenAllBtn.addEventListener('click', () => {
    const imgs = resultsEl.querySelectorAll('img[data-qr]');
    imgs.forEach(img => {
      const base = img.getAttribute('data-qr');
      img.src = base + '&_=' + Date.now();
    });
  });

  pickBtn.addEventListener('click', () => vscode.postMessage({ type: 'pickFiles' }));
  clearBtn.addEventListener('click', () => {
    selectedPaths = [];
    renderSelection();
  });

  uploadBtn.addEventListener('click', () => {
    statusEl.textContent = '';
    resultsEl.innerHTML = '';
    if (!selectedPaths.length) {
      statusEl.innerHTML = '<span class="err">Pick at least one HTML file first.</span>';
      return;
    }
    uploadBtn.disabled = true;
    resultItems = [];
    saveAllBtn.style.display = 'none';
    regenAllBtn.style.display = 'none';
    vscode.postMessage({ type: 'upload', paths: selectedPaths });
  });

  function escapeHtml(s) {
    return String(s).replace(/[&<>"']/g, c => ({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'}[c]));
  }

  window.addEventListener('message', (e) => {
    const m = e.data;
    if (m.type === 'filesSelected') {
      const added = m.files.map(f => f.path).filter(p => !selectedPaths.includes(p));
      selectedPaths = selectedPaths.concat(added);
      renderSelection();
    } else if (m.type === 'start') {
      resultsEl.innerHTML = '';
      resultItems = [];
      saveAllBtn.style.display = 'none';
      regenAllBtn.style.display = 'none';
    } else if (m.type === 'status') {
      statusEl.textContent = m.message;
      statusEl.className = '';
    } else if (m.type === 'error') {
      const div = document.createElement('div');
      div.className = 'err';
      div.textContent = m.message;
      statusEl.innerHTML = '';
      statusEl.appendChild(div);
      uploadBtn.disabled = false;
    } else if (m.type === 'fileError') {
      const wrap = document.createElement('div');
      wrap.className = 'result';
      wrap.innerHTML = '<div><strong>' + escapeHtml(m.name) + '</strong></div>' +
        '<div class="err" style="margin-top:6px;">' + escapeHtml(m.message) + '</div>';
      resultsEl.appendChild(wrap);
    } else if (m.type === 'fileResult') {
      const wrap = document.createElement('div');
      wrap.className = 'result';
      wrap.innerHTML =
        '<div style="font-weight:600;margin-bottom:8px;word-break:break-all;">' + escapeHtml(m.name) + '</div>' +
        '<div style="text-align:center;margin-bottom:8px;">' +
          '<img src="' + m.qrImg + '" data-qr="' + m.qrImg + '" alt="QR" style="background:#fff;padding:8px;border-radius:4px;max-width:100%;" />' +
        '</div>' +
        '<div style="font-size:11px;opacity:0.8;word-break:break-all;">Hash: ' + escapeHtml(m.hash) + '</div>';
      const actions = document.createElement('div');
      actions.className = 'result-actions';
      const openPreview = document.createElement('button');
      openPreview.textContent = 'Open';
      openPreview.className = 'secondary';
      openPreview.onclick = () => vscode.postMessage({ type: 'open', text: m.previewUrl });
      const saveQr = document.createElement('button');
      saveQr.textContent = 'Save QR';
      saveQr.className = 'secondary';
      saveQr.onclick = () => vscode.postMessage({ type: 'saveQr', url: m.qrImg, name: m.name });
      actions.appendChild(openPreview);
      actions.appendChild(saveQr);
      wrap.appendChild(actions);
      resultsEl.appendChild(wrap);
      resultItems.push({ name: m.name, url: m.qrImg });
      if (resultItems.length >= 2) {
        saveAllBtn.style.display = '';
        regenAllBtn.style.display = '';
      }
    } else if (m.type === 'done') {
      statusEl.innerHTML = '<span class="ok">Done.</span>';
      uploadBtn.disabled = false;
    }
  });
</script>
</body>
</html>`;
}
