import { NextResponse } from 'next/server';
import { withErrorHandler } from '@server/middleware/withErrorHandler';
import { withAuth, AuthedRequest } from '@server/middleware/withAuth';
import { createAuditLog } from '@server/services/admin.service';
import { ForbiddenError, NotFoundError, ValidationError } from '@server/errors';
import { createSession, verifySession, COOKIE_NAME } from '@server/auth';
import { db, restaurants, branches } from '@server/db/drizzle';
import { eq, and, asc } from 'drizzle-orm';
import { initDatabase } from '@server/db/init';
import { cookies } from 'next/headers';

const RESTORE_COOKIE = 'admin_restore';
const SESSION_TTL = 7 * 24 * 60 * 60;

export const POST = withErrorHandler(
  withAuth(async (req: AuthedRequest) => {
    if (req.session.role !== 'superadmin' && req.session.role !== 'support') {
      throw new ForbiddenError();
    }

    let body: Awaited<ReturnType<typeof req.json>>;
    try {
      body = await req.json();
    } catch {
      throw new ValidationError('Request body must be valid JSON');
    }
    const { restaurantId } = body as { restaurantId: string };
    if (!restaurantId) {
      throw new ValidationError('restaurantId is required');
    }

    await initDatabase();

    const restRows = await db.select({ id: restaurants.id, name: restaurants.name })
      .from(restaurants)
      .where(eq(restaurants.id, restaurantId));
    const restaurant = restRows[0];
    if (!restaurant) throw new NotFoundError('Restaurant not found');

    const branchRows = await db.select({ id: branches.id })
      .from(branches)
      .where(and(eq(branches.restaurantId, restaurantId), eq(branches.isActive, true)))
      .orderBy(asc(branches.createdAt))
      .limit(1);
    const firstBranch = branchRows[0];

    const cookieStore = await cookies();
    const currentToken = cookieStore.get(COOKIE_NAME)?.value ?? '';
    const existingRestore = cookieStore.get(RESTORE_COOKIE)?.value ?? '';

    let originalToken: string;
    if (existingRestore) {
      const existing = await verifySession(existingRestore);
      originalToken = existing ? existingRestore : currentToken;
    } else {
      originalToken = currentToken;
    }

    await createAuditLog({
      actorId: req.session.userId,
      actorEmail: req.session.email,
      actorType: 'admin',
      action: 'Impersonated restaurant session',
      resource: restaurant.name,
      resourceId: restaurant.id,
      severity: 'warning',
    });

    const impersonateToken = await createSession({
      userId: req.session.userId,
      email: req.session.email,
      role: req.session.role,
      restaurantId: restaurant.id,
      branchId: firstBranch?.id ?? null,
    });

    const res = NextResponse.json({ ok: true, restaurantName: restaurant.name });
    const secure = process.env.NODE_ENV === 'production';

    if (originalToken) {
      res.cookies.set(RESTORE_COOKIE, originalToken, {
        httpOnly: true,
        sameSite: 'lax',
        path: '/',
        maxAge: SESSION_TTL,
        secure,
      });
    }

    res.cookies.set(COOKIE_NAME, impersonateToken, {
      httpOnly: true,
      sameSite: 'lax',
      path: '/',
      maxAge: SESSION_TTL,
      secure,
    });

    res.cookies.set('impersonating_name', restaurant.name, {
      httpOnly: false,
      sameSite: 'lax',
      path: '/',
      maxAge: SESSION_TTL,
      secure,
    });

    res.cookies.set('impersonating_restaurant_id', restaurantId, {
      httpOnly: false,
      sameSite: 'lax',
      path: '/',
      maxAge: SESSION_TTL,
      secure,
    });

    return res;
  })
);
