import { NextRequest, NextResponse } from "next/server";
import { z } from "zod";
import { db, mealPlans, mealPlanMembers, users, eq, and } from "@epicure/db";
import { requireSessionOrApiKey } from "@/lib/api-auth";

type Params = { params: Promise<{ weekStart: string }> };

async function getOrCreatePlan(userId: string, weekStart: string) {
  const existing = await db.query.mealPlans.findFirst({
    where: and(eq(mealPlans.userId, userId), eq(mealPlans.weekStart, weekStart)),
  });
  if (existing) return existing;

  const id = crypto.randomUUID();
  await db.insert(mealPlans).values({ id, userId, weekStart });
  return { id, userId, weekStart, createdAt: new Date() };
}

// ─── GET /api/v1/meal-plans/[weekStart]/members ──────────────────────────────
// Owner only — returns members joined with basic user info.
export async function GET(req: NextRequest, { params }: Params) {
  const { session, response } = await requireSessionOrApiKey(req);
  if (response) return response;
  const { weekStart } = await params;

  const plan = await db.query.mealPlans.findFirst({
    where: and(eq(mealPlans.userId, session!.user.id), eq(mealPlans.weekStart, weekStart)),
  });
  if (!plan) return NextResponse.json([]);

  const members = await db.query.mealPlanMembers.findMany({
    where: eq(mealPlanMembers.mealPlanId, plan.id),
    with: { user: true },
  });

  return NextResponse.json(
    members.map((m) => ({
      id: m.id,
      userId: m.userId,
      role: m.role,
      createdAt: m.createdAt,
      user: { name: m.user.name, username: m.user.username, avatarUrl: m.user.avatarUrl },
    }))
  );
}

// ─── POST /api/v1/meal-plans/[weekStart]/members ─────────────────────────────
// Owner only — invite by email or userId. Auto-creates the plan for this week if missing.
const InviteSchema = z
  .object({
    email: z.string().email().optional(),
    userId: z.string().optional(),
    role: z.enum(["viewer", "editor"]),
  })
  .refine((d) => d.email !== undefined || d.userId !== undefined, {
    message: "Provide either email or userId",
  });

export async function POST(req: NextRequest, { params }: Params) {
  const { session, response } = await requireSessionOrApiKey(req);
  if (response) return response;
  const { weekStart } = await params;

  const body = await req.json() as unknown;
  const parsed = InviteSchema.safeParse(body);
  if (!parsed.success) return NextResponse.json({ error: "Validation error" }, { status: 400 });

  const { email, userId, role } = parsed.data;

  const targetUser = await db.query.users.findFirst({
    where: email ? eq(users.email, email) : eq(users.id, userId!),
  });
  if (!targetUser) return NextResponse.json({ error: "User not found" }, { status: 404 });

  if (targetUser.id === session!.user.id) {
    return NextResponse.json({ error: "Cannot invite yourself" }, { status: 400 });
  }

  const plan = await getOrCreatePlan(session!.user.id, weekStart);

  const existing = await db.query.mealPlanMembers.findFirst({
    where: and(eq(mealPlanMembers.mealPlanId, plan.id), eq(mealPlanMembers.userId, targetUser.id)),
  });
  if (existing) return NextResponse.json({ error: "Already a member" }, { status: 409 });

  const memberId = crypto.randomUUID();
  await db.insert(mealPlanMembers).values({
    id: memberId,
    mealPlanId: plan.id,
    userId: targetUser.id,
    role,
  });

  return NextResponse.json({ id: memberId, mealPlanId: plan.id }, { status: 201 });
}

// ─── DELETE /api/v1/meal-plans/[weekStart]/members?memberId=… ────────────────
// Owner OR the member themselves can remove.
export async function DELETE(req: NextRequest, { params }: Params) {
  const { session, response } = await requireSessionOrApiKey(req);
  if (response) return response;
  const { weekStart } = await params;
  const memberId = req.nextUrl.searchParams.get("memberId");
  if (!memberId) return NextResponse.json({ error: "memberId required" }, { status: 400 });

  // Look up the member row first (not scoped to plans owned by the caller) —
  // a member removing themselves isn't the plan owner, so scoping the plan
  // lookup to `ownerId = session.user.id` would 404 before we ever reach the
  // self-leave check below.
  const member = await db.query.mealPlanMembers.findFirst({
    where: eq(mealPlanMembers.id, memberId),
  });
  if (!member) return NextResponse.json({ error: "Not found" }, { status: 404 });

  const plan = await db.query.mealPlans.findFirst({
    where: and(eq(mealPlans.id, member.mealPlanId), eq(mealPlans.weekStart, weekStart)),
  });
  if (!plan) return NextResponse.json({ error: "Not found" }, { status: 404 });

  const isOwner = plan.userId === session!.user.id;
  const isSelf = member.userId === session!.user.id;
  if (!isOwner && !isSelf) return NextResponse.json({ error: "Forbidden" }, { status: 403 });

  await db.delete(mealPlanMembers).where(eq(mealPlanMembers.id, memberId));
  return new NextResponse(null, { status: 204 });
}
