import { NextRequest, NextResponse } from 'next/server';
import { dbHelpers } from '@/lib/db';
import { getSession } from '@/lib/auth';
import { stepProgressSchema } from '@/lib/validators';
import { db, schema } from '@/lib/db';
import { eq } from 'drizzle-orm';
import { estimateConversionTokens } from '@/lib/conversion-pricing';

// Fraction of a project's total estimated tokens charged per completed step (simulation fallback only).
// Used only when actualTokens is not provided — real engine runs always pass actual token counts.
// Step 4 (Code Review) is a UI-only diff view with no AI call — excluded intentionally.
const STEP_TOKEN_WEIGHTS: Record<number, number> = {
  2: 0.10, // Pre-Analysis (proposeDependencies LLM call)
  3: 0.60, // Migration (main conversion run)
  5: 0.15, // Verification (test generation)
  7: 0.15, // Artifacts (scaffold generation)
};

interface AuthResult {
  userId: string;
}

/** Verify session + project ownership */
async function authorize(request: NextRequest, projectId: string): Promise<AuthResult | NextResponse> {
  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 { userId: session.user.id }; // authorized
}

const stepNameMap: Record<number, string> = {
  0: 'Overview',
  1: 'Repository',
  2: 'Pre-Analysis',
  3: 'Migration',
  4: 'Code Review',
  5: 'Verification',
  6: 'Security',
  7: 'Artifacts',
  8: 'Export',
};

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

    let body;
    try {
      const text = await request.text();
      if (!text) {
        return NextResponse.json({ error: 'Request body is empty' }, { status: 400 });
      }
      body = JSON.parse(text);
    } catch (e) {
      return NextResponse.json({ error: 'Invalid JSON in request body' }, { status: 400 });
    }

    const parsed = stepProgressSchema.safeParse(body);
    if (!parsed.success) {
      return NextResponse.json({ error: parsed.error.issues[0]?.message ?? 'Input non valido' }, { status: 400 });
    }
    const { stepNumber, status, maxReachedStep, metadata } = parsed.data;
    
    // Record step progress
    await dbHelpers.recordStepProgress(id, stepNumber, stepNameMap[stepNumber] || 'Unknown', status, metadata);
    
    // Update project's max reached step and current step
    const updates: any = {};
    if (maxReachedStep !== undefined) {
      updates.maxReachedStep = maxReachedStep;
    }
    if (status === 'completed' && stepNumber === 7) {
      updates.status = 'completed';
      updates.completedAt = new Date();
    } else if (status === 'in_progress') {
      updates.currentStep = stepNumber;
      // Update overall status based on step
      if (stepNumber === 2) updates.status = 'analyzing';
      if (stepNumber === 3) updates.status = 'converting';
      if (stepNumber === 5) updates.status = 'validating';
    }
    
    if (Object.keys(updates).length > 0) {
      await dbHelpers.updateProjectProgress(id, updates);
    }
    
    // Add activity entry
    const stepName = stepNameMap[stepNumber] ?? `Step ${stepNumber}`;
    await dbHelpers.addActivity(
      id,
      status === 'completed' ? `Completed ${stepName}` : `Started ${stepName}`,
      undefined,
      'System'
    );

    // Charge tokens when a token-bearing step completes.
    // Steps with a STEP_TOKEN_WEIGHT use the estimation formula as fallback.
    // Steps that pass actualTokens directly always charge, regardless of weight.
    const actualTokensProvided = typeof metadata?.actualTokens === 'number' && metadata.actualTokens > 0
      ? metadata.actualTokens
      : null;
    if (status === 'completed' && (STEP_TOKEN_WEIGHTS[stepNumber] !== undefined || actualTokensProvided !== null)) {
      const project = await dbHelpers.getProject(id);
      const config = (project?.config ?? {}) as Record<string, unknown>;

      const actualTokens = actualTokensProvided;

      const scanResults = (config.preAnalysis as Record<string, unknown> | undefined)?.scanResults as Record<string, unknown> | undefined;
      const effectiveLoc =
        typeof scanResults?.effectiveLoc === 'number' && scanResults.effectiveLoc > 0
          ? (scanResults.effectiveLoc as number)
          : undefined;
      const totalProjectTokens = actualTokens ?? estimateConversionTokens({
        effectiveLoc,
        totalLines: project?.totalLines,
        sourceLanguage: project?.sourceLanguage,
        estimatedLOC: config.estimatedLOC as number | string | null | undefined,
      });
      const delta = actualTokens
        ? actualTokens  // actual tokens already represent this step's real cost
        : Math.round(totalProjectTokens * STEP_TOKEN_WEIGHTS[stepNumber]!);
      if (delta > 0) {
        // Track tokens on project for reporting
        await dbHelpers.addTokens(id, delta);

        // Consume tokens from company's pool and write a log entry
        const sessionUser = await db.query.users.findFirst({
          where: eq(schema.users.id, userId),
          columns: { companyId: true, name: true, email: true },
        });

        if (sessionUser?.companyId) {
          await db.insert(schema.tokenLogs).values({
            companyId: sessionUser.companyId,
            userId,
            userName: sessionUser.name || 'Unknown',
            userEmail: sessionUser.email,
            projectId: id,
            projectName: project?.name || 'Unknown Project',
            stepName: stepNameMap[stepNumber] ?? `Step ${stepNumber}`,
            tokensConsumed: delta,
          });
        }
      }
    }

    return NextResponse.json({
      success: true, 
      message: 'Step progress recorded',
      step: stepNumber,
      status
    });
  } catch (error) {
    console.error('Error recording step progress:', error);
    return NextResponse.json({ error: 'Failed to record step progress' }, { status: 500 });
  }
}

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

    const steps = await dbHelpers.getProjectSteps(id);
    
    return NextResponse.json({ steps });
  } catch (error) {
    console.error('Error fetching project steps:', error);
    return NextResponse.json({ error: 'Failed to fetch project steps' }, { status: 500 });
  }
}
