import { NextRequest, NextResponse } from 'next/server';
import { db, schema } from '@/lib/db';
import { eq, and } from 'drizzle-orm';
import bcrypt from 'bcrypt';
import { rateLimit } from '@/lib/rate-limit';
import { signinSchema } from '@/lib/validators';
import { generateAccessToken, generateRefreshToken } from '@/lib/tokens';
import { create2FAChallenge, sendEmail2FACode, sendSMS2FACode } from '@/lib/2fa';
import { ACCESS_TOKEN_MAX_AGE_SECONDS, BCRYPT_ROUNDS, REFRESH_TOKEN_MAX_AGE_SECONDS } from '@/lib/constants';

export async function POST(request: NextRequest) {
  try {
    // Rate limit: 5 attempts per 60s per IP
    const ip = request.headers.get('x-forwarded-for')?.split(',')[0]?.trim() || 'unknown';
    const rl = rateLimit(`signin:${ip}`, { limit: 5, windowSeconds: 60 });
    if (!rl.allowed) {
      return NextResponse.json(
        { error: 'Troppi tentativi. Riprova tra un minuto.' },
        { status: 429, headers: { 'Retry-After': String(Math.ceil((rl.resetAt - Date.now()) / 1000)) } }
      );
    }

    const body = await request.json();
    const parsed = signinSchema.safeParse(body);
    if (!parsed.success) {
      return NextResponse.json({ error: parsed.error.issues[0]?.message ?? 'Input non valido' }, { status: 400 });
    }
    const { email, password } = parsed.data;

    // Find user
    const user = await db.query.users.findFirst({
      where: eq(schema.users.email, email)
    });

    if (!user) {
      return NextResponse.json({ error: 'Credenziali non valide' }, { status: 401 });
    }

    // Get credential account
    const account = await db.query.accounts.findFirst({
      where: and(
        eq(schema.accounts.userId, user.id),
        eq(schema.accounts.providerId, 'credential')
      )
    });

    if (!account || !account.password) {
      return NextResponse.json({ error: 'Credenziali non valide' }, { status: 401 });
    }

    // Verify password
    const isValid = await bcrypt.compare(password, account.password);
    if (!isValid) {
      return NextResponse.json({ error: 'Credenziali non valide' }, { status: 401 });
    }

    // Check if 2FA is enabled for this user
    if (user.twoFactorEnabled && user.twoFactorMethod) {
      // Create 2FA challenge
      const challengeId = await create2FAChallenge(
        user.id,
        user.twoFactorMethod as 'email' | 'sms' | 'authenticator',
        undefined,
        request.headers.get('x-forwarded-for') || undefined,
        request.headers.get('user-agent') || undefined
      );

      // Send code based on method (for email/sms)
      if (user.twoFactorMethod === 'email') {
        // Generate and send email code
        const { generateVerificationCode } = await import('@/lib/2fa');
        const emailCode = generateVerificationCode();
        await db
          .update(schema.twoFactorChallenges)
          .set({ codeHash: await bcrypt.hash(emailCode, BCRYPT_ROUNDS) })
          .where(eq(schema.twoFactorChallenges.id, challengeId));
        await sendEmail2FACode(user.email, emailCode);
      } else if (user.twoFactorMethod === 'sms' && user.phoneNumber) {
        // Generate and send SMS code
        const { generateVerificationCode } = await import('@/lib/2fa');
        const smsCode = generateVerificationCode();
        await db
          .update(schema.twoFactorChallenges)
          .set({ codeHash: await bcrypt.hash(smsCode, BCRYPT_ROUNDS) })
          .where(eq(schema.twoFactorChallenges.id, challengeId));
        await sendSMS2FACode(user.phoneNumber, smsCode);
      }

      // Return challenge response - user needs to complete 2FA
      return NextResponse.json({
        requires2FA: true,
        challengeId,
        method: user.twoFactorMethod,
        message: user.twoFactorMethod === 'authenticator'
          ? 'Inserisci il codice dalla tua app di autenticazione'
          : 'Inserisci il codice di verifica inviato',
      }, { status: 202 });
    }

    // Generate refresh token and session
    const { refreshToken, sessionId } = await generateRefreshToken(
      user.id,
      request.headers.get('x-forwarded-for') || undefined,
      request.headers.get('user-agent') || undefined
    );

    // Generate access token
    const accessToken = generateAccessToken({
      userId: user.id,
      email: user.email,
      role: user.role,
      sessionId,
    });

    // Set HttpOnly cookies
    const response = NextResponse.json({
      success: true,
      user: { id: user.id, email: user.email, name: user.name, role: user.role }
    });

    // Access token cookie (short-lived)
    response.cookies.set('scriba.access_token', accessToken, {
      httpOnly: true,
      secure: process.env.NODE_ENV === 'production',
      sameSite: 'lax',
      path: '/',
      maxAge: ACCESS_TOKEN_MAX_AGE_SECONDS,
    });

    // Refresh token cookie (long-lived)
    response.cookies.set('scriba.refresh_token', refreshToken, {
      httpOnly: true,
      secure: process.env.NODE_ENV === 'production',
      sameSite: 'lax',
      path: '/',
      maxAge: REFRESH_TOKEN_MAX_AGE_SECONDS,
    });

    return response;
  } catch (error) {
    console.error('Sign-in error:', error);
    return NextResponse.json({ error: 'Login fallito. Riprova.' }, { status: 500 });
  }
}
