import { NextRequest, NextResponse } from "next/server";
import { z } from "zod";
import { and, eq } from "drizzle-orm";
import { getServerSession } from "next-auth";
import { AuthOptions } from "@/app/api/auth/[...nextauth]/authOptions";
import { db } from "@/app/db/db";
import { portfolioUsers } from "@/app/db/schema/portfolio";
import { userPortfolioConfig } from "@/app/db/schema/user_portfolio_config";
import { buildStarChange } from "@/app/lib/portfolioUserConfig";

const ConfigSchema = z
  .object({
    starred: z.boolean().optional(),
    folderId: z.string().regex(/^\d+$/).nullable().optional(),
  })
  .refine((v) => v.starred !== undefined || v.folderId !== undefined, {
    message: "Nothing to update",
  });

// Upserts the caller's personal config for one portfolio (star / move to
// folder). Rows are created lazily: no row means all defaults.
export async function PATCH(
  req: NextRequest,
  props: { params: Promise<{ portfolioId: string }> },
) {
  try {
    const session = await getServerSession(AuthOptions);
    if (!session?.user?.dbId) {
      return NextResponse.json({ error: "Unauthenticated" }, { status: 401 });
    }
    const userId = session.user.dbId;

    const { portfolioId } = await props.params;
    if (!/^\d+$/.test(portfolioId)) {
      return NextResponse.json({ error: "Portfolio not found" }, { status: 404 });
    }

    const parsed = ConfigSchema.safeParse(await req.json());
    if (!parsed.success) {
      return NextResponse.json({ error: "Invalid config" }, { status: 400 });
    }

    // Config only exists for portfolios the user can actually see.
    const membership = await db
      .select({ id: portfolioUsers.id })
      .from(portfolioUsers)
      .where(
        and(
          eq(portfolioUsers.userId, userId),
          eq(portfolioUsers.portfolioId, BigInt(portfolioId)),
        ),
      );
    if (membership.length === 0) {
      return NextResponse.json({ error: "Portfolio not found" }, { status: 404 });
    }

    const change: Partial<{
      starredAt: Date | null;
      folderId: bigint | null;
    }> = {};
    if (parsed.data.starred !== undefined) {
      change.starredAt = buildStarChange({
        starred: parsed.data.starred,
        now: new Date(),
      }).starredAt;
    }
    if (parsed.data.folderId !== undefined) {
      change.folderId =
        parsed.data.folderId === null ? null : BigInt(parsed.data.folderId);
    }

    await db
      .insert(userPortfolioConfig)
      .values({
        userId,
        portfolioId: BigInt(portfolioId),
        ...change,
      })
      .onConflictDoUpdate({
        target: [userPortfolioConfig.userId, userPortfolioConfig.portfolioId],
        set: { ...change, updatedAt: new Date() },
      });

    return NextResponse.json({ ok: true });
  } catch (err) {
    console.error("Error updating portfolio config:", err);
    return NextResponse.json({ error: "Server error" }, { status: 500 });
  }
}
