import { hash } from 'bcryptjs';
import { eq } from 'drizzle-orm';
import { NextRequest, NextResponse } from 'next/server';
import { memberships, users } from '@/db/schema';
import { db } from '@/lib/db';
import { AuthError } from '@/lib/auth/session';
import {
  assertManageableTargetUser,
  buildMembershipValues,
  parseUserMutationPayload,
  requireUserManagementAccess,
  validateManagedOrganizations
} from '../_lib';

type Params = { params: Promise<{ id: string }> };

export async function PUT(request: NextRequest, { params }: Params) {
  try {
    const { id } = await params;
    const { session, isSuperAdmin, manageableOrganizationIds } = await requireUserManagementAccess();
    const payload = parseUserMutationPayload(await request.json());
    const targetUser = await assertManageableTargetUser(id, manageableOrganizationIds, isSuperAdmin);

    await validateManagedOrganizations(payload.memberships, manageableOrganizationIds, isSuperAdmin);

    if (!isSuperAdmin && payload.systemRole !== 'user') {
      return NextResponse.json({ message: 'Forbidden' }, { status: 403 });
    }

    if (!isSuperAdmin && targetUser.systemRole === 'super_admin') {
      return NextResponse.json({ message: 'Forbidden' }, { status: 403 });
    }

    const userWithSameEmail = await db.query.users.findFirst({
      where: eq(users.email, payload.email)
    });

    if (userWithSameEmail && userWithSameEmail.id !== id) {
      return NextResponse.json(
        { message: 'An account with this email already exists' },
        { status: 409 }
      );
    }

    const updateValues: {
      name: string;
      email: string;
      systemRole: 'super_admin' | 'user';
      activeOrganizationId: string | null;
      passwordHash?: string;
    } = {
      name: payload.name,
      email: payload.email,
      systemRole: targetUser.systemRole === 'super_admin' ? 'super_admin' : 'user',
      activeOrganizationId: payload.memberships[0]?.organizationId ?? null
    };

    if (payload.password) {
      if (payload.password.length < 8) {
        return NextResponse.json({ message: 'Password must be at least 8 characters' }, { status: 400 });
      }

      updateValues.passwordHash = await hash(payload.password, 10);
    }

    await db.update(users).set(updateValues).where(eq(users.id, id));

    await db.delete(memberships).where(eq(memberships.userId, id));
    await db.insert(memberships).values(buildMembershipValues(id, payload.memberships));

    if (
      session.user.id === id &&
      !payload.memberships.some(
        (membership) => membership.organizationId === (session.user.activeOrganizationId ?? '')
      )
    ) {
      await db
        .update(users)
        .set({ activeOrganizationId: payload.memberships[0]?.organizationId ?? null })
        .where(eq(users.id, id));
    }

    return NextResponse.json({
      success: true,
      message: 'User updated successfully'
    });
  } catch (error) {
    if (error instanceof AuthError) {
      return NextResponse.json({ message: error.message }, { status: error.status });
    }

    if (error instanceof Error) {
      return NextResponse.json({ message: error.message }, { status: 400 });
    }

    return NextResponse.json({ message: 'Unable to update user' }, { status: 500 });
  }
}

export async function DELETE(_request: NextRequest, { params }: Params) {
  try {
    const { id } = await params;
    const { session, isSuperAdmin, manageableOrganizationIds } = await requireUserManagementAccess();

    if (session.user.id === id) {
      return NextResponse.json({ message: 'You cannot delete your own account' }, { status: 400 });
    }

    await assertManageableTargetUser(id, manageableOrganizationIds, isSuperAdmin);

    await db.delete(memberships).where(eq(memberships.userId, id));
    await db.delete(users).where(eq(users.id, id));

    return NextResponse.json({
      success: true,
      message: 'User deleted successfully'
    });
  } catch (error) {
    if (error instanceof AuthError) {
      return NextResponse.json({ message: error.message }, { status: error.status });
    }

    return NextResponse.json({ message: 'Unable to delete user' }, { status: 500 });
  }
}
