const express      = require('express');
const fs           = require('fs');
const path         = require('path');
const { execSync } = require('child_process');
const router       = express.Router();
const authMw       = require('../middleware/auth');

const PANEL_DIR = path.join(__dirname, '..');
const PRESERVE  = new Set(['data', '.env', 'node_modules', '.git', 'update-temp', 'update-temp.zip']);

function getConfig() {
  return { repo: process.env.GITHUB_REPO, token: process.env.GITHUB_TOKEN };
}

// Use PowerShell Invoke-RestMethod — reliable on Windows, handles TLS correctly
function psGet(url) {
  const { token } = getConfig();
  const script = `
    $headers = @{ Authorization = 'token ${token}'; 'User-Agent' = 'Nettbyte-Kpanel' }
    try {
      $r = Invoke-RestMethod -Uri '${url}' -Headers $headers -Method Get -ErrorAction Stop
      $r | ConvertTo-Json -Depth 10
    } catch {
      Write-Output ('__ERROR__' + $_.Exception.Message)
    }
  `;
  const encoded = Buffer.from(script, 'utf16le').toString('base64');
  const out = execSync(
    `powershell -NoProfile -NonInteractive -ExecutionPolicy Bypass -EncodedCommand ${encoded}`,
    { timeout: 30000, encoding: 'utf8' }
  ).trim();
  if (out.startsWith('__ERROR__')) throw new Error(out.replace('__ERROR__', ''));
  return JSON.parse(out);
}

// Use PowerShell Invoke-WebRequest to download the ZIP
function psDownload(url, dest) {
  const { token } = getConfig();
  const script = `
    $headers = @{ Authorization = 'token ${token}'; 'User-Agent' = 'Nettbyte-Kpanel' }
    try {
      Invoke-WebRequest -Uri '${url}' -Headers $headers -OutFile '${dest}' -ErrorAction Stop
      Write-Output 'ok'
    } catch {
      Write-Output ('__ERROR__' + $_.Exception.Message)
    }
  `;
  const encoded = Buffer.from(script, 'utf16le').toString('base64');
  const out = execSync(
    `powershell -NoProfile -NonInteractive -ExecutionPolicy Bypass -EncodedCommand ${encoded}`,
    { timeout: 120000, encoding: 'utf8' }
  ).trim();
  if (out.includes('__ERROR__')) throw new Error(out.replace('__ERROR__', ''));
}

function copyFiles(src, dest) {
  for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
    if (PRESERVE.has(entry.name)) continue;
    const s = path.join(src, entry.name);
    const d = path.join(dest, entry.name);
    if (entry.isDirectory()) {
      fs.mkdirSync(d, { recursive: true });
      copyFiles(s, d);
    } else {
      fs.copyFileSync(s, d);
    }
  }
}

function adminOnly(req, res, next) {
  if (req.user?.role !== 'admin') return res.status(403).json({ error: 'Admin only' });
  next();
}

// ── Check for update ───────────────────────────────────────
router.get('/check', authMw, adminOnly, (req, res) => {
  const { repo } = getConfig();
  if (!repo) return res.status(500).json({ error: 'GITHUB_REPO not set in .env' });
  try {
    const current = JSON.parse(fs.readFileSync(path.join(PANEL_DIR, 'version.json'), 'utf8')).version;
    const release = psGet(`https://api.github.com/repos/${repo}/releases/latest`);

    const latest = (release.tag_name || '').replace(/^v/, '');
    if (!latest) return res.status(400).json({ error: 'No releases found on GitHub' });

    res.json({
      current,
      latest,
      hasUpdate:    latest !== current,
      releaseNotes: release.body         || '',
      publishedAt:  release.published_at || '',
      zipUrl:       release.zipball_url
    });
  } catch (e) {
    res.status(500).json({ error: e.message });
  }
});

// ── Apply update ───────────────────────────────────────────
router.post('/apply', authMw, adminOnly, (req, res) => {
  const { repo } = getConfig();
  if (!repo) return res.status(500).json({ error: 'GITHUB_REPO not set in .env' });

  const tempZip = path.join(PANEL_DIR, 'update-temp.zip');
  const tempDir = path.join(PANEL_DIR, 'update-temp');

  try {
    const release = psGet(`https://api.github.com/repos/${repo}/releases/latest`);
    const version = (release.tag_name || '').replace(/^v/, '');
    if (!version) throw new Error('No releases found on GitHub');

    // Download ZIP via PowerShell
    psDownload(release.zipball_url, tempZip);

    // Extract
    fs.mkdirSync(tempDir, { recursive: true });
    execSync(
      `powershell -Command "Expand-Archive -Path '${tempZip}' -DestinationPath '${tempDir}' -Force"`,
      { timeout: 60000 }
    );

    // GitHub wraps files in a subfolder like "owner-repo-abc123/"
    const subFolders = fs.readdirSync(tempDir);
    if (!subFolders.length) throw new Error('Update archive was empty');
    const sourceDir = path.join(tempDir, subFolders[0]);

    // Copy new files, preserving data/, .env, node_modules/, .git/
    copyFiles(sourceDir, PANEL_DIR);

    // Write updated version
    fs.writeFileSync(path.join(PANEL_DIR, 'version.json'), JSON.stringify({ version }, null, 2));

    // Clean up
    fs.rmSync(tempZip, { force: true });
    fs.rmSync(tempDir, { recursive: true, force: true });

    // Install any new dependencies
    execSync('npm install --omit=dev', { cwd: PANEL_DIR, timeout: 120000 });

    res.json({ ok: true, version });

    // Restart so new code takes effect
    setTimeout(() => process.exit(0), 1500);
  } catch (e) {
    try { fs.rmSync(tempZip, { force: true }); } catch (_) {}
    try { fs.rmSync(tempDir, { recursive: true, force: true }); } catch (_) {}
    res.status(500).json({ error: e.message });
  }
});

module.exports = router;
