import { and, eq } from 'drizzle-orm';
import { auth } from '@/auth';
import { memberships, organizations } from '@/db/schema';
import { db } from '@/lib/db';

export class AuthError extends Error {
  status: number;

  constructor(message: string, status: number) {
    super(message);
    this.name = 'AuthError';
    this.status = status;
  }
}

export async function requireSession() {
  const session = await auth();

  if (!session?.user?.id) {
    throw new AuthError('Unauthorized', 401);
  }

  return session;
}

export async function requireSystemRole(role: 'super_admin') {
  const session = await requireSession();

  if (session.user.systemRole !== role) {
    throw new AuthError('Forbidden', 403);
  }

  return session;
}

export async function requireOrganizationAccess(options?: {
  role?: string;
  roles?: string[];
  permission?: string;
  permissions?: string[];
  allowSuperAdminBypass?: boolean;
}) {
  const session = await requireSession();

  if (options?.allowSuperAdminBypass !== false && session.user.systemRole === 'super_admin') {
    const activeOrganization = session.user.organizations.find(
      (organization) => organization.id === session.user.activeOrganizationId
    );

    if (!activeOrganization) {
      throw new AuthError('Organization membership required', 403);
    }

      return {
        session,
        membership: {
          userId: session.user.id,
          organizationId: activeOrganization.id,
          role: activeOrganization.role,
          businessRole: activeOrganization.businessRole,
          permissions: session.user.activePermissions
        },
      organization: {
        id: activeOrganization.id,
        name: activeOrganization.name,
        slug: activeOrganization.slug,
        plan: activeOrganization.plan,
        imageUrl: activeOrganization.imageUrl
      }
    };
  }

  if (!session.user.activeOrganizationId) {
    throw new AuthError('Organization membership required', 403);
  }

  const membership = await db.query.memberships.findFirst({
    where: and(
      eq(memberships.userId, session.user.id),
      eq(memberships.organizationId, session.user.activeOrganizationId)
    )
  });

  if (!membership) {
    throw new AuthError('Forbidden', 403);
  }

  const allowedRoles = options?.roles ?? (options?.role ? [options.role] : []);
  const allowedPermissions = options?.permissions ?? (options?.permission ? [options.permission] : []);

  if (allowedRoles.length > 0 && !allowedRoles.includes(membership.role)) {
    throw new AuthError('Forbidden', 403);
  }

  if (
    allowedPermissions.length > 0 &&
    !allowedPermissions.every((permission) => membership.permissions.includes(permission))
  ) {
    throw new AuthError('Forbidden', 403);
  }

  const organization = await db.query.organizations.findFirst({
    where: eq(organizations.id, membership.organizationId)
  });

  if (!organization) {
    throw new AuthError('Organization not found', 404);
  }

  return {
    session,
    membership,
    organization
  };
}
