/**
 * Fastify Server Generator
 *
 * Generates main Fastify server bootstrap file
 */

import type { TemplateContext } from '@specverse/types';
import { normalizeSpec, deriveBasePath } from '@specverse/types/spec-rules';

export default function generateFastifyServer(context: TemplateContext): string {
  const { spec, models } = context;

  // Extract model names for route registration
  const allModels = models || (spec?.models ? Object.values(spec.models) : []);
  const modelNames = allModels.map((m: any) => m.name).filter(Boolean);

  // Generate route imports and registrations
  const routeImports = modelNames.map((name: string) =>
    `import ${name}Routes from './routes/${name}Controller.js';`
  ).join('\n');

  const routeRegistrations = modelNames.map((name: string) => {
    const path = deriveBasePath(name);
    return `  await fastify.register(${name}Routes, { prefix: '${path}', controllers: { ${name}Controller: new (await import('./controllers/${name}Controller.js')).${name}Controller() } });`;
  }).join('\n');

  // Check for events in spec
  const specEvents = spec.events ? Object.keys(spec.events) : [];
  const hasEvents = specEvents.length > 0 || modelNames.length > 0;

  // Service imports (the singleton instances from services/{Name}.ts)
  // Each service has `/services/{Name}.ts` → `export default {name}Service`
  // Each service also gets a routes file at `/routes/{Name}Routes.ts`.
  const servicesList = spec.services ? Object.keys(spec.services) : [];
  const serviceSingletonImports = servicesList.map((name: string) => {
    const lower = name.charAt(0).toLowerCase() + name.slice(1);
    return `import ${lower} from './services/${name}.js';`;
  }).join('\n');
  const serviceRouteImports = servicesList.map((name: string) =>
    `import ${name}Routes from './routes/${name}Routes.js';`
  ).join('\n');
  const serviceRouteRegistrations = servicesList.map((name: string) => {
    const lower = name.charAt(0).toLowerCase() + name.slice(1);
    return `  await fastify.register(${name}Routes, { prefix: '/api/services/${name}', services: { ${name}: ${lower} } });`;
  }).join('\n');

  return `/**
 * Fastify Server
 * Generated from SpecVerse specification
 */

import Fastify from 'fastify';
import cors from '@fastify/cors';
import { PrismaClient } from '@prisma/client';
${hasEvents ? `import { eventBus } from './events/eventBus.js';
import { registerWebSocketBridge } from './events/websocket-bridge.js';` : ''}

// Initialize Prisma
export const prisma = new PrismaClient();

// Initialize Fastify
const fastify = Fastify({
  logger: { level: 'info' },
});

// Register plugins
await fastify.register(cors, { origin: true, credentials: true });

// Health check
fastify.get('/health', async () => ({ status: 'ok', timestamp: new Date().toISOString() }));
fastify.get('/', async () => ({ name: 'SpecVerse Generated API', models: ${JSON.stringify(modelNames)} }));

// Spec endpoint — serves the specification for the runtime frontend
const embeddedSpec = ${JSON.stringify(normalizeSpec(spec), null, 2)};
fastify.get('/api/spec', async () => embeddedSpec);

// Runtime info endpoint — models and controllers for DevShell
fastify.get('/api/runtime/info', async () => ({
  controllers: ${JSON.stringify(modelNames.map((n: string) => `${n}Controller`))},
  models: ${JSON.stringify(modelNames)},
  events: ${JSON.stringify(specEvents)},
  services: ${JSON.stringify(servicesList)}
}));

${hasEvents ? `// Event history endpoint
fastify.get('/api/events', async () => eventBus.getHistory());` : ''}

// Register routes
${routeImports}

${serviceSingletonImports ? `// Service singletons + their Fastify route files\n${serviceSingletonImports}\n${serviceRouteImports}` : ''}

async function registerRoutes() {
${routeRegistrations}
${serviceRouteRegistrations ? '\n  // Service operation routes (RPC-style under /api/services/{ServiceName})\n' + serviceRouteRegistrations : ''}
}

// Start server
const start = async () => {
  try {
    await registerRoutes();
${hasEvents ? `    // Register WebSocket bridge for real-time frontend events
    await registerWebSocketBridge(fastify);` : ''}
    const port = parseInt(process.env.PORT || '3000');
    await fastify.listen({ port, host: '0.0.0.0' });
    console.log(\`Server running at http://localhost:\${port}\`);
    console.log(\`API endpoints: ${modelNames.map((n: string) => `/api/${n.toLowerCase()}s`).join(', ')}\`);
${hasEvents ? `    console.log(\`WebSocket: ws://localhost:\${port}/ws\`);
    console.log(\`Events: ${specEvents.join(', ')}\`);` : ''}
  } catch (err) {
    fastify.log.error(err);
    process.exit(1);
  }
};

start();
`;
}
