import express from 'express'
import cors, { type CorsOptions } from 'cors'
import helmet from 'helmet'
import morgan from 'morgan'
import swaggerUi from 'swagger-ui-express'
import { openApiDocument } from './swagger/openapi'
import { getPublicStorageRoot } from './lib/storage'
import { authLimiter, apiLimiter, publicLimiter, adminLimiter } from './middleware/rateLimiter'
import { requestIdMiddleware } from './middleware/requestId'

// ─── Module routes ────────────────────────────────────────────
import webhookRouter       from './modules/webhooks/webhook.routes'
import companyAuthRouter   from './modules/auth/auth.company.routes'
import employeeAuthRouter  from './modules/auth/auth.employee.routes'
import accountAuthRouter   from './modules/auth/auth.account.routes'
import renterAuthRouter    from './modules/auth/auth.renter.routes'
import teamRouter          from './modules/team/team.routes'
import offersRouter        from './modules/offers/offer.routes'
import analyticsRouter     from './modules/analytics/analytics.routes'
import notificationsRouter from './modules/notifications/notification.routes'
import adminRouter         from './modules/admin/admin.routes'
import subscriptionsRouter, {
  subscriptionPublicRouter,
  subscriptionWebhookRouter,
} from './modules/subscriptions/subscription.routes'
import paymentsRouter      from './modules/payments/payment.routes'
import billingRouter       from './modules/billing/billing.routes'
import customersRouter     from './modules/customers/customer.routes'
import vehiclesRouter      from './modules/vehicles/vehicle.routes'
import companiesRouter     from './modules/companies/company.routes'
import reservationsRouter  from './modules/reservations/reservation.routes'
import carplaceRouter      from './modules/carplace/carplace.routes'
import siteRouter          from './modules/site/site.routes'
import reviewsRouter       from './modules/reviews/review.routes'
import complaintsRouter    from './modules/complaints/complaint.routes'
import licenseValidationRouter from './modules/licenses/license.validation.routes'

// ─── Centralized error handling ───────────────────────────────
import { errorMiddleware } from './http/errors/errorMiddleware'

const v1 = '/api/v1'

const defaultCorsOrigins = [
  'http://localhost:3000',
  'http://localhost:3001',
  'http://localhost:3002',
  'http://localhost:4000',
  'http://127.0.0.1:3000',
  'http://127.0.0.1:3001',
  'http://127.0.0.1:3002',
  'http://127.0.0.1:4000',
]

export const corsOrigins = process.env.CORS_ORIGINS
  ? process.env.CORS_ORIGINS.split(',').map((o) => o.trim()).filter(Boolean)
  : defaultCorsOrigins

function isAllowedLocalDevOrigin(origin: string) {
  if (process.env.NODE_ENV === 'production') return false

  try {
    const url = new URL(origin)
    return (
      url.protocol === 'http:' &&
      ['localhost', '127.0.0.1'].includes(url.hostname) &&
      ['3000', '3001', '3002', '4000'].includes(url.port)
    )
  } catch {
    return false
  }
}

export function isCorsOriginAllowed(origin: string | undefined) {
  if (!origin) return true
  return corsOrigins.includes(origin) || isAllowedLocalDevOrigin(origin)
}

export const corsOptions: CorsOptions = {
  origin(origin, callback) {
    callback(null, isCorsOriginAllowed(origin))
  },
  credentials: true,
}

