import "server-only";
import { eq } from "drizzle-orm";
import { cookies } from "next/headers";
import { getSession } from "@/lib/auth";
import { withPlatformAdmin } from "@/db/client";
import { adminUsers, adminUserBrands, brands } from "@/db/schema";
import type { AdminRole, AdminUser, TenantContext } from "@/lib/admin-permissions-types";

/**
 * Source of truth for the current admin user.
 *
 * Looks up the Neon Auth session, then resolves the user from the
 * `admin_users` table (linked to `neon_auth.user` by email).
 *
 * In development mode (NODE_ENV !== "production"), also checks for
 * dev_session cookie as a bypass for local testing.
 *
 * Returns `null` if:
 *   - No Neon Auth session (caller not signed in)
 *   - The session email doesn't match any `admin_users.email`
 *   - The user is a brand-scoped role (brand_admin / store_employee) and has no
 *     rows in `admin_user_brands` (not provisioned for any brand yet)
 *
 * Platform admins may be provisioned with zero brand links and still receive
 * access (they see all brands). Brand-scoped admins require >= 1 link row.
 *
 * Provisioning: an admin must ensure rows exist in both tables for the user's
 * email (matched from their Neon Auth session). Until provisioned, the layout
 * shows "Access Denied" — correct behavior.
 */
export async function getAdminUser(): Promise<AdminUser | null> {
  // Check for dev_session cookie in development mode
  if (process.env.NODE_ENV !== "production") {
    const cookieStore = await cookies();
    const devSession = cookieStore.get("dev_session")?.value;
    if (devSession === "platform_admin" || devSession === "brand_admin" || devSession === "store_employee") {
      return buildDevAdmin(devSession as AdminRole);
    }
  }

  let sessionEmail: string | null = null;
  try {
    const { data: session } = await getSession();
    sessionEmail = session?.user?.email ?? null;
  } catch (err) {
    console.error("[admin-permissions] getSession() failed:", err);
    return null;
  }

  if (!sessionEmail) {
    return null;
  }

  try {
    return await withPlatformAdmin(async (db) => {
      const userRows = await db
        .select()
        .from(adminUsers)
        .where(eq(adminUsers.email, sessionEmail.toLowerCase()))
        .limit(1);
      const user = userRows[0];
      if (!user) {
        return null;
      }

      const role = (user.role as AdminRole) || "brand_admin";

      // Load all brand memberships for this admin (supports multi-brand admins).
      // The redundant adminUsers join was removed; role lives on admin_users.
      const membershipRows = await db
        .select({
          brandId: adminUserBrands.brandId,
          brandName: brands.name,
          brandSlug: brands.slug,
        })
        .from(adminUserBrands)
        .innerJoin(brands, eq(brands.id, adminUserBrands.brandId))
        .where(eq(adminUserBrands.adminUserId, user.id));

      // Brand-scoped roles (brand_admin, store_employee) require at least one brand link.
      // Platform admins may have zero or more explicit links; they get cross-brand access via role.
      if (membershipRows.length === 0 && role !== "platform_admin") {
        // Signed in but not provisioned for any brand.
        return null;
      }

      const first = membershipRows[0] ?? null;
      return buildAdminUser({
        id: user.id,
        email: user.email,
        displayName: user.name,
        brandId: first?.brandId ?? null,
        brandName: first?.brandName ?? null,
        brandSlug: first?.brandSlug ?? null,
        role,
        active: true,
        brandIds: membershipRows.map((m) => m.brandId),
      });
    });
  } catch (err) {
    console.error("[admin-permissions] Database query failed:", err);
    return null;
  }
}

/**
 * Resolves the current admin user AND their brand. Returns `null` if
 * the user is not signed in or has no brand. For platform_admin (no
 * brand), `brand` is `null` and callers should use `withPlatformAdmin`
 * to query across all brands.
 */
export async function getCurrentTenant(): Promise<TenantContext | null> {
  const user = await getAdminUser();
  if (!user) return null;
  if (!user.brand_id) {
    // platform_admin — no specific brand
    return null;
  }
  return {
    user,
    tenant: {
      id: user.brand_id,
      name: user.display_name ?? user.brand_slug ?? "Unknown",
      slug: user.brand_slug ?? "unknown",
      status: "active",
    },
  };
}

// ────────────────────────────────────────────────────────────────────────
// Re-exports for backward compat
// ────────────────────────────────────────────────────────────────────────

export type { AdminUser, AdminRole, TenantContext } from "@/lib/admin-permissions-types";

/**
 * @deprecated Kept for unit tests that exercise the dev shim path.
 * Production code should never call this — `getAdminUser()` only reads
 * the Neon Auth session now.
 */
export function buildDevAdmin(role: AdminRole): AdminUser {
  const isPlatform = role === "platform_admin";
  const brandId = isPlatform ? null : "dev-brand";
  return {
    id: "dev",
    user_id: "dev",
    email: null,
    display_name: "Demo Admin",
    brand_id: brandId,
    brand_ids: brandId ? [brandId] : [],
    brand_slug: isPlatform ? null : "tuxedo",
    role,
    active: true,
    auth_provider: "dev",
    ...permissionsForRole(role),
    must_change_password: false,
  };
}

function buildAdminUser(input: {
  id: string;
  email: string;
  displayName: string | null;
  brandId: string | null;
  brandName: string | null;
  brandSlug: string | null;
  role: AdminRole;
  active: boolean;
  brandIds?: string[];
}): AdminUser {
  const brandIds = input.brandIds && input.brandIds.length > 0
    ? input.brandIds
    : (input.brandId ? [input.brandId] : []);
  return {
    id: input.id,
    user_id: input.id,
    email: input.email,
    display_name: input.displayName,
    brand_id: input.brandId,
    brand_ids: brandIds,
    brand_slug: input.brandSlug,
    role: input.role,
    active: input.active,
    auth_provider: "neon_auth",
    ...permissionsForRole(input.role),
  };
}

/**
 * Single source of truth for "what can a role do". Used by both the
 * dev shim and the real user lookup so the demo and the real thing
 * behave identically.
 */
export function permissionsForRole(role: AdminRole) {
  if (role === "platform_admin") {
    return {
      can_manage_products: true,
      can_manage_stops: true,
      can_manage_orders: true,
      can_manage_pickup: true,
      can_manage_messages: true,
      can_manage_refunds: true,
      can_manage_users: true,
      can_manage_water_log: true,
      can_manage_reports: true,
      can_manage_settings: true,
      can_manage_billing: true,
      can_manage_branding: true,
      can_manage_marketing: true,
      can_manage_team: true,
    };
  }
  if (role === "brand_admin") {
    return {
      can_manage_products: true,
      can_manage_stops: true,
      can_manage_orders: true,
      can_manage_pickup: true,
      can_manage_messages: true,
      can_manage_refunds: true,
      can_manage_users: false,
      can_manage_water_log: true,
      can_manage_reports: true,
      can_manage_settings: true,
      can_manage_billing: true,
      can_manage_branding: true,
      can_manage_marketing: true,
      can_manage_team: true,
    };
  }
  // store_employee
  return {
    can_manage_products: false,
    can_manage_stops: false,
    can_manage_orders: true,
    can_manage_pickup: true,
    can_manage_messages: false,
    can_manage_refunds: false,
    can_manage_users: false,
    can_manage_water_log: false,
    can_manage_reports: false,
    can_manage_settings: false,
    can_manage_billing: false,
    can_manage_branding: false,
    can_manage_marketing: false,
    can_manage_team: false,
  };
}
