/**
 * File routes — /api/files, /api/file, upload, export
 */
import fs from 'fs';
import path from 'path';
import os from 'os';
import { exec } from 'child_process';
import { resolveSeedWorkflowDir } from '../../utils/bundle-paths.js';
import { ensureProjectProfile } from '../helpers.js';

function resolveUserPath(inputPath) {
  if (!inputPath || typeof inputPath !== 'string') return '';
  const expanded = inputPath.startsWith('~')
    ? path.join(os.homedir(), inputPath.slice(1))
    : inputPath;
  return path.resolve(expanded);
}

async function reloadProjectState(server) {
  await server.projectContext.scan();
  if (server.symbolIndex) await server.symbolIndex.build().catch(() => {});
  if (server.blueprintContext) await server.blueprintContext.load().catch(() => {});
}

export async function clearImportedProjectTargets(workDir) {
  const projectDirs = ['Apps', 'Sections', 'ExtComponents', 'Services', 'Database', 'Theme', 'Process', 'Config'];
  for (const dirName of projectDirs) {
    const dirPath = path.join(workDir, dirName);
    if (fs.existsSync(dirPath)) {
      await fs.promises.rm(dirPath, { recursive: true, force: true });
    }
  }

  for (const fileName of ['VL.md']) {
    const filePath = path.join(workDir, fileName);
    if (fs.existsSync(filePath)) {
      await fs.promises.rm(filePath, { force: true });
    }
  }
}

