/**
 * Express Server Setup
 *
 * Configures Express application with middleware, routes, and error handling
 */

import express, { Application, Request, Response, NextFunction } from 'express';
import cors from 'cors';
import helmet from 'helmet';
import compression from 'compression';
import { config } from './config';
import { logger, httpLogStream } from './utils/logger';
import { register } from './utils/metrics';
import { authenticateAdmin } from './middleware/auth';
import morgan from 'morgan';

// Import routes
import healthRoutes from './routes/health';
import authRoutes from './routes/auth';
import translateRoutes from './routes/translate';
import jobsRoutes from './routes/jobs';
import accountRoutes from './routes/account';
import webhooksRoutes from './routes/webhooks';
import sitesRoutes from './routes/sites';
import pricingRoutes from './routes/pricing';
import subscriptionRoutes from './routes/subscription';
import estimateRoutes from './routes/estimate';
import statsRoutes from './routes/stats';
import multilingualLicenseRoutes from './routes/multilingualLicense';
import translateLicenseRoutes from './routes/translateLicense';
import onboardingRoutes from './routes/onboarding';
import updateRoutes from './routes/updates';

// Admin routes
import adminAuthRoutes from './routes/admin/auth';
import adminUsersRoutes from './routes/admin/users';
import adminTransactionsRoutes from './routes/admin/transactions';
import adminJobsRoutes from './routes/admin/jobs';
import adminAnalyticsRoutes from './routes/admin/analytics';
import adminSettingsRoutes from './routes/admin/settings';
import adminLicensesRoutes from './routes/admin/licenses';
import adminTiersRoutes from './routes/admin/tiers';
import adminWebhooksRoutes from './routes/admin/webhooks';
import adminSubscriptionsRoutes from './routes/admin/subscriptions';
import adminInvoicesRoutes from './routes/admin/invoices';
import adminDisputesRoutes from './routes/admin/disputes';
import adminTranslationWebhookOutboxRoutes from './routes/admin/translationWebhookOutbox';

export function createServer(): Application {
  const app = express();

  // Trust proxy (for accurate IP addresses behind load balancer)
  app.set('trust proxy', 1);

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

  // CORS configuration
  app.use(cors({
    origin: (origin, callback) => {
      // Allow requests with no origin (mobile apps, Postman, etc.)
      if (!origin) {
        return callback(null, true);
      }

      // Check if origin is in allowed list
      if (config.corsAllowedOrigins.includes(origin) || config.corsAllowedOrigins.includes('*')) {
        callback(null, true);
      } else {
        callback(new Error('Not allowed by CORS'));
      }
    },
    credentials: true,
    methods: ['GET', 'POST', 'PATCH', 'DELETE', 'OPTIONS'],
    allowedHeaders: ['Content-Type', 'Authorization', 'X-WP-Nonce', 'X-API-Key', 'X-Requested-With'],
  }));

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

  // Compression
  app.use(compression());

  // HTTP request logging. A license key must never reach a log line, so the
  // url token is redacted before morgan formats it.
  morgan.token('url', (req: any) =>
    String(req.originalUrl || req.url || '').replace(/([?&]license_key=)[^&]*/gi, '$1[REDACTED]')
  );
  app.use(morgan('combined', { stream: httpLogStream }));

  // Request ID middleware
  app.use((req: Request, res: Response, next: NextFunction) => {
    req.requestId = `req_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
    res.setHeader('X-Request-ID', req.requestId);
    next();
  });

  // Client IP extraction
  app.use((req: Request, _res: Response, next: NextFunction) => {
    req.clientIp = (req.headers['x-forwarded-for'] as string)?.split(',')[0] || req.ip || 'unknown';
    next();
  });

  // Public routes
  app.use('/health', healthRoutes);
  app.use('/v1/pricing', pricingRoutes); // Public pricing endpoint
  // Back-compat: public portal surface expected by WordPress plugin tests
  app.use('/pricing', pricingRoutes);

  // Public customer portal placeholder (unauthenticated for now)
  app.get('/account/licenses', (_req: Request, res: Response) => {
    res.status(200)
      .type('html')
      .send(`<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <title>Press.Zone Licenses</title>
  </head>
  <body>
    <main>
      <h1>Press.Zone Licenses</h1>
      <p>This endpoint is a public placeholder for license self-service.</p>
      <p><a href="/pricing">View pricing</a></p>
    </main>
  </body>
</html>`);
  });

  // API v1 routes
  app.use('/v1/auth', authRoutes);
  app.use('/v1/translate', translateRoutes);
  app.use('/v1/jobs', jobsRoutes);
  app.use('/v1/account', accountRoutes);
  app.use('/v1/account/subscription', subscriptionRoutes); // Subscription details endpoint
  app.use('/v1/subscriptions', accountRoutes); // Includes /plans endpoint
  app.use('/v1/webhooks', webhooksRoutes);
  app.use('/v1/sites', sitesRoutes);
  app.use('/v1/estimate', estimateRoutes); // Token estimation
  app.use('/v1/stats', statsRoutes); // Accuracy statistics

  // Multilingual Press Zone licensing (commercial plugin licensing)
  app.use('/v1/multilingual/license', multilingualLicenseRoutes);

  // Translate Press Zone licensing
  app.use('/v1/translate/license', translateLicenseRoutes);

  // International Press Zone licensing
  app.use('/v1/international/license', multilingualLicenseRoutes);

  // Plugin update delivery for international-press-zone
  app.use('/v1/international/updates', updateRoutes);


  // Onboarding (in-plugin registration + checkout)
  app.use('/v1/onboarding', onboardingRoutes);

  // Admin routes
  const adminRouter = express.Router();
  adminRouter.use('/auth', adminAuthRoutes);
  adminRouter.use('/users', adminUsersRoutes);
  adminRouter.use('/transactions', adminTransactionsRoutes);
  adminRouter.use('/jobs', adminJobsRoutes);
  adminRouter.use('/analytics', adminAnalyticsRoutes);
  adminRouter.use('/settings', adminSettingsRoutes);
  adminRouter.use('/licenses', adminLicensesRoutes);
  adminRouter.use('/tiers', adminTiersRoutes);
  adminRouter.use('/webhooks', adminWebhooksRoutes);
  adminRouter.use('/subscriptions', adminSubscriptionsRoutes);
  adminRouter.use('/invoices', adminInvoicesRoutes);
  adminRouter.use('/disputes', adminDisputesRoutes);
  adminRouter.use('/translation-webhook-outbox', adminTranslationWebhookOutboxRoutes);
  app.use('/v1/admin', adminRouter);

  // Metrics endpoint (admin only)
  app.get('/metrics', authenticateAdmin, async (_req: Request, res: Response) => {
    try {
      res.set('Content-Type', register.contentType);
      const metrics = await register.metrics();
      res.end(metrics);
    } catch {
      res.status(500).end();
    }
  });

  // 404 handler
  app.use((req: Request, res: Response) => {
    res.status(404).json({
      error: {
        code: 'NOT_FOUND',
        message: 'The requested resource was not found',
        path: req.path,
      },
    });
  });

  // Global error handler
  app.use((err: Error, req: Request, res: Response, _next: NextFunction) => {
    logger.error({
      message: err.message,
      stack: err.stack,
      requestId: req.requestId,
      path: req.path,
      method: req.method,
    });

    res.status(500).json({
      error: {
        code: 'INTERNAL_SERVER_ERROR',
        message: config.nodeEnv === 'production'
          ? 'An unexpected error occurred'
          : err.message,
        requestId: req.requestId,
      },
    });
  });

  return app;
}
