import express from 'express';
import helmet from 'helmet';
import morgan from 'morgan';
import dotenv from 'dotenv';
import cookieParser from 'cookie-parser';
import { UserService } from './services/user.service';
import { SSOUserData } from './types/auth.types';
import { sequelize } from './config/database';
import { corsMiddleware } from './middlewares/cors.middleware';
import routes from './routes/index';
import { ensureUploadDir, UPLOAD_DIR } from './config/storage';
import path from 'path';

// Load environment variables
dotenv.config();

const app: express.Application = express();
const userService = new UserService();

// Initialize database connection
const initializeDatabase = async () => {
  try {
    await sequelize.authenticate();
  } catch (error) {
    console.error('❌ Database connection failed:', error);
  }
};

// Initialize database
initializeDatabase();

// Trust proxy - Enable this when behind a reverse proxy (nginx, load balancer, etc.)
// This allows Express to read X-Forwarded-* headers correctly
// Set to true in production, false in development
if (process.env.TRUST_PROXY === 'true' || process.env.NODE_ENV === 'production') {
  app.set('trust proxy', true);
} else {
  // In development, trust first proxy (useful for local testing with nginx)
  app.set('trust proxy', 1);
}

// CORS middleware - MUST be before other middleware
app.use(corsMiddleware);

// Security middleware - Configure Helmet to work with CORS
// Get frontend URL for CSP - allow cross-origin connections in development
const frontendUrl = process.env.FRONTEND_URL || 'http://localhost:3000';
const isDevelopment = process.env.NODE_ENV !== 'production';

// Build connect-src directive - allow backend API and blob URLs
const connectSrc = ["'self'", "blob:", "data:"];
if (isDevelopment) {
  // In development, allow connections to common dev ports
  connectSrc.push("http://localhost:3000", "http://localhost:5000", "ws://localhost:3000", "ws://localhost:5000");
  // Also allow the configured frontend URL if it's a localhost URL
  if (frontendUrl.includes('localhost')) {
    connectSrc.push(frontendUrl);
  }
} else {
  // In production, only allow the configured frontend URL
  if (frontendUrl && frontendUrl !== '*') {
    const frontendOrigins = frontendUrl.split(',').map(url => url.trim()).filter(Boolean);
    connectSrc.push(...frontendOrigins);
  }
}

// Build CSP directives - conditionally include upgradeInsecureRequests
const cspDirectives: any = {
  defaultSrc: ["'self'", "blob:"],
  styleSrc: ["'self'", "'unsafe-inline'", "https://fonts.googleapis.com"],
  scriptSrc: ["'self'"],
  imgSrc: ["'self'", "data:", "https:", "blob:"],
  connectSrc: connectSrc,
  frameSrc: ["'self'", "blob:"],
  fontSrc: ["'self'", "https://fonts.gstatic.com", "data:"],
  objectSrc: ["'none'"],
  baseUri: ["'self'"],
  formAction: ["'self'"],
};

// Only add upgradeInsecureRequests in production (it forces HTTPS)
if (!isDevelopment) {
  cspDirectives.upgradeInsecureRequests = [];
}

app.use(helmet({
  crossOriginEmbedderPolicy: false,
  crossOriginResourcePolicy: { policy: "cross-origin" },
  contentSecurityPolicy: {
    directives: cspDirectives,
  },
}));

// Cookie parser middleware - MUST be before routes
app.use(cookieParser());

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

// Logging middleware
app.use(morgan('combined'));

// Health check endpoint (before API routes)
app.get('/health', (_req: express.Request, res: express.Response) => {
  res.status(200).json({ 
    status: 'OK', 
    timestamp: new Date(),
    uptime: process.uptime(),
    environment: process.env.NODE_ENV || 'development'
  });
});

// Mount API routes - MUST be before static file serving
app.use('/api/v1', routes);

// Serve uploaded files statically
ensureUploadDir();
app.use('/uploads', express.static(UPLOAD_DIR));

