require('dotenv').config();

const express = require('express');
const sessionMiddleware = require('./lib/session');
const log = require('./lib/logger');
const authMiddleware = require('./lib/auth');

const app = express();
app.set('trust proxy', 1);

// Security headers
const helmet = require('helmet');
app.use(helmet({
  contentSecurityPolicy: {
    directives: {
      defaultSrc: ["'self'"],
      scriptSrc: ["'self'", "'unsafe-inline'", "https://mc.yandex.ru"],
      styleSrc: ["'self'", "'unsafe-inline'"],
      imgSrc: ["'self'", "data:", "https://mc.yandex.ru"],
      connectSrc: ["'self'", "wss:", "ws:"],
      fontSrc: ["'self'"],
      objectSrc: ["'none'"],
      frameAncestors: ["'none'"],
      baseUri: ["'self'"],
      formAction: ["'self'"],
      scriptSrcAttr: ["'unsafe-inline'"],
    },
  },
  crossOriginEmbedderPolicy: false,
}));

// Session
app.use(sessionMiddleware);

// Static assets (before auth — always public)
app.use(express.static('public'));
// Works portfolio — static HTML projects
app.use('/works', express.static('works'));

// Auth routes (before auth middleware — public)
app.use('/auth', require('./routes/auth'));

// Public API (only specific endpoints for landing page)
const apiRouter = require('./routes/api');
app.get('/api/settings', apiRouter);
app.get('/api/tools', apiRouter);
app.get('/api/content/advantages', apiRouter);
app.get('/api/content/dashboard', apiRouter);

// Public status page (before auth — no login required)
app.use('/status', require('./routes/status'));

// Auth middleware (protects everything below)
app.use(authMiddleware);

// Protected API (all other /api/* routes)
app.use('/api', apiRouter);

// Health check (extended)
const os = require('os');
const startTime = Date.now();
app.get('/health', (req, res) => {
  // Public callers get a minimal response; detailed metrics only for authenticated admins.
  const isAdmin = req.session && req.session.user && req.session.user.role === 'admin';
  if (!isAdmin) return res.json({ status: 'ok' });

  const mem = process.memoryUsage();
  const queue = require('./lib/queue');
  const wsInfo = require('./lib/ws');
  const loadavg = os.loadavg();

  res.json({
    status: 'ok',
    uptime: Math.floor((Date.now() - startTime) / 1000),
    memory: {
      rss: Math.round(mem.rss / 1024 / 1024) + 'MB',
      heap: Math.round(mem.heapUsed / 1024 / 1024) + '/' + Math.round(mem.heapTotal / 1024 / 1024) + 'MB',
      system: Math.round((1 - os.freemem() / os.totalmem()) * 100) + '%',
    },
    cpu: {
      load1m: loadavg[0].toFixed(2),
      load5m: loadavg[1].toFixed(2),
      load15m: loadavg[2].toFixed(2),
      cores: os.cpus().length,
    },
    queue: {
      stats: queue.getStats(),
      active: queue.getActiveCount(),
      pending: queue.getQueueDepth(),
    },
    ws: {
      connections: wsInfo.getConnectionCount(),
    },
    node: process.version,
    pid: process.pid,
  });
});

// Routes
const compressRouter = require('./routes/compress');
app.use('/compress', compressRouter);

// Download endpoint
const fs = require('fs');
const path = require('path');
app.get('/download/:filename', (req, res) => {
  const filename = path.basename(req.params.filename);
  const filePath = path.join(require('./lib/storage').RESULTS_DIR, filename);
  if (!fs.existsSync(filePath)) return res.status(404).json({ error: 'Файл не найден' });
  res.download(filePath, 'compressed.zip');
});

app.use(require('./routes/parser'));
app.use('/placeholder', require('./routes/placeholder'));
app.use('/placeholder-img', require('./routes/placeholder'));
app.use(require('./routes/httpclient'));
app.use(require('./routes/redirects'));
app.use(require('./routes/svgeditor'));
app.use('/video', require('./routes/video'));
app.use('/pdf', require('./routes/pdf'));
app.use('/favicon', require('./routes/favicon'));
app.use(require('./routes/pages'));

// Start server (async for AdminJS setup)
const PORT = parseInt(process.env.PORT) || 3000;

(async () => {
  // AdminJS — loaded async (ESM modules)
  try {
    const { setupAdmin } = require('./lib/admin');
    await setupAdmin(app);
    log.info('AdminJS mounted at /admin');
  } catch (err) {
    log.error('AdminJS setup failed', { error: err.message });
  }

  // Global error handler — registered AFTER AdminJS so errors thrown inside /admin are caught too.
  app.use((err, req, res, next) => {
    log.error('Unhandled error', { error: err.message, stack: err.stack });
    if (res.headersSent) return next(err);
    res.status(500).json({ error: 'Внутренняя ошибка сервера' });
  });

  const server = app.listen(PORT, () => {
    log.info(`Server started on http://localhost:${PORT}`);
  });

  // WebSocket
  const wsServer = require('./lib/ws');
  wsServer.attach(server);

  // Graceful shutdown
  function shutdown(signal) {
    log.info(`${signal} received, shutting down gracefully...`);
    server.close(() => {
      log.info('Server closed');
      process.exit(0);
    });
    setTimeout(() => {
      log.warn('Forced shutdown after timeout');
      process.exit(1);
    }, 10000);
  }

  process.on('SIGTERM', () => shutdown('SIGTERM'));
  process.on('SIGINT', () => shutdown('SIGINT'));
})();

process.on('unhandledRejection', (err) => {
  log.error('Unhandled rejection', { error: err?.message || String(err) });
});
process.on('uncaughtException', (err) => {
  log.error('Uncaught exception', { error: err.message, stack: err.stack });
  process.exit(1);
});
