import express, { Application, Request, Response } from 'express';
import cors from 'cors';
import helmet from 'helmet';
import rateLimit from 'express-rate-limit';
import path from 'path';
import environment from './config/environment';
import logger from './utils/logger';
import { errorHandler, notFoundHandler } from './middleware/error.middleware';
import { requestTimeout } from './middleware/request-timeout.middleware';
import { authenticate } from './middleware/auth.middleware';

const app: Application = express();

// Trust proxy (required for correct IP detection behind Traefik/Nginx)
app.set('trust proxy', 1);

// Security middleware
app.use(helmet());

// CORS configuration
app.use(cors({
  origin: environment.cors.origin,
  credentials: true,
}));

// Rate limiting - general API routes (applied below, after auth limiter)

// Rate limiting - auth routes (generous to avoid blocking logins during
// normal use; each OAuth flow = 1 callback + token exchange)
const authLimiter = rateLimit({
  windowMs: 15 * 60 * 1000, // 15 minutes
  max: 60, // 60 auth attempts per window (allows ~20 full login cycles)
  message: 'Zu viele Anmeldeversuche. Bitte versuchen Sie es später erneut.',
  standardHeaders: true,
  legacyHeaders: false,
});

app.use('/api/auth', authLimiter);
// General rate limiter — skip auth routes (own limiter above) and authenticated
// requests (Bearer token present). Auth middleware validates the token downstream;
// rate-limiting authenticated dashboard polling would cause 429 floods.
app.use('/api', rateLimit({
  windowMs: environment.rateLimit.windowMs,
  max: environment.rateLimit.max,
  message: 'Too many requests from this IP, please try again later.',
  standardHeaders: true,
  legacyHeaders: false,
  skip: (req) => {
    if (req.path.startsWith('/auth')) return true;
    const auth = req.headers.authorization;
    return typeof auth === 'string' && auth.startsWith('Bearer ');
  },
}));

// Body parsing middleware
app.use(express.json({ limit: '10mb' }));
app.use(express.urlencoded({ extended: true, limit: '10mb' }));

// Request timeout middleware
app.use(requestTimeout);

// Request logging middleware
app.use((req: Request, _res: Response, next) => {
  logger.info('Incoming request', {
    method: req.method,
    path: req.path,
    ip: req.ip,
  });
  next();
});

// Health check endpoint
app.get('/health', (_req: Request, res: Response) => {
  res.status(200).json({
    status: 'ok',
    timestamp: new Date().toISOString(),
    uptime: process.uptime(),
    environment: environment.nodeEnv,
  });
});

// API routes
import authRoutes      from './routes/auth.routes';
import userRoutes      from './routes/user.routes';
import memberRoutes    from './routes/member.routes';
import adminRoutes     from './routes/admin.routes';
import trainingRoutes  from './routes/training.routes';
import vehicleRoutes   from './routes/vehicle.routes';
import incidentRoutes  from './routes/incident.routes';
import equipmentRoutes from './routes/equipment.routes';
import nextcloudRoutes   from './routes/nextcloud.routes';
import atemschutzRoutes  from './routes/atemschutz.routes';
import eventsRoutes      from './routes/events.routes';
import bookingRoutes     from './routes/booking.routes';
import notificationRoutes from './routes/notification.routes';
import bookstackRoutes   from './routes/bookstack.routes';
import vikunjaRoutes     from './routes/vikunja.routes';
import bestellungRoutes  from './routes/bestellung.routes';
import configRoutes      from './routes/config.routes';
import serviceMonitorRoutes from './routes/serviceMonitor.routes';
import settingsRoutes       from './routes/settings.routes';
import bannerRoutes         from './routes/banner.routes';
import permissionRoutes     from './routes/permission.routes';
import ausruestungsanfrageRoutes from './routes/ausruestungsanfrage.routes';
import issueRoutes             from './routes/issue.routes';
import buchungskategorieRoutes from './routes/buchungskategorie.routes';
import checklistRoutes         from './routes/checklist.routes';
import fahrzeugTypRoutes       from './routes/fahrzeugTyp.routes';
import ausruestungTypRoutes    from './routes/ausruestungTyp.routes';
import buchhaltungRoutes        from './routes/buchhaltung.routes';
import personalEquipmentRoutes  from './routes/personalEquipment.routes';
import toolConfigRoutes         from './routes/toolConfig.routes';
import scheduledMessagesRoutes  from './routes/scheduledMessages.routes';

app.use('/api/auth',        authRoutes);
app.use('/api/user',        userRoutes);
app.use('/api/members',     memberRoutes);
app.use('/api/admin',       adminRoutes);
app.use('/api/training',    trainingRoutes);
app.use('/api/vehicles',    vehicleRoutes);
app.use('/api/incidents',   incidentRoutes);
app.use('/api/equipment',   equipmentRoutes);
app.use('/api/atemschutz',  atemschutzRoutes);
app.use('/api/nextcloud/talk', nextcloudRoutes);
app.use('/api/events',      eventsRoutes);
app.use('/api/bookings',    bookingRoutes);
app.use('/api/notifications', notificationRoutes);
app.use('/api/bookstack',   bookstackRoutes);
app.use('/api/vikunja',    vikunjaRoutes);
app.use('/api/bestellungen', bestellungRoutes);
app.use('/api/config',     configRoutes);
app.use('/api/admin',      serviceMonitorRoutes);
app.use('/api/admin/settings', settingsRoutes);
app.use('/api/settings',       settingsRoutes);
app.use('/api/banners',        bannerRoutes);
app.use('/api/permissions',    permissionRoutes);
app.use('/api/ausruestungsanfragen', ausruestungsanfrageRoutes);
app.use('/api/issues',            issueRoutes);
app.use('/api/buchungskategorien', buchungskategorieRoutes);
app.use('/api/checklisten',       checklistRoutes);
app.use('/api/fahrzeug-typen',    fahrzeugTypRoutes);
app.use('/api/ausruestung-typen', ausruestungTypRoutes);
app.use('/api/buchhaltung',      buchhaltungRoutes);
app.use('/api/persoenliche-ausruestung', personalEquipmentRoutes);
app.use('/api/admin/tools',            toolConfigRoutes);
app.use('/api/scheduled-messages',     scheduledMessagesRoutes);

// Static file serving for uploads (authenticated)
const uploadsDir = process.env.NODE_ENV === 'production' ? '/app/uploads' : path.resolve(__dirname, '../../uploads');
app.use('/uploads', authenticate, express.static(uploadsDir));

// 404 handler
app.use(notFoundHandler);

// Error handling middleware (must be last)
app.use(errorHandler);

export default app;