// Legacy SSO Callback endpoint for user creation/update (kept for backward compatibility)
app.post('/api/v1/auth/sso-callback', async (req: express.Request, res: express.Response): Promise<void> => {
  try {
    const ssoData: SSOUserData = req.body;
    
    // Validate required fields - email and oktaSub are required
    if (!ssoData.email || !ssoData.oktaSub) {
      res.status(400).json({
        success: false,
        message: 'Missing required fields: email and oktaSub are required',
        timestamp: new Date()
      });
      return;
    }

    // Create or update user
    const user = await userService.createOrUpdateUser(ssoData);
    
    res.status(200).json({
      success: true,
      message: 'User processed successfully',
      data: {
        user: {
          userId: user.userId,
          employeeId: user.employeeId || null,
          oktaSub: user.oktaSub,
          email: user.email,
          firstName: user.firstName || null,
          lastName: user.lastName || null,
          displayName: user.displayName || null,
          department: user.department || null,
          designation: user.designation || null,
          phone: user.phone || null,
          location: user.location || null,
          role: user.role,
          lastLogin: user.lastLogin
        },
        isNewUser: user.createdAt.getTime() === user.updatedAt.getTime()
      },
      timestamp: new Date()
    });
  } catch (error) {
    console.error('❌ SSO Callback failed:', error);
    res.status(500).json({
      success: false,
      message: 'Internal server error',
      timestamp: new Date()
    });
  }
});

// Get all users endpoint
app.get('/api/v1/users', async (_req: express.Request, res: express.Response): Promise<void> => {
  try {
    const users = await userService.getAllUsers();
    
    res.status(200).json({
      success: true,
      message: 'Users retrieved successfully',
      data: {
        users: users.map(user => ({
          userId: user.userId,
          employeeId: user.employeeId || null,
          oktaSub: user.oktaSub,
          email: user.email,
          firstName: user.firstName || null,
          lastName: user.lastName || null,
          displayName: user.displayName || null,
          department: user.department || null,
          designation: user.designation || null,
          phone: user.phone || null,
          location: user.location || null,
          role: user.role,
          lastLogin: user.lastLogin,
          createdAt: user.createdAt
        })),
        total: users.length
      },
      timestamp: new Date()
    });
  } catch (error) {
    console.error('❌ Get Users failed:', error);
    res.status(500).json({
      success: false,
      message: 'Internal server error',
      timestamp: new Date()
    });
  }
});

// Serve React build static files (only in production or when build folder exists)
// Check for both 'build' (Create React App) and 'dist' (Vite) folders
const buildPath = path.join(__dirname, "..", "build");
const distPath = path.join(__dirname, "..", "dist");
const fs = require('fs');

// Try to find React build directory
let reactBuildPath: string | null = null;
if (fs.existsSync(buildPath)) {
  reactBuildPath = buildPath;
} else if (fs.existsSync(distPath)) {
  reactBuildPath = distPath;
}

// Serve static files if React build exists
if (reactBuildPath && fs.existsSync(path.join(reactBuildPath, "index.html"))) {
  // Serve static assets (JS, CSS, images, etc.) - these will have CSP headers from Helmet
  app.use(express.static(reactBuildPath, {
    setHeaders: (res: express.Response, filePath: string) => {
      // Apply CSP headers to HTML files served as static files
      if (filePath.endsWith('.html')) {
        // CSP headers are already set by Helmet middleware, but ensure they're applied
        // The meta tag in index.html will also enforce CSP
      }
    }
  }));
  
  // Catch-all handler: serve React app for all non-API routes
  // This must be AFTER all API routes to avoid intercepting API requests
  app.get('*', (req: express.Request, res: express.Response): void => {
    // Don't serve React for API routes, uploads, or health check
    if (req.path.startsWith('/api/') || req.path.startsWith('/uploads/') || req.path === '/health') {
      res.status(404).json({
        success: false,
        message: `Route ${req.originalUrl} not found`,
        timestamp: new Date(),
      });
      return;
    }
    
    // Serve React app for all other routes (SPA routing)
    // This handles client-side routing in React Router
    // CSP headers from Helmet will be applied to this response
    res.sendFile(path.join(reactBuildPath!, "index.html"));
  });
} else {
  // No React build found - provide API info at root and use standard 404 handler
  app.get('/', (_req: express.Request, res: express.Response): void => {
    res.status(200).json({
      message: 'Royal Enfield Workflow Management System API',
      version: '1.0.0',
      status: 'running',
      timestamp: new Date(),
      note: 'React build not found. API is available at /api/v1'
    });
  });
  
  // Standard 404 handler for non-existent routes
  app.use((req: express.Request, res: express.Response): void => {
    res.status(404).json({
      success: false,
      message: `Route ${req.originalUrl} not found`,
      timestamp: new Date(),
    });
  });
}

export default app;