import { redirect } from "next/navigation";
import { and, eq } from "drizzle-orm";
import { auth } from "@/core/auth/auth";
import {
  authorize,
  hasPlatformAdminAccess,
  requireAuthorization,
  type AuthPrincipal,
  type TenantPermission,
} from "@/core/authorization/authorize";
import { getDb } from "@/core/db/client";
import { tenants } from "@/core/db/schema";
import { getRequestHostname } from "@/core/tenant/request-tenant";
import type { TenantContext } from "@/core/tenant/types";

export type DashboardContext = {
  principal: AuthPrincipal;
  tenant: TenantContext;
  user: {
    id: string;
    name: string | null | undefined;
    email: string | null | undefined;
  };
};

export class DashboardAuthError extends Error {
  status: number;
  code?: "NO_MEMBERSHIP" | "FORBIDDEN" | "UNAUTHENTICATED";

  constructor(
    status: number,
    message: string,
    code?: DashboardAuthError["code"],
  ) {
    super(message);
    this.name = "DashboardAuthError";
    this.status = status;
    this.code = code;
  }
}

async function resolveDashboardContext(
  requiredPermission?: TenantPermission,
): Promise<DashboardContext> {
  const session = await auth();
  if (!session?.user?.id) {
    throw new DashboardAuthError(401, "Unauthenticated", "UNAUTHENTICATED");
  }

  const principal: AuthPrincipal = {
    userId: session.user.id,
    platformRole: session.user.platformRole,
    tenantMemberships: session.user.tenantMemberships ?? [],
  };

  // Never trust client-supplied tenant headers. Membership comes from session only.
  const membership = principal.tenantMemberships.find(
    (m) => m.status === "active",
  );

  if (!membership) {
    throw new DashboardAuthError(
      403,
      "No active studio membership",
      "NO_MEMBERSHIP",
    );
  }

  if (requiredPermission) {
    const result = authorize(principal, requiredPermission, {
      tenantId: membership.tenantId,
    });
    if (!result.allowed) {
      throw new DashboardAuthError(403, result.reason, "FORBIDDEN");
    }
  }

  const db = getDb();
  const [tenant] = await db
    .select()
    .from(tenants)
    .where(
      and(eq(tenants.id, membership.tenantId), eq(tenants.status, "active")),
    )
    .limit(1);

  if (!tenant) {
    throw new DashboardAuthError(403, "Tenant unavailable", "FORBIDDEN");
  }

  const hostname = await getRequestHostname();

  return {
    principal,
    user: {
      id: session.user.id,
      name: session.user.name,
      email: session.user.email,
    },
    tenant: {
      tenantId: tenant.id,
      tenantSlug: tenant.slug,
      studioName: tenant.studioName,
      status: tenant.status,
      hostname,
      domainId: null,
      domainType: "platform",
      isPrimaryDomain: true,
    },
  };
}

/**
 * Page/server-action helper — redirects to login/admin/register on failure.
 */
export async function requireDashboardContext(
  requiredPermission?: TenantPermission,
): Promise<DashboardContext> {
  try {
    return await resolveDashboardContext(requiredPermission);
  } catch (error) {
    if (error instanceof DashboardAuthError) {
      if (error.status === 401) redirect("/?auth=login");

      if (error.code === "NO_MEMBERSHIP") {
        const session = await auth();
        if (
          session?.user &&
          hasPlatformAdminAccess({
            userId: session.user.id,
            platformRole: session.user.platformRole,
            tenantMemberships: session.user.tenantMemberships ?? [],
          })
        ) {
          redirect("/admin");
        }
        redirect("/register");
      }

      redirect("/dashboard");
    }
    throw error;
  }
}

/**
 * API helper — returns auth errors instead of redirects.
 */
export async function requireDashboardApiContext(
  requiredPermission?: TenantPermission,
): Promise<DashboardContext> {
  return resolveDashboardContext(requiredPermission);
}

export { requireAuthorization };
