import type { NextRequest } from "next/server";
import { convexQuery } from "./convex-client";
import { CONVEX_PATHS } from "./convex-paths";

export interface ConvexAppUser {
  id: string;
  convexId: string;
  email: string;
  name: string;
  role?: string;
  clerkId?: string | null;
  stripeCustomerId?: string | null;
  companyName?: string | null;
  companySize?: string | null;
  phoneNumber?: string | null;
  website?: string | null;
  country?: string | null;
  city?: string | null;
  preferredCurrency?: string | null;
  selectedPackage?: string | null;
  selectedBillingPeriod?: "monthly" | "yearly" | null;
  appUserId?: string | null;
  prismaId?: string | null;
  isTrialOver?: boolean | null;
  setupFeePaid?: boolean | null;
}

export type RawConvexUser = {
  _id: string;
  email: string;
  name: string;
  role?: string;
  clerkId?: string | null;
  stripeCustomerId?: string | null;
  companyName?: string | null;
  companySize?: string | null;
  phoneNumber?: string | null;
  website?: string | null;
  country?: string | null;
  city?: string | null;
  preferredCurrency?: string | null;
  selectedPackage?: string | null;
  selectedBillingPeriod?: "monthly" | "yearly" | null;
  avatar?: string | null;
  industry?: string | null;
  password?: string | null;
  emailVerified?: number | null;
  createdAt?: number | null;
  onboardingComplete?: boolean;
  whatsappConnected?: boolean;
  whatsappNumber?: string | null;
  appUserId?: string | null;
  prismaId?: string | null;
  isTrialOver?: boolean | null;
  setupFeePaid?: boolean | null;
};

interface AuthSession {
  user?: {
    id?: string | null;
    email?: string | null;
  };
}

type AuthFunction = () => Promise<AuthSession | null>;

export function getStableAppUserId(user: {
  appUserId?: string | null;
  prismaId?: string | null;
  _id?: string | null;
}): string {
  return user.appUserId ?? user.prismaId ?? user._id ?? "";
}

function normalizeUser(user: RawConvexUser): ConvexAppUser {
  return {
    id: getStableAppUserId(user),
    convexId: user._id,
    email: user.email,
    name: user.name,
    role: user.role,
    clerkId: user.clerkId ?? null,
    stripeCustomerId: user.stripeCustomerId ?? null,
    companyName: user.companyName ?? null,
    companySize: user.companySize ?? null,
    phoneNumber: user.phoneNumber ?? null,
    website: user.website ?? null,
    country: user.country ?? null,
    city: user.city ?? null,
    preferredCurrency: user.preferredCurrency ?? null,
    selectedPackage: user.selectedPackage ?? null,
    selectedBillingPeriod: user.selectedBillingPeriod ?? null,
    appUserId: user.appUserId ?? null,
    prismaId: user.prismaId ?? null,
    isTrialOver: user.isTrialOver ?? null,
    setupFeePaid: user.setupFeePaid ?? null,
  };
}

export async function getRawConvexUserByEmail(
  email: string,
): Promise<RawConvexUser | null> {
  return await convexQuery<RawConvexUser>(CONVEX_PATHS.getUserByEmail, {
    email: email.toLowerCase(),
  });
}

export async function getConvexUserByEmail(
  email: string,
): Promise<ConvexAppUser | null> {
  const user = await getRawConvexUserByEmail(email);
  return user ? normalizeUser(user) : null;
}

export async function getRawConvexUserByClerkId(
  clerkId: string,
): Promise<RawConvexUser | null> {
  return await convexQuery<RawConvexUser>(CONVEX_PATHS.getUserByClerkId, {
    clerkId,
  });
}

export async function getConvexUserByClerkId(
  clerkId: string,
): Promise<ConvexAppUser | null> {
  const user = await getRawConvexUserByClerkId(clerkId);
  return user ? normalizeUser(user) : null;
}

export async function getRawConvexUserByAnyId(
  id: string,
): Promise<RawConvexUser | null> {
  return await convexQuery<RawConvexUser>(CONVEX_PATHS.getUserByAnyId, { id });
}

export async function getRawConvexUserByAppUserId(
  appUserId: string,
): Promise<RawConvexUser | null> {
  return (
    (await convexQuery<RawConvexUser>(CONVEX_PATHS.getUserByAppUserId, {
      appUserId,
    })) ?? (await getRawConvexUserByAnyId(appUserId))
  );
}

export async function getConvexUserByAppUserId(
  appUserId: string,
): Promise<ConvexAppUser | null> {
  const user = await getRawConvexUserByAppUserId(appUserId);
  return user ? normalizeUser(user) : null;
}

export async function getAuthenticatedConvexUser(
  request: NextRequest,
  authFunction: AuthFunction,
): Promise<ConvexAppUser | null> {
  void request;

  const session = await authFunction();
  if (session?.user?.email) {
    const user = await getConvexUserByEmail(session.user.email);
    if (user) return user;
  }

  const sessionUserId =
    session?.user && "id" in session.user
      ? (session.user as { id?: string }).id
      : undefined;
  if (sessionUserId) {
    const byId = await getConvexUserByAppUserId(sessionUserId);
    if (byId) return byId;
  }

  try {
    const { currentUser } = await import("@clerk/nextjs/server");
    const clerkUser = await currentUser();
    if (clerkUser?.id) {
      const byClerkId = await getConvexUserByClerkId(clerkUser.id);
      if (byClerkId) return byClerkId;

      const primaryEmail = clerkUser.emailAddresses.find(
        (email) => email.id === clerkUser.primaryEmailAddressId,
      )?.emailAddress;
      if (primaryEmail) {
        const byEmail = await getConvexUserByEmail(primaryEmail);
        if (byEmail) return byEmail;
      }
    }
  } catch {
    // Clerk not configured or not authenticated.
  }

  return null;
}
