/**
 * API Route Generator
 * Generates Next.js API routes from schema definitions
 */

import { ApiEndpointDef, PrismaModelDef } from '../../core/schema/generator';

export interface GeneratedRoute {
  path: string;
  filename: string;
  content: string;
}

export function generateApiRoutes(
  endpoints: ApiEndpointDef[],
  models: PrismaModelDef[]
): GeneratedRoute[] {
  const routes: GeneratedRoute[] = [];
  
  // Group endpoints by base path
  const grouped = groupEndpointsByPath(endpoints);
  
  for (const [basePath, pathEndpoints] of Object.entries(grouped)) {
    // Find associated model
    const modelName = extractModelName(basePath);
    const model = models.find(m => m.name.toLowerCase() === modelName.toLowerCase());
    
    // Check if this is a dynamic route (has [id])
    const hasDynamic = pathEndpoints.some(e => e.path.includes('[id]'));
    
    if (hasDynamic) {
      // Generate both base route and dynamic route
      const baseEndpoints = pathEndpoints.filter(e => !e.path.includes('[id]'));
      const dynamicEndpoints = pathEndpoints.filter(e => e.path.includes('[id]'));
      
      if (baseEndpoints.length > 0) {
        routes.push({
          path: basePath,
          filename: `app${basePath}/route.ts`,
          content: generateRouteFile(baseEndpoints, model),
        });
      }
      
      if (dynamicEndpoints.length > 0) {
        routes.push({
          path: `${basePath}/[id]`,
          filename: `app${basePath}/[id]/route.ts`,
          content: generateDynamicRouteFile(dynamicEndpoints, model),
        });
      }
    } else {
      routes.push({
        path: basePath,
        filename: `app${basePath}/route.ts`,
        content: generateRouteFile(pathEndpoints, model),
      });
    }
  }
  
  return routes;
}

function groupEndpointsByPath(endpoints: ApiEndpointDef[]): Record<string, ApiEndpointDef[]> {
  const grouped: Record<string, ApiEndpointDef[]> = {};
  
  for (const endpoint of endpoints) {
    // Extract base path (without [id])
    const basePath = endpoint.path.replace('/[id]', '');
    if (!grouped[basePath]) {
      grouped[basePath] = [];
    }
    grouped[basePath].push(endpoint);
  }
  
  return grouped;
}

function extractModelName(path: string): string {
  // /api/customer-order -> CustomerOrder
  const parts = path.split('/').filter(Boolean);
  const last = parts[parts.length - 1];
  return last
    .split('-')
    .map(p => p.charAt(0).toUpperCase() + p.slice(1))
    .join('');
}

function generateRouteFile(endpoints: ApiEndpointDef[], model?: PrismaModelDef): string {
  const modelName = model?.name || 'Entity';
  const modelNameLower = modelName.charAt(0).toLowerCase() + modelName.slice(1);
  
  const imports = [
    `import { NextRequest, NextResponse } from 'next/server';`,
    `import { prisma } from '@/lib/db';`,
  ];
  
  const handlers: string[] = [];
  
  for (const endpoint of endpoints) {
    if (endpoint.method === 'GET') {
      handlers.push(generateGetHandler(modelName, modelNameLower));
    } else if (endpoint.method === 'POST') {
      handlers.push(generatePostHandler(modelName, modelNameLower, model));
    }
  }
  
  return [
    `/**`,
    ` * Auto-generated by Dark Factory`,
    ` * ${modelName} API Routes`,
    ` */`,
    ``,
    ...imports,
    ``,
    `export const dynamic = 'force-dynamic';`,
    ``,
    ...handlers,
  ].join('\n');
}

function generateDynamicRouteFile(endpoints: ApiEndpointDef[], model?: PrismaModelDef): string {
  const modelName = model?.name || 'Entity';
  const modelNameLower = modelName.charAt(0).toLowerCase() + modelName.slice(1);
  
  const imports = [
    `import { NextRequest, NextResponse } from 'next/server';`,
    `import { prisma } from '@/lib/db';`,
  ];
  
  const handlers: string[] = [];
  
  for (const endpoint of endpoints) {
    if (endpoint.method === 'GET') {
      handlers.push(generateGetByIdHandler(modelName, modelNameLower));
    } else if (endpoint.method === 'PUT') {
      handlers.push(generatePutHandler(modelName, modelNameLower, model));
    } else if (endpoint.method === 'DELETE') {
      handlers.push(generateDeleteHandler(modelName, modelNameLower));
    }
  }
  
  return [
    `/**`,
    ` * Auto-generated by Dark Factory`,
    ` * ${modelName} Dynamic API Routes`,
    ` */`,
    ``,
    ...imports,
    ``,
    `export const dynamic = 'force-dynamic';`,
    ``,
    `interface RouteContext {`,
    `  params: Promise<{ id: string }>;`,
    `}`,
    ``,
    ...handlers,
  ].join('\n');
}

