import { NextResponse } from 'next/server';
import { and, eq, isNull } from 'drizzle-orm';
import crypto from 'node:crypto';

import { db } from '@/lib/db';
import { userEmailChanges } from '@/lib/db/schema/users';
import { createAuditLog } from '@/lib/audit';
import { errorResponse, ValidationError } from '@/lib/errors';
import { env } from '@/lib/env';

/**
 * Cancel a pending email-change. Linked from the email sent to the
 * OLD address as a safety net for "I didn't ask for this" reports.
 */
export async function GET(
  _req: Request,
  context: { params: Promise<{ token: string }> },
): Promise<Response> {
  try {
    const { token } = await context.params;
    if (!token) throw new ValidationError('Missing token');
    const tokenHash = crypto.createHash('sha256').update(token).digest('hex');

    const pending = await db.query.userEmailChanges.findFirst({
      where: and(
        eq(userEmailChanges.confirmTokenHash, tokenHash),
        isNull(userEmailChanges.appliedAt),
        isNull(userEmailChanges.cancelledAt),
      ),
    });
    if (!pending) throw new ValidationError('Token is invalid or already used');

    await db
      .update(userEmailChanges)
      .set({ cancelledAt: new Date() })
      .where(eq(userEmailChanges.id, pending.id));

    void createAuditLog({
      userId: pending.userId,
      portId: null,
      action: 'update',
      entityType: 'user_email_change',
      entityId: pending.id,
      newValue: { newEmail: pending.newEmail },
      metadata: { type: 'email_change_cancelled' },
      severity: 'warning',
    });

    const baseUrl = env.APP_URL.replace(/\/+$/, '');
    return NextResponse.redirect(`${baseUrl}/settings?emailChange=cancelled`);
  } catch (error) {
    return errorResponse(error);
  }
}
