import { NextResponse } from 'next/server';
import bcrypt from 'bcryptjs';
import { eq, and } from 'drizzle-orm';
import { db, users } from '@server/db/drizzle';
import { initDatabase } from '@server/db/init';
import { withErrorHandler } from '@server/middleware/withErrorHandler';
import { withAuth, AuthedRequest } from '@server/middleware/withAuth';
import { withValidation, ParsedRequest } from '@server/middleware/withValidation';
import { changePasswordSchema, ChangePasswordInput } from '@server/validators/auth.validator';
import { AuthError, NotFoundError, ValidationError } from '@server/errors';

export const POST = withErrorHandler(
  withAuth(
    withValidation(changePasswordSchema, async (req: ParsedRequest<ChangePasswordInput>) => {
      await initDatabase();
      const { currentPassword, newPassword } = req.parsedBody;
      const session = (req as unknown as AuthedRequest).session;

      if (!/[A-Z]/.test(newPassword)) throw new ValidationError('New password must contain at least one uppercase letter');
      if (!/[0-9]/.test(newPassword)) throw new ValidationError('New password must contain at least one number');

      const rows = await db
        .select({ id: users.id, passwordHash: users.passwordHash })
        .from(users)
        .where(and(eq(users.id, session.userId), eq(users.isActive, true)));
      const user = rows[0];
      if (!user) throw new NotFoundError('User');

      const valid = await bcrypt.compare(currentPassword, user.passwordHash);
      if (!valid) throw new AuthError('Current password is incorrect');

      const newHash = await bcrypt.hash(newPassword, 12);
      await db.update(users).set({ passwordHash: newHash, updatedAt: new Date().toISOString() }).where(eq(users.id, session.userId));

      return NextResponse.json({ success: true, message: 'Password updated successfully' });
    }) as unknown as (req: AuthedRequest, ctx: { params: Promise<Record<string, string>> }) => Promise<NextResponse | Response>
  )
);
