import 'dotenv/config';
import express from 'express';
import helmet from 'helmet';
import cors from 'cors';
import rateLimit from 'express-rate-limit';

import { staffbaseAuth as createStaffbaseAuth } from './middleware/staffbaseAuth';
import { devAuth } from './middleware/devAuth';
import { checkDbConnection } from './db/client';
import { logger } from './services/logger';

import matchesRouter from './routes/matches';
import tipsRouter from './routes/tips';
import leaderboardRouter from './routes/leaderboard';
import adminRouter from './routes/admin';
import profileRouter from './routes/profile';
import devRouter from './routes/dev';

const app = express();
const PORT = parseInt(process.env.PORT ?? '3001');

// ============================================================
// Security Middleware
// ============================================================
app.use(
  helmet({
    // Staffbase lädt das Plugin in einem iFrame
    // X-Frame-Options muss daher SAMEORIGIN oder ALLOW-FROM erlauben
    frameguard: false,
    contentSecurityPolicy: {
      directives: {
        defaultSrc: ["'self'"],
        scriptSrc: ["'self'"],
        styleSrc: ["'self'", "'unsafe-inline'"], // für inline styles im Frontend
        imgSrc: ["'self'", 'data:', 'https://crests.football-data.org'],
        frameAncestors: ['https://app.staffbase.com', 'https://*.staffbase.com'],
      },
    },
  })
);

// CORS – nur Staffbase Origins erlauben
const allowedOrigins = (process.env.CORS_ORIGIN ?? 'https://app.staffbase.com')
  .split(',')
  .map((o) => o.trim());

app.use(
  cors({
    origin: (origin, callback) => {
      // Requests ohne Origin (z.B. direkte API-Calls) in Development erlauben
      if (!origin && process.env.NODE_ENV !== 'production') {
        return callback(null, true);
      }
      if (!origin || allowedOrigins.some((allowed) => origin.includes(allowed.replace('https://', '')))) {
        callback(null, true);
      } else {
        callback(new Error(`CORS blocked: ${origin}`));
      }
    },
    credentials: true,
  })
);

// Body parsing
app.use(express.json({ limit: '10kb' }));

// Rate limiting – API global
app.use(
  '/api',
  rateLimit({
    windowMs: 15 * 60 * 1000, // 15 Minuten
    max: 200,                   // Max 200 Requests pro IP
    standardHeaders: true,
    legacyHeaders: false,
    message: { error: 'Too many requests', retryAfter: '15 minutes' },
  })
);

// Tighter rate limit für Tipp-Abgabe
app.use(
  '/api/tips',
  rateLimit({
    windowMs: 60 * 1000, // 1 Minute
    max: 20,
    message: { error: 'Too many tip submissions' },
  })
);

// ============================================================
// Health Check (ohne Auth – für Railway/Render/Uptime-Monitoring)
// ============================================================
app.get('/health', async (_req, res) => {
  const dbOk = await checkDbConnection();
  res.status(dbOk ? 200 : 503).json({
    status: dbOk ? 'ok' : 'degraded',
    db: dbOk ? 'connected' : 'unreachable',
    timestamp: new Date().toISOString(),
    version: process.env.npm_package_version ?? '1.0.0',
  });
});

// ============================================================
// Protected API Routes (alle erfordern Staffbase JWT)
// ============================================================
// Auth: In Development ohne JWT über devAuth, sonst Staffbase JWT
if (process.env.NODE_ENV === 'development') {
  app.use('/api', (req, res, next) => {
    // Wenn JWT vorhanden → Staffbase Auth, sonst Dev-Mode
    if (req.query.jwt || req.headers.authorization?.startsWith('Bearer ')) {
      return createStaffbaseAuth()(req, res, next);
    }
    return devAuth(req, res, next);
  });
} else {
  app.use('/api', createStaffbaseAuth());
}
app.use('/api/matches', matchesRouter);
app.use('/api/tips', tipsRouter);
app.use('/api/leaderboard', leaderboardRouter);
app.use('/api/admin', adminRouter);
app.use('/api/profile', profileRouter);
if (process.env.NODE_ENV === 'development') {
  app.use('/api/dev', devRouter);
}

// ============================================================
// Frontend (React Build) – statisches Serving
// In Production liefert das Backend auch das Frontend aus
// ============================================================
if (process.env.NODE_ENV === 'production') {
  // eslint-disable-next-line @typescript-eslint/no-var-requires
  const path = require('path') as typeof import('path');
  app.use(express.static(path.join(process.cwd(), 'public')));
  app.get('*', (_req, res) => {
    res.sendFile(path.join(process.cwd(), 'public', 'index.html'));
  });
}

// ============================================================
// Error Handler
// ============================================================
app.use(
  (
    err: Error,
    _req: express.Request,
    res: express.Response,
    _next: express.NextFunction
  ) => {
    logger.error('Unhandled error', {
      message: err.message,
      stack: err.stack,
      name: err.name,
    });
    res.status(500).json({
      error: 'Internal server error',
      message: process.env.NODE_ENV === 'development' ? err.message : undefined,
    });
  }
);

// ============================================================
// Start Server
// ============================================================
app.listen(PORT, () => {
  logger.info(`🚀 WM 2026 Tippspiel Backend running on port ${PORT}`, {
    env: process.env.NODE_ENV,
    port: PORT,
  });
});

export default app;
