import { NextRequest, NextResponse } from 'next/server';
import { prisma } from '@/lib/db';
import { MODULE_REGISTRY, checkDependencies, checkDependents, getModule } from '@/lib/modules/registry';
import { invalidateFeatureFlags, syncModuleRegistry } from '@/lib/modules/feature-flags';

export const dynamic = 'force-dynamic';

/**
 * GET /api/modules
 * Returns all modules with their current enabled/disabled status.
 * If no configs exist in DB yet, syncs from registry first.
 */
export async function GET() {
  try {
    let configs = await prisma.moduleConfig.findMany({
      orderBy: { sortOrder: 'asc' },
    });

    // Sync registry to DB if new modules were added or on first boot
    const registryCount = MODULE_REGISTRY.length;
    const dbModuleIds = new Set(configs.map((c: any) => c.moduleId));
    const hasNewModules = MODULE_REGISTRY.some(m => !dbModuleIds.has(m.moduleId));
    if (configs.length === 0 || hasNewModules) {
      await syncModuleRegistry();
      configs = await prisma.moduleConfig.findMany({
        orderBy: { sortOrder: 'asc' },
      });
    }

    // Merge registry metadata with DB state — only include modules still in the registry
    const modules = configs
      .filter((config: any) => !!getModule(config.moduleId))
      .map((config: any) => {
        const def = getModule(config.moduleId)!;
        return {
          ...config,
          features: def.features || [],
          tier: def.tier || 'starter',
          agentId: def.agentId || null,
          prismaModels: def.prismaModels || [],
          apiRoutes: def.apiRoutes || [],
          uiRoutes: def.uiRoutes || [],
        };
      });

    const enabledCount = modules.filter((m: any) => m.isEnabled).length;
    const totalCount = modules.length;

    return NextResponse.json({
      modules,
      stats: { total: totalCount, enabled: enabledCount, available: totalCount - enabledCount },
    });
  } catch (error) {
    console.error('Failed to fetch modules:', error);
    return NextResponse.json({ error: 'Failed to fetch modules' }, { status: 500 });
  }
}

/**
 * POST /api/modules
 * Toggle a module on or off.
 * Body: { moduleId: string, action: 'enable' | 'disable' }
 */
export async function POST(request: NextRequest) {
  try {
    const { moduleId, action } = await request.json();

    if (!moduleId || !['enable', 'disable'].includes(action)) {
      return NextResponse.json({ error: 'Invalid request. Requires moduleId and action (enable/disable).' }, { status: 400 });
    }

    const moduleDef = getModule(moduleId);
    if (!moduleDef) {
      return NextResponse.json({ error: `Module '${moduleId}' not found in registry.` }, { status: 404 });
    }

    // Core modules cannot be disabled
    if (action === 'disable' && moduleDef.isCore) {
      return NextResponse.json({ error: `Cannot disable core module '${moduleDef.name}'.` }, { status: 403 });
    }

    // Get current enabled set
    const enabledConfigs = await prisma.moduleConfig.findMany({
      where: { isEnabled: true },
      select: { moduleId: true },
    });
    const enabledSet = new Set<string>(enabledConfigs.map((c: { moduleId: string }) => c.moduleId));

    if (action === 'enable') {
      // Check dependencies
      const depCheck = checkDependencies(moduleId, enabledSet);
      if (!depCheck.satisfied) {
        const missingNames = depCheck.missing.map(id => getModule(id)?.name || id);
        return NextResponse.json({
          error: `Cannot enable '${moduleDef.name}'. Missing dependencies: ${missingNames.join(', ')}`,
          missingDependencies: depCheck.missing,
        }, { status: 409 });
      }

      await prisma.moduleConfig.upsert({
        where: { moduleId },
        create: {
          moduleId,
          name: moduleDef.name,
          description: moduleDef.description,
          category: moduleDef.category,
          icon: moduleDef.icon,
          isEnabled: true,
          isCore: moduleDef.isCore,
          sortOrder: moduleDef.sortOrder,
          dependencies: moduleDef.dependencies,
          enabledAt: new Date(),
          metadata: { features: moduleDef.features, tier: moduleDef.tier, agentId: moduleDef.agentId || null },
        },
        update: {
          isEnabled: true,
          enabledAt: new Date(),
        },
      });

      // Activate corresponding domain agent if exists
      if (moduleDef.agentId) {
        await prisma.domainAgent.updateMany({
          where: { agentId: moduleDef.agentId },
          data: { status: 'active' },
        });
      }
    } else {
      // Check dependents before disabling
      const depCheck = checkDependents(moduleId, enabledSet);
      if (!depCheck.safe) {
        const depNames = depCheck.dependents.map(id => getModule(id)?.name || id);
        return NextResponse.json({
          error: `Cannot disable '${moduleDef.name}'. These enabled modules depend on it: ${depNames.join(', ')}`,
          dependentModules: depCheck.dependents,
        }, { status: 409 });
      }

      await prisma.moduleConfig.update({
        where: { moduleId },
        data: { isEnabled: false, enabledAt: null },
      });

      // Set corresponding agent to dormant
      if (moduleDef.agentId) {
        // Only set dormant if no other enabled module uses this agent
        const otherModulesUsingAgent = MODULE_REGISTRY.filter(
          m => m.agentId === moduleDef.agentId && m.moduleId !== moduleId && enabledSet.has(m.moduleId)
        );
        if (otherModulesUsingAgent.length === 0) {
          await prisma.domainAgent.updateMany({
            where: { agentId: moduleDef.agentId },
            data: { status: 'dormant' },
          });
        }
      }
    }

    invalidateFeatureFlags();

    return NextResponse.json({
      success: true,
      moduleId,
      action,
      message: `Module '${moduleDef.name}' ${action === 'enable' ? 'enabled' : 'disabled'} successfully.`,
    });
  } catch (error) {
    console.error('Failed to toggle module:', error);
    return NextResponse.json({ error: 'Failed to toggle module' }, { status: 500 });
  }
}
