import { notFound } from "next/navigation";
import { headers } from "next/headers";
import Link from "next/link";
import Image from "next/image";
import { Lock } from "lucide-react";
import { auth } from "@/lib/auth/server";
import {
  db,
  users,
  recipes,
  userFollows,
  userBlocks,
  cookingHistory,
  ratings,
  eq,
  and,
  desc,
  count,
  isNotNull,
} from "@epicure/db";
import { Avatar, AvatarImage, AvatarFallback } from "@/components/ui/avatar";
import { Badge } from "@/components/ui/badge";
import { FollowButton } from "@/components/social/follow-button";
import { BlockButton } from "@/components/social/block-button";
import { MessageButton } from "@/components/social/message-button";
import { getPublicUrl } from "@/lib/storage";
import { RecipeCoverPlaceholder } from "@/components/recipe/recipe-cover-placeholder";
import { ProfileTabs, type HistoryData, type PhotosData } from "@/components/profile/profile-tabs";

const PAGE_SIZE = 24;

type Params = {
  params: Promise<{ username: string }>;
  searchParams: Promise<{ page?: string; tab?: string; ppage?: string }>;
};

/** Consecutive-day streak (UTC calendar days) ending today or yesterday. */
function computeStreak(dates: Date[]): number {
  const daySet = new Set(dates.map((d) => d.toISOString().slice(0, 10)));
  const cursor = new Date();
  cursor.setUTCHours(0, 0, 0, 0);
  if (!daySet.has(cursor.toISOString().slice(0, 10))) {
    cursor.setUTCDate(cursor.getUTCDate() - 1);
    if (!daySet.has(cursor.toISOString().slice(0, 10))) return 0;
  }
  let streak = 0;
  while (daySet.has(cursor.toISOString().slice(0, 10))) {
    streak++;
    cursor.setUTCDate(cursor.getUTCDate() - 1);
  }
  return streak;
}

export async function generateMetadata({ params }: Params) {
  const { username } = await params;
  const user = await db.query.users.findFirst({ where: eq(users.username, username) });
  return { title: user ? `${user.name} (@${user.username})` : "Profile" };
}

