const express = require('express');
const router = express.Router();
const { authenticate, requireAdmin } = require('../middleware/auth');
const logger = require('../utils/logger');
const { db } = require('../database/db');

// Store CSP violations in database
db.run(`
  CREATE TABLE IF NOT EXISTS csp_violations (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    document_uri TEXT,
    violated_directive TEXT,
    blocked_uri TEXT,
    source_file TEXT,
    line_number INTEGER,
    column_number INTEGER,
    user_agent TEXT,
    ip_address TEXT,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
  )
`);

// CSP violation reporting endpoint (no auth required)
router.post('/report', express.json({ type: 'application/csp-report' }), (req, res) => {
  const report = req.body['csp-report'];
  const ip = req.ip || req.headers['x-forwarded-for'] || req.connection.remoteAddress;
  const userAgent = req.headers['user-agent'];

  if (!report) {
    return res.status(400).json({ error: 'Invalid CSP report' });
  }

  logger.warn('CSP Violation:', {
    documentUri: report['document-uri'],
    violatedDirective: report['violated-directive'],
    blockedUri: report['blocked-uri'],
    sourceFile: report['source-file'],
    lineNumber: report['line-number'],
    columnNumber: report['column-number'],
    ip,
    userAgent
  });

  // Store in database
  db.run(
    `INSERT INTO csp_violations 
    (document_uri, violated_directive, blocked_uri, source_file, line_number, column_number, user_agent, ip_address) 
    VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
    [
      report['document-uri'],
      report['violated-directive'],
      report['blocked-uri'],
      report['source-file'],
      report['line-number'],
      report['column-number'],
      userAgent,
      ip
    ],
    (err) => {
      if (err) {
        logger.error('Failed to store CSP violation:', err);
      }
    }
  );

  res.status(204).end();
});

// Get CSP violations (admin only)
router.get('/violations', authenticate, requireAdmin, (req, res) => {
  const { limit = 100, offset = 0 } = req.query;

  db.all(
    `SELECT * FROM csp_violations 
    ORDER BY created_at DESC 
    LIMIT ? OFFSET ?`,
    [parseInt(limit), parseInt(offset)],
    (err, violations) => {
      if (err) {
        logger.error('Failed to fetch CSP violations:', err);
        return res.status(500).json({ error: 'Failed to fetch violations' });
      }

      // Get total count
      db.get('SELECT COUNT(*) as total FROM csp_violations', (countErr, countResult) => {
        if (countErr) {
          logger.error('Failed to count CSP violations:', countErr);
          return res.status(500).json({ error: 'Failed to count violations' });
        }

        res.json({
          violations,
          total: countResult.total,
          limit: parseInt(limit),
          offset: parseInt(offset)
        });
      });
    }
  );
});

// Get CSP violation statistics (admin only)
router.get('/stats', authenticate, requireAdmin, (req, res) => {
  const { days = 7 } = req.query;
  const cutoffDate = new Date();
  cutoffDate.setDate(cutoffDate.getDate() - parseInt(days));

  Promise.all([
    // Total violations
    new Promise((resolve, reject) => {
      db.get(
        'SELECT COUNT(*) as total FROM csp_violations WHERE created_at >= ?',
        [cutoffDate.toISOString()],
        (err, row) => err ? reject(err) : resolve(row.total)
      );
    }),
    // By directive
    new Promise((resolve, reject) => {
      db.all(
        `SELECT violated_directive, COUNT(*) as count 
        FROM csp_violations 
        WHERE created_at >= ? 
        GROUP BY violated_directive 
        ORDER BY count DESC 
        LIMIT 10`,
        [cutoffDate.toISOString()],
        (err, rows) => err ? reject(err) : resolve(rows)
      );
    }),
    // By blocked URI
    new Promise((resolve, reject) => {
      db.all(
        `SELECT blocked_uri, COUNT(*) as count 
        FROM csp_violations 
        WHERE created_at >= ? 
        GROUP BY blocked_uri 
        ORDER BY count DESC 
        LIMIT 10`,
        [cutoffDate.toISOString()],
        (err, rows) => err ? reject(err) : resolve(rows)
      );
    }),
    // Recent violations
    new Promise((resolve, reject) => {
      db.all(
        `SELECT * FROM csp_violations 
        WHERE created_at >= ? 
        ORDER BY created_at DESC 
        LIMIT 20`,
        [cutoffDate.toISOString()],
        (err, rows) => err ? reject(err) : resolve(rows)
      );
    })
  ])
    .then(([total, byDirective, byUri, recent]) => {
      res.json({
        total,
        byDirective,
        byUri,
        recent,
        days: parseInt(days)
      });
    })
    .catch((err) => {
      logger.error('Failed to fetch CSP stats:', err);
      res.status(500).json({ error: 'Failed to fetch statistics' });
    });
});

// Clear old CSP violations (admin only)
router.delete('/violations', authenticate, requireAdmin, (req, res) => {
  const { days = 30 } = req.query;
  const cutoffDate = new Date();
  cutoffDate.setDate(cutoffDate.getDate() - parseInt(days));

  db.run(
    'DELETE FROM csp_violations WHERE created_at < ?',
    [cutoffDate.toISOString()],
    function(err) {
      if (err) {
        logger.error('Failed to delete old CSP violations:', err);
        return res.status(500).json({ error: 'Failed to delete violations' });
      }

      res.json({
        message: 'Old violations cleared',
        deleted: this.changes
      });
    }
  );
});

// Get current CSP policy (authenticated users)
router.get('/policy', authenticate, (req, res) => {
  const isProduction = process.env.NODE_ENV === 'production';
  
  res.json({
    mode: isProduction ? 'enforce' : 'report-only',
    policy: {
      defaultSrc: ["'self'"],
      scriptSrc: ["'self'", "'unsafe-inline'", "'unsafe-eval'", "https://www.gstatic.com"],
      styleSrc: ["'self'", "'unsafe-inline'", "https://fonts.googleapis.com"],
      fontSrc: ["'self'", "data:", "https://fonts.gstatic.com"],
      imgSrc: ["'self'", "data:", "blob:", "https:", "http:"],
      mediaSrc: ["'self'", "blob:", "data:", "mediastream:", "https:", "http:", "*"],
      connectSrc: ["'self'", "https:", "http:", "ws:", "wss:", "blob:", "*"],
      frameSrc: ["'self'", "https://www.youtube.com", "https://player.vimeo.com"],
      objectSrc: ["'none'"],
      baseUri: ["'self'"],
      formAction: ["'self'"],
      frameAncestors: ["'self'"],
      upgradeInsecureRequests: isProduction
    },
    reportUri: '/api/csp/report'
  });
});

module.exports = router;
