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

// Return hidden/readonly attrib flags for every entry in a directory (single attrib call)
function getDirAttribs(dir) {
  const attrs = {};
  try {
    const out = execSync(`attrib "${dir}\\*"`, { encoding: 'utf8', timeout: 5000, windowsHide: true });
    for (const line of out.split('\n')) {
      const driveIdx = line.search(/[A-Za-z]:\\/);
      if (driveIdx < 1) continue;
      const flags    = line.substring(0, driveIdx).toUpperCase();
      const fullPath = line.substring(driveIdx).trim();
      const name     = path.basename(fullPath);
      attrs[name] = { hidden: flags.includes('H'), readonly: flags.includes('R') };
    }
  } catch (_) {}
  return attrs;
}

// ── File list ──────────────────────────────────────────────
router.get('/list', authMw, (req, res) => {
  const dir = req.query.path || 'C:\\';
  try {
    const attrs = getDirAttribs(dir);
    const items = fs.readdirSync(dir, { withFileTypes: true }).map(d => {
      let size = null, modified = null;
      try {
        if (d.isFile()) {
          const stat = fs.statSync(path.join(dir, d.name));
          size     = stat.size;
          modified = stat.mtime;
        }
      } catch (_) {}
      const a = attrs[d.name] || {};
      return {
        name:     d.name,
        isDir:    d.isDirectory(),
        size,
        modified,
        hidden:   a.hidden   || false,
        readonly: a.readonly || false
      };
    });
    items.sort((a, b) => (b.isDir - a.isDir) || a.name.localeCompare(b.name));
    res.json({ path: dir, items });
  } catch (e) {
    res.status(400).json({ error: e.message });
  }
});

// ── Create directory ───────────────────────────────────────
router.post('/mkdir', authMw, (req, res) => {
  try {
    fs.mkdirSync(req.body.path, { recursive: true });
    writeAudit(req, 'files.mkdir', req.body.path);
    res.json({ ok: true });
  } catch (e) {
    res.status(400).json({ error: e.message });
  }
});

// ── Delete single file or folder ───────────────────────────
router.delete('/delete', authMw, (req, res) => {
  try {
    writeAudit(req, 'files.delete', req.query.path);
    fs.rmSync(req.query.path, { recursive: true, force: true });
    res.json({ ok: true });
  } catch (e) {
    res.status(400).json({ error: e.message });
  }
});

// ── Delete multiple files / folders ────────────────────────
router.delete('/delete-multi', authMw, (req, res) => {
  const { paths } = req.body;
  if (!paths || !paths.length) return res.status(400).json({ error: 'paths required' });
  const errors = [];
  paths.forEach(p => {
    try {
      try { execSync(`attrib -R "${p}"`, { windowsHide: true, timeout: 3000 }); } catch (_) {}
      fs.rmSync(p, { recursive: true, force: true });
      writeAudit(req, 'files.delete', p);
    } catch (e) {
      errors.push(path.basename(p) + ': ' + e.message);
    }
  });
  if (errors.length) res.status(207).json({ ok: false, errors });
  else res.json({ ok: true });
});

// ── Download file ──────────────────────────────────────────
router.get('/download', authMw, (req, res) => {
  const filePath = req.query.path;
  if (!filePath) return res.status(400).json({ error: 'Path required' });
  try {
    if (!fs.existsSync(filePath)) return res.status(404).json({ error: 'File not found' });
    const stat = fs.statSync(filePath);
    if (stat.isDirectory()) return res.status(400).json({ error: 'Cannot download a directory' });
    writeAudit(req, 'files.download', filePath);
    res.download(filePath, path.basename(filePath));
  } catch (e) {
    res.status(500).json({ error: e.message });
  }
});