const routeDocs = [
  { method: 'GET',  path: '/health',                         description: 'Health check' },
  { method: 'GET',  path: `${v1}/docs`,                      description: 'Machine-readable API index' },
  { method: 'GET',  path: `${v1}/auth/renter/me`,            description: 'Current renter profile' },
  { method: 'GET',  path: `${v1}/vehicles`,                  description: 'List company vehicles' },
  { method: 'POST', path: `${v1}/vehicles`,                  description: 'Create vehicle' },
  { method: 'GET',  path: `${v1}/reservations`,              description: 'List reservations' },
  { method: 'POST', path: `${v1}/reservations`,              description: 'Create reservation' },
  { method: 'GET',  path: `${v1}/customers`,                 description: 'List customers' },
  { method: 'POST', path: `${v1}/customers`,                 description: 'Create customer' },
  { method: 'GET',  path: `${v1}/offers`,                    description: 'List offers' },
  { method: 'GET',  path: `${v1}/analytics/dashboard`,       description: 'Dashboard analytics' },
  { method: 'GET',  path: `${v1}/analytics/report`,          description: 'Analytics report' },
  { method: 'GET',  path: `${v1}/notifications/company`,     description: 'Company notifications' },
  { method: 'GET',  path: `${v1}/carplace/home`,             description: 'Carplace home' },
  { method: 'GET',  path: `${v1}/carplace/search`,           description: 'Carplace paginated vehicle search' },
  { method: 'POST', path: `${v1}/carplace/quotes`,           description: 'Carplace availability and price estimate' },
  { method: 'POST', path: `${v1}/carplace/reservations`,     description: 'Create Carplace reservation request' },
  { method: 'GET',  path: `${v1}/site/:slug/brand`,          description: 'Public site brand config' },
  { method: 'GET',  path: `${v1}/companies/me`,              description: 'Current company profile' },
  { method: 'GET',  path: `${v1}/subscriptions/plans`,       description: 'Subscription plans' },
  { method: 'GET',  path: `${v1}/subscriptions/features`,    description: 'Subscription plan features' },
  { method: 'POST', path: `${v1}/admin/auth/login`,          description: 'Admin login' },
]

