import 'dotenv/config'
import Fastify from 'fastify'
import { ApolloServer } from '@apollo/server'
import { fastifyApolloDrainPlugin, fastifyApolloHandler } from '@as-integrations/fastify'
import { schema } from './schema'
import { createContext } from './context'
import { authMiddleware } from './middleware/auth'
import { tenantAuthMiddleware } from './middleware/tenant-auth'
import { createWebSocketServer } from './services/websocket'
import { rateLimitMiddleware } from './middleware/rate-limit'
import { securityHeadersMiddleware, sanitizeBodyMiddleware } from './middleware/security'
import { auditMiddleware } from './middleware/audit-middleware'
import { mfaEnforcementMiddleware } from './middleware/mfa-enforcement'
import { initBlockchainService } from './services/blockchain'
import { logger } from './lib/logger'
import { validateAllSecrets } from './lib/secret-validation'
import { initializeFIPS } from './lib/crypto'
import { getFastifyTLSOptions } from './lib/tls-config'
import { registerPhoenixRailingRoutes } from './routes/phoenix-railing.js'
import { printSchema } from 'graphql'

// Get TLS configuration (empty if certificates not available)
const tlsOptions = getFastifyTLSOptions()

const fastify = Fastify({
  logger: true,
  ...tlsOptions, // Include TLS config if certificates are available
})

// Register security headers middleware
fastify.addHook('onRequest', async (request, reply) => {
  await securityHeadersMiddleware(request, reply)
})

// Register input sanitization middleware
fastify.addHook('preHandler', async (request, reply) => {
  await sanitizeBodyMiddleware(request, reply)
})

// Register rate limiting middleware
fastify.addHook('onRequest', async (request, reply) => {
  // Skip rate limiting for health check
  if (request.url === '/health') {
    return
  }
  await rateLimitMiddleware(request, reply)
})

// Register authentication middleware (skip for WebSocket upgrade)
fastify.addHook('onRequest', async (request, reply) => {
  if (request.url === '/graphql-ws' || request.url === '/health') {
    // Skip auth for WebSocket upgrade and health check
    return
  }
  await authMiddleware(request, reply)
})

// Register tenant-aware authentication middleware
fastify.addHook('onRequest', async (request, reply) => {
  if (request.url === '/graphql-ws' || request.url === '/health') {
    // Skip tenant auth for WebSocket upgrade and health check
    return
  }
  await tenantAuthMiddleware(request, reply)
})

// Register MFA enforcement middleware (DoD/MilSpec compliance)
fastify.addHook('onRequest', async (request, reply) => {
  if (request.url === '/graphql-ws' || request.url === '/health') {
    return
  }
  await mfaEnforcementMiddleware(request, reply)
})

// Register audit middleware (DoD/MilSpec compliance)
fastify.addHook('onResponse', async (request, reply) => {
  await auditMiddleware(request, reply)
})

// Create Apollo Server
const apolloServer = new ApolloServer({
  schema,
  plugins: [fastifyApolloDrainPlugin(fastify)],
})

async function startServer() {
  try {
    // Initialize FIPS 140-2 mode (DoD/MilSpec compliance)
    initializeFIPS()
    
    // Validate all secrets in production (DoD/MilSpec compliance)
    validateAllSecrets()
    
    // Initialize blockchain service
    await initBlockchainService()

    // Start Apollo Server
    await apolloServer.start()

    // Register GraphQL route
    fastify.post('/graphql', async (request, reply) => {
      return fastifyApolloHandler(apolloServer, {
        context: async () => createContext(request),
      })(request, reply)
    })

    // Health check endpoint
    fastify.get('/health', async () => {
      return { status: 'ok', timestamp: new Date().toISOString() }
    })

    // GraphQL schema export (SDL) for docs and codegen
    fastify.get('/graphql/schema', async (_request, reply) => {
      reply.type('text/plain').send(printSchema(schema))
    })

    // GraphQL Playground (interactive docs) — redirect to Apollo Sandbox or show schema link
    fastify.get('/graphql-playground', async (_request, reply) => {
      const base = process.env.PUBLIC_URL || 'http://localhost:4000'
      reply.type('text/html').send(`
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8" />
  <title>Phoenix API — GraphQL</title>
  <style>
    body { font-family: system-ui; padding: 2rem; max-width: 48rem; margin: 0 auto; }
    a { color: #0d9488; }
    code { background: #f1f5f9; padding: 0.2em 0.4em; border-radius: 4px; }
  </style>
</head>
<body>
  <h1>Phoenix API — GraphQL</h1>
  <p><strong>Endpoint:</strong> <code>${base}/graphql</code></p>
  <p><a href="${base}/graphql/schema">Schema (SDL)</a></p>
  <p>Use <a href="https://studio.apollographql.com/sandbox/explorer?endpoint=${encodeURIComponent(base + '/graphql')}" target="_blank" rel="noopener">Apollo Sandbox</a> or any GraphQL client with the endpoint above.</p>
</body>
</html>
      `)
    })

    // Phoenix API Railing: /api/v1/infra/*, /api/v1/ve/*, /api/v1/health/* proxy + /api/v1/tenants/me/*
    await registerPhoenixRailingRoutes(fastify)

    // Start Fastify server
    const port = parseInt(process.env.PORT || '4000', 10)
    const host = process.env.HOST || '0.0.0.0'

    await fastify.listen({ port, host })

    // WebSocket server needs Node HTTP server (fastify.listen returns address string in Fastify 4+)
    createWebSocketServer(fastify.server, '/graphql-ws')
    
    logger.info(`🚀 Server ready at http://${host}:${port}/graphql`)
    logger.info(`📡 WebSocket server ready at ws://${host}:${port}/graphql-ws`)
  } catch (err) {
    logger.error('Failed to start server', { error: err })
    fastify.log.error(err)
    process.exit(1)
  }
}

startServer()