// ── Upload file(s) using busboy ────────────────────────────
router.post('/upload', authMw, (req, res) => {
  const dir = req.query.path || (req.body && req.body.path);
  if (!dir) return res.status(400).json({ error: 'Target path required' });

  let Busboy;
  try { Busboy = require('busboy'); }
  catch { return res.status(500).json({ error: 'busboy not installed. Run: npm install busboy' }); }

  const uploaded = [];
  const errors   = [];
  const bb = Busboy({ headers: req.headers, limits: { fileSize: 500 * 1024 * 1024 } });

  bb.on('file', (fieldname, file, info) => {
    const { filename } = info;
    if (!filename) { file.resume(); return; }
    const safeName = path.basename(filename);
    const destPath = path.join(dir, safeName);
    const ws = fs.createWriteStream(destPath);
    file.pipe(ws);
    ws.on('finish', () => { uploaded.push(safeName); writeAudit(req, 'files.upload', destPath); });
    ws.on('error',  err => errors.push(safeName + ': ' + err.message));
  });

  bb.on('finish', () => {
    if (errors.length) return res.status(500).json({ error: errors.join('; '), uploaded });
    res.json({ ok: true, uploaded });
  });
  bb.on('error', err => res.status(500).json({ error: err.message }));
  req.pipe(bb);
});

// ── Zip selected files / folders ──────────────────────────
router.post('/zip', authMw, async (req, res) => {
  const { files, dest } = req.body;
  if (!files || !files.length || !dest) return res.status(400).json({ error: 'files and dest required' });
  try {
    const archive = archiver('zip', { zlib: { level: 6 } });
    const output  = fs.createWriteStream(dest);
    await new Promise((resolve, reject) => {
      output.on('close', resolve);
      archive.on('error', reject);
      archive.pipe(output);
      files.forEach(f => {
        try {
          const stat = fs.statSync(f);
          if (stat.isDirectory()) archive.directory(f, path.basename(f));
          else archive.file(f, { name: path.basename(f) });
        } catch (_) {}
      });
      archive.finalize();
    });
    writeAudit(req, 'files.zip', dest);
    res.json({ ok: true, dest });
  } catch (e) {
    res.status(500).json({ error: e.message });
  }
});

// ── Unzip a .zip file ──────────────────────────────────────
router.post('/unzip', authMw, async (req, res) => {
  const { file, dest } = req.body;
  if (!file || !dest) return res.status(400).json({ error: 'file and dest required' });
  let unzipper;
  try { unzipper = require('unzipper'); }
  catch { return res.status(500).json({ error: 'unzipper not installed. Run: npm install unzipper' }); }
  try {
    await fs.createReadStream(file)
      .pipe(unzipper.Extract({ path: dest }))
      .promise();
    writeAudit(req, 'files.unzip', file + ' → ' + dest);
    res.json({ ok: true });
  } catch (e) {
    res.status(500).json({ error: e.message });
  }
});

// ── Hide / unhide ──────────────────────────────────────────
router.post('/hide', authMw, (req, res) => {
  const { path: filePath, hidden } = req.body;
  if (!filePath) return res.status(400).json({ error: 'path required' });
  try {
    execSync(`attrib ${hidden ? '+H' : '-H'} "${filePath}"`, { windowsHide: true, timeout: 5000 });
    writeAudit(req, hidden ? 'files.hide' : 'files.unhide', filePath);
    res.json({ ok: true });
  } catch (e) {
    res.status(500).json({ error: e.message });
  }
});

// ── Lock / unlock (read-only) ──────────────────────────────
router.post('/lock', authMw, (req, res) => {
  const { path: filePath, locked } = req.body;
  if (!filePath) return res.status(400).json({ error: 'path required' });
  try {
    execSync(`attrib ${locked ? '+R' : '-R'} "${filePath}"`, { windowsHide: true, timeout: 5000 });
    writeAudit(req, locked ? 'files.lock' : 'files.unlock', filePath);
    res.json({ ok: true });
  } catch (e) {
    res.status(500).json({ error: e.message });
  }
});

module.exports = router;