function generateGetHandler(modelName: string, modelNameLower: string): string {
  return `
// GET - List all ${modelName} records
export async function GET(request: NextRequest) {
  try {
    const searchParams = request.nextUrl.searchParams;
    const page = parseInt(searchParams.get('page') || '1');
    const limit = parseInt(searchParams.get('limit') || '20');
    const skip = (page - 1) * limit;

    const [items, total] = await Promise.all([
      prisma.${modelNameLower}.findMany({
        skip,
        take: limit,
        orderBy: { createdAt: 'desc' },
      }),
      prisma.${modelNameLower}.count(),
    ]);

    return NextResponse.json({
      data: items,
      pagination: {
        page,
        limit,
        total,
        totalPages: Math.ceil(total / limit),
      },
    });
  } catch (error) {
    console.error('Error fetching ${modelName}:', error);
    return NextResponse.json(
      { error: 'Failed to fetch ${modelName} records' },
      { status: 500 }
    );
  }
}
`;
}

function generatePostHandler(modelName: string, modelNameLower: string, model?: PrismaModelDef): string {
  // Get required fields from model (excluding auto-generated ones)
  const requiredFields = model?.fields
    .filter(f => !f.isOptional && !['id', 'createdAt', 'updatedAt'].includes(f.name))
    .map(f => f.name) || [];
  
  const validationCode = requiredFields.length > 0
    ? `
    // Validate required fields
    const required = [${requiredFields.map(f => `'${f}'`).join(', ')}];
    const missing = required.filter(field => !(field in body));
    if (missing.length > 0) {
      return NextResponse.json(
        { error: \`Missing required fields: \${missing.join(', ')}\` },
        { status: 400 }
      );
    }`
    : '';

  return `
// POST - Create a new ${modelName}
export async function POST(request: NextRequest) {
  try {
    const body = await request.json();
    ${validationCode}

    const ${modelNameLower} = await prisma.${modelNameLower}.create({
      data: body,
    });

    return NextResponse.json(${modelNameLower}, { status: 201 });
  } catch (error) {
    console.error('Error creating ${modelName}:', error);
    return NextResponse.json(
      { error: 'Failed to create ${modelName}' },
      { status: 500 }
    );
  }
}
`;
}

function generateGetByIdHandler(modelName: string, modelNameLower: string): string {
  return `
// GET - Get a single ${modelName} by ID
export async function GET(
  request: NextRequest,
  context: RouteContext
) {
  try {
    const { id } = await context.params;

    const ${modelNameLower} = await prisma.${modelNameLower}.findUnique({
      where: { id },
    });

    if (!${modelNameLower}) {
      return NextResponse.json(
        { error: '${modelName} not found' },
        { status: 404 }
      );
    }

    return NextResponse.json(${modelNameLower});
  } catch (error) {
    console.error('Error fetching ${modelName}:', error);
    return NextResponse.json(
      { error: 'Failed to fetch ${modelName}' },
      { status: 500 }
    );
  }
}
`;
}

function generatePutHandler(modelName: string, modelNameLower: string, model?: PrismaModelDef): string {
  return `
// PUT - Update a ${modelName}
export async function PUT(
  request: NextRequest,
  context: RouteContext
) {
  try {
    const { id } = await context.params;
    const body = await request.json();

    // Remove fields that shouldn't be updated
    delete body.id;
    delete body.createdAt;
    delete body.updatedAt;

    const ${modelNameLower} = await prisma.${modelNameLower}.update({
      where: { id },
      data: body,
    });

    return NextResponse.json(${modelNameLower});
  } catch (error) {
    console.error('Error updating ${modelName}:', error);
    return NextResponse.json(
      { error: 'Failed to update ${modelName}' },
      { status: 500 }
    );
  }
}
`;
}

function generateDeleteHandler(modelName: string, modelNameLower: string): string {
  return `
// DELETE - Delete a ${modelName}
export async function DELETE(
  request: NextRequest,
  context: RouteContext
) {
  try {
    const { id } = await context.params;

    await prisma.${modelNameLower}.delete({
      where: { id },
    });

    return NextResponse.json({ success: true });
  } catch (error) {
    console.error('Error deleting ${modelName}:', error);
    return NextResponse.json(
      { error: 'Failed to delete ${modelName}' },
      { status: 500 }
    );
  }
}
`;
}
