import { NextRequest, NextResponse } from 'next/server';
import JSZip from 'jszip';
import { dbHelpers } from '@/lib/db';
import { getSession } from '@/lib/auth';
import { buildScribaDeployWorkflow, normalizeProjectLang } from '@/lib/cicd-workflow';
import {
  readToolingFilesFromAnalysis,
  readDocsAndTestArtifactsFromAnalysis,
  normalizeEngineOutputZipPath,
  applyMarkersToFiles,
  buildMarkerMetadata,
} from '@/lib/export-bundle';

type ConversionResultShape = {
  files?: Array<{ outputPath: string; content: string }>;
  metadata?: Record<string, unknown>;
};

function readConversionResult(config: Record<string, unknown>): ConversionResultShape | undefined {
  const raw = config.conversionResult;
  if (raw && typeof raw === 'object') return raw as ConversionResultShape;
  return undefined;
}

export async function GET(
  request: NextRequest,
  { params }: { params: Promise<{ id: string }> }
) {
  const { id } = await params;

  // Auth
  const accessToken = request.cookies.get('scriba.access_token')?.value;
  const session = await getSession(accessToken);
  if (!session) {
    return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
  }

  // Load project
  const project = await dbHelpers.getProject(id);
  if (!project) {
    return NextResponse.json({ error: 'Project not found' }, { status: 404 });
  }
  if (project.userId !== session.user.id) {
    return NextResponse.json({ error: 'Forbidden' }, { status: 403 });
  }

  const config = (project.config ?? {}) as Record<string, unknown>;
  const conversionResult = readConversionResult(config);
  const engineFiles: Array<{ outputPath: string; content: string }> =
    conversionResult?.files ?? [];

  if (engineFiles.length === 0) {
    return NextResponse.json(
      { error: 'No converted files available. Complete the migration first.' },
      { status: 404 }
    );
  }

  const targetLangNorm = normalizeProjectLang(project.targetLanguage);
  const targetSlug = targetLangNorm || 'export';
  const projectName = project.name ?? 'project';
  const zipName = projectName.toLowerCase().replace(/\s+/g, '-');

  const zip = new JSZip();
  const bundleFiles: Array<{ path: string; content: string }> = [];

  // Add all converted files (strip engine temp dir scriba-out-*/ so ZIP matches project layout)
  for (const file of engineFiles) {
    const path = normalizeEngineOutputZipPath(file.outputPath);
    bundleFiles.push({ path, content: file.content ?? '' });
  }

  const toolingZip = readToolingFilesFromAnalysis(config);
  let toolingHasCi = false;
  for (const tf of toolingZip) {
    const norm = tf.path.replace(/\\/g, '/');
    if (norm.includes('.github/workflows/') && norm.endsWith('scriba-deploy.yml')) toolingHasCi = true;
    bundleFiles.push({ path: tf.path, content: tf.content });
  }

  for (const row of readDocsAndTestArtifactsFromAnalysis(config)) {
    bundleFiles.push({ path: row.path, content: row.content });
  }

  // CI/CD workflow — when CI enabled and not already included from saved tooling artifacts
  const addCI = config.addCI !== false;
  const addDocker = config.addDocker !== false;
  if (addCI && !toolingHasCi) {
    bundleFiles.push({
      path: '.github/workflows/scriba-deploy.yml',
      content: buildScribaDeployWorkflow({
        projectName,
        sourceLanguage: project.sourceLanguage,
        targetLanguage: project.targetLanguage,
        config,
        includeOptionalDocker: addDocker,
      }),
    });
  }

  // Add a migration summary README if not already present
  const hasReadme = engineFiles.some((f) =>
    normalizeEngineOutputZipPath(f.outputPath).toLowerCase().endsWith('readme.md'),
  );
  if (!hasReadme) {
    const meta = conversionResult?.metadata ?? {};
    bundleFiles.push({
      path: 'SCRIBA-MIGRATION.md',
      content:
        `# ${projectName} — Migration Summary\n\nMigrated by Scriba Engine\n\n` +
        `- **Source**: ${project.sourceLanguage ?? 'unknown'}\n` +
        `- **Target**: ${project.targetLanguage ?? 'unknown'}\n` +
        `- **Files converted**: ${engineFiles.length}\n` +
        `- **Accuracy**: ${meta.accuracy ?? project.accuracy ?? '?'}%\n` +
        `- **Date**: ${new Date().toISOString().split('T')[0]}\n`,
    });
  }

  const markerMeta = buildMarkerMetadata(project);
  const { files: markedFiles, manifestContent } = applyMarkersToFiles(bundleFiles, markerMeta);
  for (const file of markedFiles) {
    zip.file(file.path, file.content);
  }
  zip.file('SCRIBA_MANIFEST.json', manifestContent);

  const content = await zip.generateAsync({ type: 'arraybuffer', compression: 'DEFLATE' });

  // Use the standard web Response (not NextResponse) to avoid buffer type issues
  return new Response(content, {
    status: 200,
    headers: {
      'Content-Type': 'application/zip',
      'Content-Disposition': `attachment; filename="${zipName}-${targetSlug}.zip"`,
      'Content-Length': String(content.byteLength),
    },
  });
}