export function createApp() {
  const app = express()
  const corsMiddleware = cors(corsOptions)

  if (process.env.NODE_ENV === 'production') {
    app.set('trust proxy', 1)
  }

  app.use(requestIdMiddleware)

  app.use((req, res, next) => {
    if (req.headers['x-middleware-subrequest']) {
      return res.status(400).json({ error: 'bad_request', message: 'Unsupported internal request header', statusCode: 400 })
    }
    next()
  })

  app.use(corsMiddleware)

  // Customer identity documents must never be anonymously retrievable from the
  // public storage mount, even if an older raw storage URL leaks.
  app.use('/storage/companies/:companyId/customers/:customerId', (_req, res) => {
    res.status(404).end()
  })

  // Public storage assets (logos, vehicle photos, etc.) must be loadable cross-origin
  // by the browser. Without this header, helmet's default CORP: same-origin reaches
  // 404 responses (when express.static calls next() on a miss) and the browser blocks
  // the response even for broken-image cases, producing ERR_BLOCKED_BY_RESPONSE.
  app.use('/storage', (_req, res, next) => {
    res.setHeader('Cross-Origin-Resource-Policy', 'cross-origin')
    next()
  })

  // Serve only explicitly public uploaded assets. Private documents are resolved
  // through authenticated API routes such as /customers/:id/license-image.
  app.use('/storage', express.static(getPublicStorageRoot()))

  // Swagger UI — mounted before helmet so its assets are not blocked by CSP
  app.use('/docs', swaggerUi.serve, swaggerUi.setup(openApiDocument, { customSiteTitle: 'RentalDriveGo API Docs' }))
  app.get('/api/v1/openapi.json', (_req, res) => res.json(openApiDocument))

  // Webhooks must use raw body BEFORE express.json(); signature verification
  // must never reconstruct the payload with JSON.stringify(req.body).
  app.use(`${v1}/webhooks`, express.raw({ type: 'application/json' }), webhookRouter)
  app.use(`${v1}/payments/webhooks`, express.raw({ type: 'application/json' }))
  app.use(`${v1}/subscriptions/webhooks`, express.raw({ type: 'application/json' }))

  // Let /storage responses manage CORP explicitly so missing files still return
  // a normal cross-origin 404 instead of being blocked by Helmet's default
  // same-origin policy. Keep CSP explicit instead of letting browser security
  // drift into wishful thinking with headers.
  app.use(helmet({
    crossOriginResourcePolicy: false,
    contentSecurityPolicy: {
      directives: {
        defaultSrc: ["'self'"],
        baseUri: ["'self'"],
        frameAncestors: ["'none'"],
        formAction: ["'self'"],
        objectSrc: ["'none'"],
        scriptSrc: ["'self'"],
        styleSrc: ["'self'", "'unsafe-inline'"],
        imgSrc: ["'self'", 'data:', 'blob:', 'https:'],
        connectSrc: ["'self'", 'https:', 'wss:'],
        upgradeInsecureRequests: process.env.NODE_ENV === 'production' ? [] : null,
      },
    },
    referrerPolicy: { policy: 'strict-origin-when-cross-origin' },
    frameguard: { action: 'deny' },
  }))
  if (process.env.NODE_ENV !== 'test') app.use(morgan('combined'))
  app.use(express.json({ limit: '10mb' }))

  // ─── API Routes ─────────────────────────────────────────────
  app.use(`${v1}/auth/account`,   authLimiter, accountAuthRouter)
  app.use(`${v1}/auth/renter`,    authLimiter, renterAuthRouter)
  app.use(`${v1}/auth/company`,   authLimiter, companyAuthRouter)
  app.use(`${v1}/auth/employee`,  authLimiter, employeeAuthRouter)

  app.use(`${v1}/admin/auth`,     authLimiter)
  app.use(`${v1}/admin`,          adminLimiter, adminRouter)

  app.use(`${v1}/carplace`,      publicLimiter, carplaceRouter)
  app.use(`${v1}/site`,           publicLimiter, siteRouter)
  app.use(`${v1}/subscriptions`,  subscriptionPublicRouter)
  app.use(`${v1}/subscriptions`,  subscriptionWebhookRouter)

  app.use(`${v1}/vehicles`,       apiLimiter, vehiclesRouter)
  app.use(`${v1}/reservations`,   apiLimiter, reservationsRouter)
  app.use(`${v1}/team`,           apiLimiter, teamRouter)
  app.use(`${v1}/customers`,      apiLimiter, customersRouter)
  app.use(`${v1}/offers`,         apiLimiter, offersRouter)
  app.use(`${v1}/analytics`,      apiLimiter, analyticsRouter)
  app.use(`${v1}/notifications`,  apiLimiter, notificationsRouter)
  app.use(`${v1}/companies`,      apiLimiter, companiesRouter)
  app.use(`${v1}/subscriptions`,  apiLimiter, subscriptionsRouter)
  app.use(`${v1}/payments`,       apiLimiter, paymentsRouter)
  app.use(`${v1}/billing`,        apiLimiter, billingRouter)
  app.use(`${v1}/reviews`,        apiLimiter, reviewsRouter)
  app.use(`${v1}/complaints`,     apiLimiter, complaintsRouter)
  app.use(`${v1}/licenses`,       publicLimiter, licenseValidationRouter)

  // ─── Health / Docs ──────────────────────────────────────────
  app.get(v1, (_req, res) => {
    res.json({
      name: 'rentaldrivego-api',
      version: '1.0.0',
      baseUrl: v1,
      health: '/health',
      docs: `${v1}/docs`,
      openApi: `${v1}/openapi.json`,
    })
  })

  app.get('/health', (_req, res) => {
    res.json({ status: 'ok', version: '1.0.0', timestamp: new Date().toISOString() })
  })

  app.get(`${v1}/docs`, (_req, res) => {
    res.json({
      name: 'rentaldrivego-api',
      version: '1.0.0',
      baseUrl: v1,
      routes: routeDocs,
      swaggerUi: '/docs',
      openApi: '/api/v1/openapi.json',
    })
  })

  // ─── Error handler ──────────────────────────────────────────
  app.use(errorMiddleware)

  return app
}
