const express = require('express');
const fs = require('fs');
const path = require('path');
const config = require('../utils/config.js');
const { requireAuth } = require('../utils/middleware.js');

const PATHS = {
  FRONTEND_DATA: path.join(__dirname, '../../frontend/data'),
  BASE_DIR: path.join(__dirname, '../../frontend/data')
};

const themeRoutes = require('./theme.js');
const themesRoutes = require('./themes.js');
const authRoutes = require('./auth-routes.js');
const taskRoutes = require('./task-routes.js');
const serviceRoutes = require('./service-routes.js');
const setupRoutes = require('./setup-routes.js');
const systemRoutes = require('./system-routes.js');
const { testConnection } = require('../utils/mail.js');

module.exports = {
  setup: (app) => {
    // Auth routes — public (no requireAuth)
    app.use('/api/auth', authRoutes);
    // Theme discovery is public so the login overlay can pick the right
    // palette before the user logs in.
    app.use('/api/themes', themesRoutes);

    // Protected API routes
    app.use('/api/theme', requireAuth, themeRoutes);
    app.use('/api/tasks', taskRoutes); // requireAuth applied per-route inside
    app.use('/api/apps', serviceRoutes); // requireAuth applied per-route inside
    app.use('/api/setup', setupRoutes); // requireAuth applied per-route inside
    app.use('/api/system', requireAuth, systemRoutes); // live host metrics (/proc)
    app.post('/api/test-mail-connection', requireAuth, testConnection);

    app.post('/api/gluetun/mullvad-wireguard', requireAuth, async (req, res) => {
      try {
        const account = String(req.body?.accountNumber || '').replace(/\s+/g, '');
        if (!/^\d{16}$/.test(account)) {
          return res.status(400).json({ success: false, error: 'Account number must be 16 digits.' });
        }

        const cryptoMod = require('crypto');
        const kp = cryptoMod.generateKeyPairSync('x25519');
        const pkcs8 = kp.privateKey.export({ format: 'der', type: 'pkcs8' });
        const spki = kp.publicKey.export({ format: 'der', type: 'spki' });
        const privateKey = pkcs8.subarray(pkcs8.length - 32).toString('base64');
        const publicKey = spki.subarray(spki.length - 32).toString('base64');

        const body = new URLSearchParams({ account, pubkey: publicKey }).toString();
        const upstream = await fetch('https://api.mullvad.net/wg/', {
          method: 'POST',
          headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
          body
        });
        const text = (await upstream.text()).trim();

        if (!upstream.ok || !text) {
          return res.status(502).json({
            success: false,
            error: text || `Mullvad API returned ${upstream.status}.`
          });
        }
        if (/account/i.test(text) && /(invalid|not.*found|expired)/i.test(text)) {
          return res.status(400).json({ success: false, error: text });
        }

        const ipv4Only = text
          .split(',')
          .map((s) => s.trim())
          .filter((s) => /^\d+\.\d+\.\d+\.\d+\/\d+$/.test(s))
          .join(',');

        res.json({
          success: true,
          privateKey,
          publicKey,
          addresses: ipv4Only || text
        });
      } catch (error) {
        res.status(500).json({ success: false, error: error.message });
      }
    });

    app.post('/write-file', requireAuth, async (req, res) => {
      try {
        const { path: filePath, content } = req.body;
        const fsPromises = require('fs').promises;
        const pathModule = require('path');

        const fullPath = pathModule.join(PATHS.FRONTEND_DATA, filePath);
        if (!fullPath.startsWith(PATHS.BASE_DIR)) {
          return res.status(403).json({ success: false, error: 'Access denied' });
        }

        const dir = pathModule.dirname(fullPath);
        if (!fs.existsSync(dir)) {
          fs.mkdirSync(dir, { recursive: true });
        }

        await fsPromises.writeFile(fullPath, content, 'utf8');
        res.json({ success: true });
      } catch (error) {
        res.status(500).json({ success: false, error: error.message });
      }
    });

    app.get('/read-file', requireAuth, (req, res) => {
      try {
        const { path: filePath, position } = req.query;
        const pathModule = require('path');

        const fullPath = pathModule.join(PATHS.FRONTEND_DATA, filePath);
        if (!fullPath.startsWith(PATHS.BASE_DIR)) {
          return res.status(403).json({ success: false, error: 'Access denied' });
        }

        const fsPromises = require('fs').promises;

        const handleReadError = (error) => {
          if (error.code === 'ENOENT') {
            return res.status(404).json({ success: false, error: 'File not found' });
          }
          res.status(500).json({ success: false, error: error.message });
        };

        if (position !== undefined) {
          const pos = parseInt(position) || 0;
          fsPromises.readFile(fullPath, 'utf8')
            .then(data => res.send(data.substring(pos)))
            .catch(handleReadError);
        } else {
          fsPromises.readFile(fullPath, 'utf8')
            .then(data => res.send(data))
            .catch(handleReadError);
        }
      } catch (error) {
        res.status(500).json({ success: false, error: error.message });
      }
    });

    // Batch task loading
    app.post('/read-tasks-batch', requireAuth, async (req, res) => {
      try {
        const { taskIds } = req.body;
        const fsPromises = require('fs').promises;

        if (!Array.isArray(taskIds)) {
          return res.status(400).json({ success: false, error: 'taskIds must be an array' });
        }

        const loadPromises = taskIds.map(async (taskId) => {
          try {
            const taskFilePath = path.join(PATHS.FRONTEND_DATA, 'tasks', `${taskId}.json`);
            const taskData = await fsPromises.readFile(taskFilePath, 'utf8');
            return JSON.parse(taskData);
          } catch {
            return null;
          }
        });

        const results = await Promise.all(loadPromises);
        res.json(results.filter(Boolean));
      } catch (error) {
        res.status(500).json({ success: false, error: error.message });
      }
    });

    // Directory listing
    app.get('/read-directory', requireAuth, (req, res) => {
      try {
        const { path: dirPath } = req.query;
        const fullPath = path.join(PATHS.FRONTEND_DATA, dirPath);

        if (!fullPath.startsWith(PATHS.BASE_DIR)) {
          return res.status(403).json({ success: false, error: 'Access denied' });
        }

        try {
          const stats = fs.statSync(fullPath);
          if (!stats.isDirectory()) {
            return res.status(400).json({ success: false, error: 'Not a directory' });
          }
        } catch {
          return res.status(404).json({ success: false, error: 'Directory not found' });
        }

        fs.readdir(fullPath, (err, files) => {
          if (err) return res.status(500).json({ success: false, error: err.message });
          res.json(files || []);
        });
      } catch (error) {
        res.status(500).json({ success: false, error: error.message });
      }
    });

    // File delete (task files only)
    app.post('/delete-file', requireAuth, async (req, res) => {
      try {
        const { path: filePath } = req.body;
        const pathModule = require('path');
        const fsPromises = require('fs').promises;

        const fullPath = pathModule.join(PATHS.FRONTEND_DATA, filePath);
        if (!fullPath.startsWith(PATHS.BASE_DIR)) {
          return res.status(403).json({ success: false, error: 'Access denied' });
        }

        if (!filePath.startsWith('task_') || !filePath.endsWith('.json')) {
          return res.status(403).json({ success: false, error: 'Only task files can be deleted' });
        }

        await fsPromises.unlink(fullPath);
        res.json({ success: true });
      } catch (error) {
        res.status(500).json({ success: false, error: error.message });
      }
    });

    // SPA fallback — must be last
    app.get('*', (req, res) => {
      res.sendFile(path.join(config.FRONTEND_PATH, 'index.html'));
    });
  }
};
