const express = require('express');
const multer = require('multer');
const sharp = require('sharp');
const archiver = require('archiver');
const path = require('path');
const fs = require('fs');
const rateLimit = require('express-rate-limit');
const { RESULTS_DIR } = require('../lib/storage');
const log = require('../lib/logger');

const router = express.Router();

// ── Rate limiter ──────────────────────────────────────────────────────────────
const limiter = rateLimit({
  keyGenerator: (req) =>
    req.session && req.session.user && req.session.user.id
      ? 'user_' + req.session.user.id
      : req.ip,
  windowMs: 60000,
  max: 30,
  message: { error: 'Слишком много запросов' },
});

// ── Multer (memory storage, 5 MB, images only) ────────────────────────────────
const upload = multer({
  storage: multer.memoryStorage(),
  limits: { fileSize: 5 * 1024 * 1024 },
  fileFilter: (_req, file, cb) => {
    if (file.mimetype.startsWith('image/')) {
      cb(null, true);
    } else {
      cb(new Error('Допустимы только изображения'));
    }
  },
});

// ── Favicon sizes spec ────────────────────────────────────────────────────────
const FAVICON_SIZES = [
  { size: 16,  name: 'favicon-16x16.png',   purpose: 'ico' },
  { size: 32,  name: 'favicon-32x32.png',   purpose: 'ico' },
  { size: 48,  name: 'favicon-48x48.png',   purpose: 'ico' },
  { size: 180, name: 'apple-touch-icon.png', purpose: 'apple' },
  { size: 192, name: 'android-chrome-192x192.png', purpose: 'android' },
  { size: 512, name: 'android-chrome-512x512.png', purpose: 'android' },
];

// ── Cleanup helper ────────────────────────────────────────────────────────────
function scheduleCleanup(dirPath, delayMs = 30 * 60 * 1000) {
  setTimeout(() => {
    fs.rm(dirPath, { recursive: true, force: true }, (err) => {
      if (err) log.warn('Favicon cleanup failed', { dir: dirPath, error: err.message });
      else log.debug('Favicon temp dir removed', { dir: dirPath });
    });
  }, delayMs);
}

// ── GET / — serve page ────────────────────────────────────────────────────────
router.get('/', (req, res) => {
  res.sendFile(path.join(__dirname, '..', 'public', 'favicon.html'));
});

// ── POST /generate ────────────────────────────────────────────────────────────
router.post('/generate', limiter, upload.single('image'), async (req, res) => {
  if (!req.file) {
    return res.status(400).json({ error: 'Изображение не загружено' });
  }

  const timestamp = Date.now();
  const tempDirName = `favicon_${timestamp}`;
  const tempDir = path.join(RESULTS_DIR, tempDirName);

  try {
    fs.mkdirSync(tempDir, { recursive: true });

    // Generate all PNG sizes
    const generatedSizes = [];
    for (const spec of FAVICON_SIZES) {
      await sharp(req.file.buffer)
        .resize(spec.size, spec.size, { fit: 'cover', position: 'centre' })
        .png({ compressionLevel: 9 })
        .toFile(path.join(tempDir, spec.name));

      generatedSizes.push({ size: spec.size, filename: spec.name });
    }

    // Build site.webmanifest
    const manifestJson = {
      name: '',
      short_name: '',
      icons: [
        { src: '/android-chrome-192x192.png', sizes: '192x192', type: 'image/png' },
        { src: '/android-chrome-512x512.png', sizes: '512x512', type: 'image/png' },
      ],
      theme_color: '#ffffff',
      background_color: '#ffffff',
      display: 'standalone',
    };
    const manifestStr = JSON.stringify(manifestJson, null, 2);
    fs.writeFileSync(path.join(tempDir, 'site.webmanifest'), manifestStr);

    // Build HTML tags snippet
    const htmlTags = [
      '<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">',
      '<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">',
      '<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">',
      '<link rel="manifest" href="/site.webmanifest">',
    ].join('\n');
    fs.writeFileSync(path.join(tempDir, 'favicon-tags.html'), htmlTags);

    // Create ZIP archive
    const zipName = `favicon_${timestamp}.zip`;
    const zipPath = path.join(RESULTS_DIR, zipName);

    await new Promise((resolve, reject) => {
      const output = fs.createWriteStream(zipPath);
      const archive = archiver('zip', { zlib: { level: 9 } });

      output.on('close', resolve);
      archive.on('error', reject);

      archive.pipe(output);
      archive.directory(tempDir, false);
      archive.finalize();
    });

    // Schedule cleanup of temp dir and zip
    scheduleCleanup(tempDir);
    scheduleCleanup(zipPath);

    log.info('Favicon generated', { timestamp, sizes: generatedSizes.length });

    res.json({
      downloadUrl: `/favicon/download/${zipName}`,
      sizes: generatedSizes,
      htmlTags,
      manifestJson: manifestStr,
    });
  } catch (err) {
    log.error('Favicon generation failed', { error: err.message });
    fs.rm(tempDir, { recursive: true, force: true }, () => {});
    res.status(500).json({ error: 'Ошибка генерации favicon: ' + err.message });
  }
});

// ── GET /download/:filename ───────────────────────────────────────────────────
router.get('/download/:filename', (req, res) => {
  const filename = path.basename(req.params.filename);

  // Allow only favicon zip files to prevent path traversal
  if (!/^favicon_\d+\.zip$/.test(filename)) {
    return res.status(400).json({ error: 'Недопустимое имя файла' });
  }

  const filePath = path.join(RESULTS_DIR, filename);
  if (!fs.existsSync(filePath)) {
    return res.status(404).json({ error: 'Файл не найден или истёк срок хранения' });
  }

  res.download(filePath, 'favicon-pack.zip');
});

// ── Multer error handler ──────────────────────────────────────────────────────
router.use((err, req, res, next) => {
  if (err.code === 'LIMIT_FILE_SIZE') {
    return res.status(413).json({ error: 'Файл слишком большой. Максимум 5 МБ.' });
  }
  if (err.message === 'Допустимы только изображения') {
    return res.status(415).json({ error: err.message });
  }
  next(err);
});

module.exports = router;
