/**
 * Dashboard Page - SERVER-SIDE PROTECTED
 *
 * Auth resolution order:
 *   1. Clerk-backed auth() — covers bridged Clerk sessions with app DB user
 *   2. OTP auth_token cookie — covers legacy OTP login
 *   3. Direct Clerk currentUser() — covers new signups not yet bridged
 *   4. All fail → redirect to clerk-login
 */

import { redirect } from "next/navigation";
import { auth } from "@/lib/auth";
import { type Lang } from "@/lib/config";
import { logger } from "@/lib/logger";
import { verifySecureToken } from "@/lib/secure-tokens";
import { seedIndustryDefaults } from "@/lib/services/appointment-type-seeder";
import { DashboardService } from "@/lib/services/dashboard.service";
import type { Session } from "next-auth";
import NewDashboardClient from "./NewDashboardClient";

// 🔒 CRITICAL: Force dynamic rendering - never cache this page
export const dynamic = "force-dynamic";
export const revalidate = 0;

export default async function DashboardPage({
  params,
  searchParams,
}: {
  params: { lang: Lang };
  searchParams?: { welcome?: string };
}) {
  const { lang } = params;
  const showWelcome = searchParams?.welcome === "true";

  // ── Unified auth resolution ──
  let userId: string | undefined;
  let userEmail: string | undefined;
  let userName: string | undefined;
  let sessionRole: string | undefined;
  let sessionOrganizationId: string | null = null;
  let sessionOrgRole: string | null = null;
  let sessionAllowedTabs: string[] | null = null;
  let sessionStripeCustomerId: string | null = null;
  let sessionExpires: string | undefined;

  // 1. Try Clerk auth directly first (most reliable when Clerk is the auth provider)
  try {
    const { currentUser } = await import("@clerk/nextjs/server");
    const clerkUser = await currentUser();
    if (clerkUser) {
      const email = clerkUser.emailAddresses[0]?.emailAddress?.toLowerCase();
      if (email) {
        userEmail = email;
        userName =
          [clerkUser.firstName, clerkUser.lastName].filter(Boolean).join(" ") ||
          undefined;
        // Look up the app user from Convex by email
        const { convexQuery } = await import("@/lib/convex-client");
        const convexUser = await convexQuery<Record<string, unknown>>(
          "auth/queries:getUserByEmail",
          { email },
        );
        if (convexUser) {
          userId =
            (convexUser.prismaId as string) ||
            (convexUser.appUserId as string) ||
            (convexUser._id as string);
          sessionRole = (convexUser.role as string) || undefined;
        } else {
          // Clerk user exists but not in Convex — use Clerk ID
          userId = clerkUser.id;
        }
      }
    }
  } catch (err) {
    logger.warn("Clerk direct auth failed in dashboard", {
      error: err instanceof Error ? err.message : String(err),
    });
  }

  // 2. Fallback: Try NextAuth session (bridges Clerk → app DB)
  if (!userId) {
    const session = await auth();
    if (session?.user?.id) {
      userId = session.user.id;
      userEmail = session.user.email || undefined;
      userName = session.user.name || undefined;
      sessionRole = session.user.role;
      sessionOrganizationId = session.user.organizationId ?? null;
      sessionOrgRole = session.user.orgRole ?? null;
      sessionAllowedTabs =
        (session.user.allowedTabs as string[] | null) ?? null;
      sessionStripeCustomerId = session.user.stripeCustomerId ?? null;
      sessionExpires = session.expires;
    }
  }

  // 3. Try OTP auth_token cookie (legacy login)
  if (!userId) {
    const { cookies: nextCookies } = await import("next/headers");
    const cookieStore = await nextCookies();
    const authToken = cookieStore.get("auth_token")?.value;

    if (authToken) {
      try {
        const tokenData = await verifySecureToken(authToken);
        if (tokenData) {
          userId = tokenData.userId as string;
          userEmail = tokenData.email as string;
          userName = tokenData.fullName as string;
        }
      } catch {
        // token invalid/expired — continue to next method
      }
    }
  }

  // 4. No valid authentication found — send to login with return URL
  if (!userId) {
    redirect(
      `/${lang}/clerk-login?redirect_url=${encodeURIComponent(`/${lang}/dashboard`)}`,
    );
  }

  // ── Data layer: Fetch initial dashboard data ──
  const initialData = await DashboardService.getInitialData(userId, {
    email: userEmail,
    name: userName,
  });

  // Redirect if access denied — but NEVER redirect back to clerk-login
  // If the user got this far with a userId, they are authenticated.
  // Only redirect for genuinely missing onboarding or expired subscriptions.
  if (!initialData.accessStatus.hasAccess) {
    const reason = initialData.accessStatus.reason;
    const redirectUrl = initialData.accessStatus.redirectUrl?.replace(
      "/en/",
      `/${lang}/`,
    );

    // Only redirect for clear onboarding/pricing issues, never to clerk-login
    if (
      reason === "Onboarding not completed" &&
      redirectUrl?.includes("onboarding")
    ) {
      redirect(redirectUrl);
    }
    if (
      reason === "No active subscription" &&
      (redirectUrl?.includes("pricing") || redirectUrl?.includes("reactivate"))
    ) {
      redirect(redirectUrl);
    }
    // For all other cases (user not found in Convex, system errors, etc.)
    // — allow dashboard to render with whatever data we have.
    // This prevents redirect loops when Convex is intermittently unavailable.
    logger.warn("Dashboard access denied but allowing render to prevent loop", {
      userId,
      reason,
      redirectUrl,
    });
  }

  // Enrich session data from Convex when fields are incomplete
  // (e.g. name/email missing after OTP login or incomplete Clerk bridge)
  if (userEmail && (!userName || !sessionStripeCustomerId)) {
    try {
      const { getConvexUserByEmail } = await import("@/lib/convex-auth-state");
      const convexUser = await getConvexUserByEmail(userEmail);
      if (convexUser) {
        if (!userName && convexUser.name) userName = convexUser.name;
        if (!sessionStripeCustomerId && convexUser.stripeCustomerId) {
          sessionStripeCustomerId = convexUser.stripeCustomerId;
        }
        if (!sessionRole && convexUser.role) sessionRole = convexUser.role;
      }
    } catch {
      // Convex unavailable — continue with what we have
    }
  }

  // Build session object for the client component
  const dashboardSession: Session = {
    user: {
      id: userId,
      email: userEmail || "",
      name: userName,
      role: sessionRole,
      organizationId: sessionOrganizationId,
      orgRole: sessionOrgRole,
      allowedTabs: sessionAllowedTabs,
      stripeCustomerId: sessionStripeCustomerId,
    },
    expires: sessionExpires || new Date(Date.now() + 7200000).toISOString(),
  };

  // Integration config — derived from Convex user + org data.
  // `initialData` is computed by DashboardService which now fetches both the
  // user row (legacy n8n fields) and the organization row (Twilio/Meta WA
  // credentials). Consumers should treat `hasWhatsApp` as the single source
  // of truth for "is WhatsApp connected" on the dashboard card.
  const integrationConfig = initialData.integrationConfig;

  // Seed industry-specific appointment types on first visit (if org has none)
  const { convexQuery } = await import("@/lib/convex-client");
  const orgState = await convexQuery<Record<string, unknown>>(
    "organizations/queries:getOrganizationStateByUserId",
    { userId },
  );

  if (orgState?.organization) {
    const orgId =
      ((orgState.organization as Record<string, unknown>).id as string) ||
      ((orgState.organization as Record<string, unknown>)._id as string);
    if (orgId) {
      const appointmentTypes = await convexQuery<unknown[]>(
        "appointment_types/queries:getByOrganization",
        { organizationId: orgId },
      );
      if (!appointmentTypes || appointmentTypes.length === 0) {
        const convexUser = await convexQuery<Record<string, unknown>>(
          "auth/queries:getUserByEmail",
          { email: userEmail || "" },
        );
        // Fire-and-forget — don't block page render
        seedIndustryDefaults(
          userId,
          orgId,
          convexUser?.industry as string | undefined,
        ).catch((err) =>
          console.error("Failed to seed appointment types:", err),
        );
      }
    }
  }

  return (
    <NewDashboardClient
      lang={lang}
      session={dashboardSession}
      integrationConfig={integrationConfig}
      showWelcome={showWelcome}
    />
  );
}