export default async function UserProfilePage({ params, searchParams }: Params) {
  const { username } = await params;
  const { page: pageParam, tab: tabParam, ppage: ppageParam } = await searchParams;
  const page = Math.max(1, parseInt(pageParam ?? "1", 10) || 1);
  const offset = (page - 1) * PAGE_SIZE;
  const photoPage = Math.max(1, parseInt(ppageParam ?? "1", 10) || 1);
  const photoOffset = (photoPage - 1) * PAGE_SIZE;
  const activeTab = tabParam === "history" || tabParam === "photos" ? tabParam : "recipes";

  const session = await auth.api.getSession({ headers: await headers() });

  const user = await db.query.users.findFirst({ where: eq(users.username, username) });
  if (!user) notFound();

  const [followerCountRow, followingCountRow, recipeCountRow, publicRecipes] = await Promise.all([
    db
      .select({ count: count() })
      .from(userFollows)
      .where(eq(userFollows.followingId, user.id)),
    db
      .select({ count: count() })
      .from(userFollows)
      .where(eq(userFollows.followerId, user.id)),
    db
      .select({ count: count() })
      .from(recipes)
      .where(and(eq(recipes.authorId, user.id), eq(recipes.visibility, "public"))),
    db.query.recipes.findMany({
      where: and(eq(recipes.authorId, user.id), eq(recipes.visibility, "public")),
      orderBy: desc(recipes.createdAt),
      limit: PAGE_SIZE,
      offset,
      with: {
        photos: { orderBy: (t, { asc }) => asc(t.order), limit: 1 },
      },
    }),
  ]);

  const followerCount = followerCountRow[0]?.count ?? 0;
  const followingCount = followingCountRow[0]?.count ?? 0;
  const recipeCount = recipeCountRow[0]?.count ?? 0;
  const totalPages = Math.max(1, Math.ceil(recipeCount / PAGE_SIZE));

  let isFollowing = false;
  let isBlocked = false;
  const isOwnProfile = session?.user.id === user.id;
  if (session && !isOwnProfile) {
    const [followRow, blockRow] = await Promise.all([
      db.query.userFollows.findFirst({
        where: and(
          eq(userFollows.followerId, session.user.id),
          eq(userFollows.followingId, user.id),
        ),
      }),
      db.query.userBlocks.findFirst({
        where: and(
          eq(userBlocks.blockerId, session.user.id),
          eq(userBlocks.blockedId, user.id),
        ),
      }),
    ]);
    isFollowing = !!followRow;
    isBlocked = !!blockRow;
  }

  // Private accounts hide their recipe grid from anyone who isn't the owner or an
  // existing follower. This only affects what's rendered on this direct-link profile
  // page — it does not change access to a specific recipe's own direct URL, and it
  // does not gate new follow requests (following stays immediate, no approval step).
  const isPrivateHidden = user.isPrivate && !isOwnProfile && !isFollowing;

  // Cooking history and "cooked it" photo gallery are only meaningful (and visible) to the
  // profile owner: history reveals private behavioral/timing patterns, and photos may be
  // attached to reviews of recipes that aren't visible to other viewers (private recipes),
  // so surfacing them to non-owners could leak the existence of content they can't access.
  let historyData: HistoryData | null = null;
  let photosData: PhotosData | null = null;

  if (isOwnProfile) {
    const [totalCookedRow, cookedDatesRows, lastCookedRow, recentEntries, totalPhotosRow, photoRows] =
      await Promise.all([
        db.select({ count: count() }).from(cookingHistory).where(eq(cookingHistory.userId, user.id)),
        db.query.cookingHistory.findMany({
          where: eq(cookingHistory.userId, user.id),
          columns: { cookedAt: true },
          orderBy: desc(cookingHistory.cookedAt),
          limit: 3650,
        }),
        db.query.cookingHistory.findFirst({
          where: eq(cookingHistory.userId, user.id),
          orderBy: desc(cookingHistory.cookedAt),
          with: { recipe: { columns: { id: true, title: true } } },
        }),
        db.query.cookingHistory.findMany({
          where: eq(cookingHistory.userId, user.id),
          orderBy: desc(cookingHistory.cookedAt),
          limit: 20,
          with: { recipe: { columns: { id: true, title: true } } },
        }),
        db
          .select({ count: count() })
          .from(ratings)
          .where(and(eq(ratings.userId, user.id), isNotNull(ratings.photoKey))),
        db.query.ratings.findMany({
          where: and(eq(ratings.userId, user.id), isNotNull(ratings.photoKey)),
          orderBy: desc(ratings.createdAt),
          limit: PAGE_SIZE,
          offset: photoOffset,
          with: { recipe: { columns: { id: true, title: true } } },
        }),
      ]);

    const totalCooked = totalCookedRow[0]?.count ?? 0;
    const streak = computeStreak(cookedDatesRows.map((r) => r.cookedAt));
    const totalPhotos = totalPhotosRow[0]?.count ?? 0;

    historyData = {
      totalCooked,
      streak,
      lastCooked:
        lastCookedRow && lastCookedRow.recipe
          ? {
              recipeId: lastCookedRow.recipe.id,
              recipeTitle: lastCookedRow.recipe.title,
              cookedAt: lastCookedRow.cookedAt.toISOString(),
            }
          : null,
      recentEntries: recentEntries
        .filter((e) => e.recipe)
        .map((e) => ({
          id: e.id,
          recipeId: e.recipe!.id,
          recipeTitle: e.recipe!.title,
          cookedAt: e.cookedAt.toISOString(),
          servings: e.servings,
        })),
    };

    photosData = {
      items: photoRows
        .filter((r) => r.recipe && r.photoKey)
        .map((r) => ({
          id: r.id,
          recipeId: r.recipe!.id,
          recipeTitle: r.recipe!.title,
          photoKey: r.photoKey!,
          createdAt: r.createdAt.toISOString(),
        })),
      page: photoPage,
      totalPages: Math.max(1, Math.ceil(totalPhotos / PAGE_SIZE)),
      total: totalPhotos,
    };
  }

  const initials = user.name
    .split(" ")
    .slice(0, 2)
    .map((w) => w[0])
    .join("")
    .toUpperCase();

  const recipesSection = isPrivateHidden ? (
    <div className="text-center py-16 text-muted-foreground space-y-2">
      <Lock className="mx-auto h-8 w-8" />
      <p className="text-lg font-medium">This account is private</p>
      <p className="text-sm">Follow @{user.username} to see their recipes.</p>
    </div>
  ) : (
    publicRecipes.length > 0 ? (
      <div className="space-y-4">
        <h2 className="text-xl font-semibold">Recipes</h2>
        <div className="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 gap-4">
          {publicRecipes.map((recipe) => {
            const cover = recipe.photos[0];
            return (
              <Link
                key={recipe.id}
                href={`/recipes/${recipe.id}`}
                className="group block rounded-xl overflow-hidden border bg-card hover:shadow-md transition-shadow"
              >
                <div className="relative aspect-square bg-muted overflow-hidden">
                  {cover ? (
                    <Image
                      src={getPublicUrl(cover.storageKey)}
                      unoptimized
                      alt={recipe.title}
                      fill
                      sizes="(max-width: 640px) 50vw, (max-width: 768px) 33vw, 25vw"
                      className="object-cover group-hover:scale-105 transition-transform duration-200"
                    />
                  ) : (
                    <RecipeCoverPlaceholder recipe={recipe} />
                  )}
                </div>
                <div className="p-2">
                  <p className="text-sm font-medium leading-tight line-clamp-2">{recipe.title}</p>
                </div>
              </Link>
            );
          })}
        </div>

        {totalPages > 1 && (
          <div className="flex items-center justify-center gap-2 pt-2">
            {page > 1 && (
              <Link
                href={`/u/${username}${page - 1 > 1 ? `?page=${page - 1}` : ""}`}
                className="rounded-md border px-3 py-1.5 text-sm hover:bg-accent"
              >
                Previous
              </Link>
            )}
            <span className="text-sm text-muted-foreground px-2">
              Page {page} of {totalPages}
            </span>
            {page < totalPages && (
              <Link
                href={`/u/${username}?page=${page + 1}`}
                className="rounded-md border px-3 py-1.5 text-sm hover:bg-accent"
              >
                Next
              </Link>
            )}
          </div>
        )}
      </div>
    ) : (
      <div className="text-center py-16 text-muted-foreground">
        <p className="text-lg">No public recipes yet.</p>
      </div>
    )
  );

  return (
    <div className="max-w-4xl mx-auto space-y-10">
      {/* Profile header */}
      <div className="flex flex-col sm:flex-row gap-6 items-start sm:items-center">
        <Avatar className="h-24 w-24 shrink-0">
          {user.avatarUrl && <AvatarImage src={user.avatarUrl} alt={user.name} />}
          <AvatarFallback className="text-2xl">{initials}</AvatarFallback>
        </Avatar>

        <div className="flex-1 space-y-3">
          <div className="flex flex-wrap items-center gap-3">
            <div>
              <h1 className="text-2xl font-bold leading-tight flex items-center gap-2">
                {user.name}
                {isOwnProfile && user.isPrivate && (
                  <Badge variant="outline" className="gap-1 text-xs font-normal">
                    <Lock className="h-3 w-3" /> Private
                  </Badge>
                )}
              </h1>
              <p className="text-muted-foreground text-sm">@{user.username}</p>
            </div>
            {!isOwnProfile && session && (
              <div className="flex items-center gap-2">
                <FollowButton
                  targetUserId={user.id}
                  targetUsername={user.username!}
                  initialFollowing={isFollowing}
                />
                {!isBlocked && <MessageButton targetUsername={user.username!} />}
                <BlockButton targetUsername={user.username!} initialBlocked={isBlocked} />
              </div>
            )}
          </div>

          {user.bio && !isPrivateHidden && (
            <p className="text-sm leading-relaxed max-w-prose">{user.bio}</p>
          )}

          <div className="flex flex-wrap gap-2">
            <Badge variant="secondary">
              <span className="font-semibold mr-1">{recipeCount}</span> recipes
            </Badge>
            <Badge variant="secondary">
              <span className="font-semibold mr-1">{followerCount}</span> followers
            </Badge>
            <Badge variant="secondary">
              <span className="font-semibold mr-1">{followingCount}</span> following
            </Badge>
          </div>
        </div>
      </div>

      {/* Recipes / cooking history / photos */}
      {isOwnProfile && historyData && photosData ? (
        <ProfileTabs
          username={username}
          defaultTab={activeTab}
          recipesContent={recipesSection}
          history={historyData}
          photos={photosData}
        />
      ) : (
        recipesSection
      )}
    </div>
  );
}