export function setupFileRoutes(app, server) {
  // --- File tree ---
  app.get('/api/files', async (req, res) => {
    if (!server.hasSelectedWorkspace()) {
      return res.json({ tree: {}, files: [], workDir: '' });
    }
    // Always scan disk for fresh results (file tree must reflect actual files on disk)
    const workDir = server.config.workDir;
    const tree = {};  // { "Apps": ["Main.vx"], "Process/Specs": ["Intent.json"], "root": ["readme.md"] }
    const all = [];

    async function walkDir(dir, relDir) {
      let entries;
      try { entries = await fs.promises.readdir(dir, { withFileTypes: true }); } catch { return; }
      for (const entry of entries) {
        const name = entry.name;
        // Skip hidden dirs except .vl-code
        if (name.startsWith('.') && name !== '.vl-code') continue;
        if (name === 'node_modules' || name === '.git') continue;
        const fullPath = path.join(dir, name);
        const relPath = relDir ? `${relDir}/${name}` : name;
        if (entry.isDirectory()) {
          await walkDir(fullPath, relPath);
        } else {
          const ext = name.split('.').pop()?.toLowerCase() || '';
          const vlExts = { vx: 'app', sc: 'section', cp: 'component', vs: 'service', vdb: 'database', vth: 'theme' };
          const type = vlExts[ext] || ext;
          let size = 0;
          try { const stat = await fs.promises.stat(fullPath); size = stat.size; } catch {}
          all.push({ path: relPath, type, name, size });
          const cat = relDir || 'root';
          if (!tree[cat]) tree[cat] = [];
          tree[cat].push(name);
        }
      }
    }

    await walkDir(workDir, '');
    res.json({ tree, files: all, workDir });
  });

  // --- Raw file (images, binary) ---
  app.get('/api/file/raw', (req, res) => {
    if (!server.hasSelectedWorkspace()) return res.status(404).json({ error: 'No workspace selected' });
    const filePath = req.query.path;
    if (!filePath) return res.status(400).json({ error: 'path required' });
    const fullPath = path.resolve(server.config.workDir, filePath);
    if (!fs.existsSync(fullPath)) return res.status(404).json({ error: 'File not found' });
    res.sendFile(fullPath);
  });

  // --- Read file ---
  app.get('/api/file', async (req, res) => {
    if (!server.hasSelectedWorkspace()) return res.status(404).json({ error: 'No workspace selected' });
    const filePath = req.query.path;
    if (!filePath) return res.status(400).json({ error: 'path required' });
    const fullPath = path.resolve(server.config.workDir, filePath);
    try {
      const content = await fs.promises.readFile(fullPath, 'utf-8');
      res.json({ path: filePath, content });
    } catch (e) {
      res.status(404).json({ error: e.message });
    }
  });

  // --- Delete file ---
  app.delete('/api/file', async (req, res) => {
    if (!server.hasSelectedWorkspace()) return res.status(400).json({ error: 'No workspace selected' });
    const filePath = req.body?.path || req.query?.path;
    if (!filePath) return res.status(400).json({ error: 'path required' });
    const fullPath = path.resolve(server.config.workDir, filePath);
    try {
      await fs.promises.unlink(fullPath);
      // Remove empty parent dirs
      let dir = path.dirname(fullPath);
      while (dir !== server.config.workDir) {
        const entries = await fs.promises.readdir(dir);
        if (entries.length > 0) break;
        await fs.promises.rmdir(dir);
        dir = path.dirname(dir);
      }
      res.json({ ok: true });
    } catch (e) {
      res.status(500).json({ error: e.message });
    }
  });

  // --- Clear all project files ---
  app.post('/api/files/clear', async (req, res) => {
    if (!server.hasSelectedWorkspace()) return res.status(400).json({ error: 'No workspace selected' });
    const vlDirs = ['Apps', 'Sections', 'ExtComponents', 'Services', 'Database', 'Theme', 'Process'];
    let cleared = 0;
    for (const dir of vlDirs) {
      const dirPath = path.join(server.config.workDir, dir);
      if (fs.existsSync(dirPath)) {
        try {
          await fs.promises.rm(dirPath, { recursive: true });
          cleared++;
        } catch {}
      }
    }
    await reloadProjectState(server);
    server.broadcast({ type: 'file_tree_updated' });
    res.json({ ok: true, cleared });
  });

  // --- Write file ---
  app.post('/api/file', async (req, res) => {
    if (!server.hasSelectedWorkspace()) return res.status(400).json({ error: 'No workspace selected' });
    const { path: filePath, content } = req.body;
    if (!filePath) return res.status(400).json({ error: 'path required' });
    const fullPath = path.resolve(server.config.workDir, filePath);
    try {
      const dir = path.dirname(fullPath);
      if (!fs.existsSync(dir)) await fs.promises.mkdir(dir, { recursive: true });
      await fs.promises.writeFile(fullPath, content || '', 'utf-8');
      res.json({ ok: true, path: filePath });
    } catch (e) {
      res.status(500).json({ error: e.message });
    }
  });

  // --- Upload ZIP ---
  app.post('/api/upload-zip', async (req, res) => {
    try {
      if (!server.hasSelectedWorkspace()) return res.status(400).json({ error: 'No workspace selected' });
      const { data, filename } = req.body;
      if (!data) return res.status(400).json({ error: 'data required (base64)' });
      const { extractZipToDir } = await import('../../utils/zip-extract.js');
      const buf = Buffer.from(data, 'base64');
      const tmpPath = path.join(os.tmpdir(), `vlcode-upload-${Date.now()}.zip`);
      fs.writeFileSync(tmpPath, buf);
      await clearImportedProjectTargets(server.config.workDir);
      await extractZipToDir(tmpPath, server.config.workDir);
      fs.unlinkSync(tmpPath);
      const seedDir = resolveSeedWorkflowDir();
      ensureProjectProfile(server.config.workDir, seedDir);
      await reloadProjectState(server);
      server.broadcast({ type: 'file_tree_updated' });
      res.json({ ok: true, filename });
    } catch (e) {
      res.status(500).json({ error: e.message });
    }
  });

  // --- Upload folder ---
  app.post('/api/upload-folder', async (req, res) => {
    try {
      if (!server.hasSelectedWorkspace()) return res.status(400).json({ error: 'No workspace selected' });
      const { files } = req.body;
      if (!files?.length) return res.status(400).json({ error: 'files[] required' });
      await clearImportedProjectTargets(server.config.workDir);
      let written = 0;
      for (const f of files) {
        const fullPath = path.resolve(server.config.workDir, f.path);
        const dir = path.dirname(fullPath);
        if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
        const content = f.content.startsWith('data:') ? Buffer.from(f.content.split(',')[1], 'base64') : f.content;
        fs.writeFileSync(fullPath, content);
        written++;
      }
      const seedDir = resolveSeedWorkflowDir();
      ensureProjectProfile(server.config.workDir, seedDir);
      await reloadProjectState(server);
      server.broadcast({ type: 'file_tree_updated' });
      res.json({ ok: true, written });
    } catch (e) {
      res.status(500).json({ error: e.message });
    }
  });

  // --- Export ZIP ---
  app.get('/api/export-zip', async (req, res) => {
    try {
      if (!server.hasSelectedWorkspace()) return res.status(400).json({ error: 'No workspace selected' });
      const { createZipFromDir } = await import('../../utils/zip-extract.js');
      const zipBuf = await createZipFromDir(server.config.workDir);
      const name = path.basename(server.config.workDir) + '.zip';
      res.setHeader('Content-Type', 'application/zip');
      res.setHeader('Content-Disposition', `attachment; filename="${name}"`);
      res.send(zipBuf);
    } catch (e) {
      res.status(500).json({ error: e.message });
    }
  });

  // --- Browse directory ---
  app.get('/api/browse-dir', (req, res) => {
    try {
      const dirPath = req.query.path || os.homedir();
      const resolved = resolveUserPath(dirPath);
      if (!fs.existsSync(resolved)) return res.status(404).json({ error: 'Not found' });
      const stat = fs.statSync(resolved);
      if (!stat.isDirectory()) return res.status(400).json({ error: 'Not a directory' });

      const entries = fs.readdirSync(resolved, { withFileTypes: true });
      const dirs = [];
      for (const entry of entries) {
        if (!entry.isDirectory()) continue;
        if (entry.name.startsWith('.') && entry.name !== '.vl-code') continue;
        try {
          fs.accessSync(path.join(resolved, entry.name), fs.constants.R_OK);
          let isVL = false;
          try {
            const sub = fs.readdirSync(path.join(resolved, entry.name));
            isVL = sub.some(f => f.endsWith('.vx') || f === '.vl-code' || f === 'Apps');
          } catch {}
          dirs.push({ name: entry.name, path: path.join(resolved, entry.name), isVL });
        } catch {}
      }
      dirs.sort((a, b) => {
        if (a.isVL !== b.isVL) return a.isVL ? -1 : 1;
        return a.name.localeCompare(b.name);
      });
      res.json({ current: resolved, parent: path.dirname(resolved), dirs, sep: path.sep });
    } catch (e) {
      res.status(500).json({ error: e.message });
    }
  });

  // --- Open folder in system file manager ---
  app.post('/api/open-folder', (req, res) => {
    if (!server.hasSelectedWorkspace()) return res.status(400).json({ error: 'No workspace selected' });
    const folderPath = resolveUserPath(req.body.path || server.config.workDir);
    const cmd = process.platform === 'darwin' ? `open "${folderPath}"` :
                process.platform === 'win32' ? `explorer "${folderPath}"` :
                `xdg-open "${folderPath}"`;
    exec(cmd, (err) => {
      if (err) return res.status(500).json({ error: err.message });
      res.json({ ok: true });
    });
  });

  // --- File autocomplete for @-mention ---
  app.get('/api/files/autocomplete', (req, res) => {
    if (!server.hasSelectedWorkspace()) return res.json([]);
    const q = (req.query.q || '').toLowerCase();
    const files = server.projectContext.getAllFiles();
    const matches = files.filter(f => f.name.toLowerCase().includes(q) || f.path.toLowerCase().includes(q)).slice(0, 20);
    res.json(matches.map(f => ({ name: f.name, path: f.path, type: f.type })));
  });

  // --- Mentions (files + symbols) ---
  app.get('/api/mentions', (req, res) => {
    const q = (req.query.q || '').toLowerCase();
    const files = server.projectContext.getAllFiles()
      .filter(f => f.name.toLowerCase().includes(q) || f.path.toLowerCase().includes(q))
      .slice(0, 10).map(f => ({ name: f.name, path: f.path, type: 'file', fileType: f.type }));
    let symbols = [];
    if (server.symbolIndex) {
      const allSymbols = server.symbolIndex.getAllSymbols?.() || [];
      symbols = allSymbols.filter(s => s.name.toLowerCase().includes(q))
        .slice(0, 10).map(s => ({ name: s.name, path: s.file, type: 'symbol', symbolType: s.type }));
    }
    res.json([...files, ...symbols]);
  });
}
