import { NextRequest, NextResponse } from 'next/server';
import OpenAI from 'openai';
import { dbHelpers, db, schema } from '@/lib/db';
import { eq } from 'drizzle-orm';
import { getSession } from '@/lib/auth';

async function authorize(request: NextRequest, projectId: string) {
  const accessToken = request.cookies.get('scriba.access_token')?.value;
  const session = await getSession(accessToken);
  if (!session) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
  const project = await dbHelpers.getProject(projectId);
  if (!project) return NextResponse.json({ error: 'Conversion not found' }, { status: 404 });
  if (project.userId !== session.user.id) return NextResponse.json({ error: 'Forbidden' }, { status: 403 });
  return project;
}

export async function POST(
  request: NextRequest,
  { params }: { params: Promise<{ id: string }> }
) {
  const { id } = await params;
  const authResult = await authorize(request, id);
  if (authResult instanceof NextResponse) return authResult;
  const project = authResult;

  let body: { errors?: string[] };
  try {
    body = await request.json();
  } catch {
    return NextResponse.json({ error: 'Invalid JSON' }, { status: 400 });
  }

  const errors = (body.errors ?? []).filter(Boolean).slice(0, 60);
  if (errors.length === 0) {
    return NextResponse.json({ patchedCount: 0, message: 'No errors provided' });
  }

  const apiKey = process.env.OPENAI_API_KEY;
  if (!apiKey) {
    return NextResponse.json({ error: 'Repair service not configured' }, { status: 503 });
  }

  // Load current translated files from project config
  const projConfig = (project.config ?? {}) as Record<string, unknown>;
  const analysisResults = (projConfig.analysisResults ?? {}) as Record<string, unknown>;
  const translation = (analysisResults.translation ?? {}) as Record<string, unknown>;
  const files = (translation.files ?? []) as Array<{ targetFile?: string; targetCode?: string; [k: string]: unknown }>;

  if (files.length === 0) {
    return NextResponse.json({ error: 'No translated files found in project config' }, { status: 422 });
  }

  // Identify files referenced in the error output
  const errorText = errors.join('\n');
  const referencedFiles = files.filter(f => {
    if (!f.targetFile) return false;
    const baseName = f.targetFile.split('/').pop() ?? '';
    return errorText.includes(f.targetFile) || (baseName.length > 2 && errorText.includes(baseName));
  });

  // Fall back to the first 5 files if no specific ones were identified
  const filesToFix = referencedFiles.length > 0 ? referencedFiles : files.slice(0, 5);

  const client = new OpenAI({ apiKey });

  const fileContext = filesToFix
    .map(f => `### ${f.targetFile}\n\`\`\`\n${(f.targetCode ?? '').slice(0, 8000)}\n\`\`\``)
    .join('\n\n');

  const prompt = `You are a code repair assistant. The following files were generated by a migration engine and failed to build. Fix ONLY the compilation/build errors shown. Do not refactor or change logic. Return the corrected files.

## Build errors:
\`\`\`
${errorText.slice(0, 4000)}
\`\`\`

## Files to fix:
${fileContext}

## Instructions:
- Fix only what causes the build errors
- Keep all logic and structure intact
- Return a JSON array: [{"path": "...", "content": "..."}]
- Include ONLY files you changed
- Do not wrap in markdown code blocks — return raw JSON only`;

  try {
    const completion = await client.chat.completions.create({
      model: 'gpt-5.5',
      max_tokens: 8192,
      messages: [
        { role: 'system', content: 'You are a precise code repair assistant. Always return valid JSON only, no markdown.' },
        { role: 'user', content: prompt },
      ],
    });

    const rawText = completion.choices[0]?.message?.content ?? '';

    let patchedFiles: Array<{ path: string; content: string }> = [];
    try {
      const jsonMatch = rawText.match(/\[[\s\S]*\]/);
      if (jsonMatch) {
        patchedFiles = JSON.parse(jsonMatch[0]);
      }
    } catch {
      return NextResponse.json({ error: 'Repair engine returned unparseable response' }, { status: 500 });
    }

    if (patchedFiles.length === 0) {
      return NextResponse.json({ patchedCount: 0, message: 'No patches returned by repair engine' });
    }

    // Apply patches back to the translation files array
    const updatedFiles = files.map(f => {
      const patch = patchedFiles.find(p =>
        p.path === f.targetFile ||
        (f.targetFile && p.path && f.targetFile.endsWith(p.path)) ||
        (f.targetFile && p.path && p.path.endsWith(f.targetFile.split('/').pop() ?? ''))
      );
      return patch ? { ...f, targetCode: patch.content } : f;
    });

    // Persist patched files to project config
    await dbHelpers.updateProjectProgress(id, {
      config: {
        ...projConfig,
        analysisResults: {
          ...analysisResults,
          translation: {
            ...translation,
            files: updatedFiles,
          },
        },
        sandboxRepairAttempt: ((projConfig.sandboxRepairAttempt as number | undefined) ?? 0) + 1,
      } as Record<string, unknown>,
    });

    // Record actual OpenAI token usage to company token log
    const repairTokens = (completion.usage?.prompt_tokens ?? 0) + (completion.usage?.completion_tokens ?? 0);
    if (repairTokens > 0 && project.userId) {
      const ownerId = project.userId;
      await dbHelpers.addTokens(id, repairTokens).catch(() => {});
      const sessionUser = await db.query.users.findFirst({
        where: eq(schema.users.id, ownerId),
        columns: { companyId: true, name: true, email: true },
      }).catch(() => null);
      if (sessionUser?.companyId) {
        await db.insert(schema.tokenLogs).values({
          companyId: sessionUser.companyId,
          userId: ownerId,
          userName: sessionUser.name ?? 'Unknown',
          userEmail: sessionUser.email,
          projectId: id,
          projectName: project.name ?? 'Unknown Project',
          stepName: 'Sandbox Repair',
          tokensConsumed: repairTokens,
        }).catch(() => {});
      }
    }

    return NextResponse.json({ patchedCount: patchedFiles.length });
  } catch (err) {
    const msg = err instanceof Error ? err.message : 'Repair failed';
    return NextResponse.json({ error: msg }, { status: 500 });
  }
}
