import { NextRequest, NextResponse } from "next/server";
import { getServerSession } from "next-auth";
import { and, eq } from "drizzle-orm";
import { z } from "zod";

import { AuthOptions } from "@/app/api/auth/[...nextauth]/authOptions";
import { db } from "@/app/db/db";
import { portfolioCapabilities, portfolioUsers } from "@/app/db/schema/portfolio";
import { user } from "@/app/db/schema/users";
import { updatePibiRequest } from "@/app/lib/updatePibiRequest";
import { deletePibiRequest } from "@/app/lib/deletePibiRequest";

const patchSchema = z.object({
  dealId: z.string().min(1, "dealId is required"),
  measureName: z.string().min(1).optional(),
  orderedAt: z.string().datetime().optional(),
  completedAt: z.string().datetime().nullable().optional(),
});

async function resolveApprover(
  email: string,
  portfolioId: string,
): Promise<
  | { ok: true; userId: bigint }
  | { ok: false; status: 401 | 403 | 404; error: string }
> {
  const userRow = await db
    .select({ id: user.id })
    .from(user)
    .where(eq(user.email, email))
    .limit(1);

  if (!userRow[0]) return { ok: false, status: 404, error: "User not found" };

  const portfolioUserRow = await db
    .select({ role: portfolioUsers.role })
    .from(portfolioUsers)
    .where(
      and(
        eq(portfolioUsers.portfolioId, BigInt(portfolioId)),
        eq(portfolioUsers.userId, userRow[0].id),
      ),
    )
    .limit(1);

  if (!portfolioUserRow[0]?.role) {
    return { ok: false, status: 403, error: "No portfolio access" };
  }

  const capabilityRows = await db
    .select({ capability: portfolioCapabilities.capability })
    .from(portfolioCapabilities)
    .where(
      and(
        eq(portfolioCapabilities.portfolioId, BigInt(portfolioId)),
        eq(portfolioCapabilities.userId, userRow[0].id),
      ),
    );

  if (!capabilityRows.map((r) => r.capability).includes("approver")) {
    return { ok: false, status: 403, error: "Approver capability required" };
  }

  return { ok: true, userId: userRow[0].id };
}

/**
 * PATCH /api/portfolio/[portfolioId]/pibi-requests/[id]
 *
 * Approver-only. Updates a PIBI request row.
 * Body: { dealId: string, measureName?: string, orderedAt?: string, completedAt?: string | null }
 */
export async function PATCH(
  req: NextRequest,
  props: { params: Promise<{ portfolioId: string; id: string }> },
) {
  const { portfolioId, id } = await props.params;

  const session = await getServerSession(AuthOptions);
  if (!session?.user?.email) {
    return NextResponse.json({ error: "Unauthorised" }, { status: 401 });
  }

  let body: unknown;
  try {
    body = await req.json();
  } catch {
    return NextResponse.json({ error: "Invalid JSON" }, { status: 400 });
  }

  const parsed = patchSchema.safeParse(body);
  if (!parsed.success) {
    return NextResponse.json({ error: parsed.error.flatten() }, { status: 400 });
  }

  const auth = await resolveApprover(session.user.email, portfolioId);
  if (!auth.ok) {
    return NextResponse.json({ error: auth.error }, { status: auth.status });
  }

  const { dealId, measureName, orderedAt, completedAt } = parsed.data;

  const result = await updatePibiRequest({
    id: BigInt(id),
    dealId,
    updates: {
      ...(measureName !== undefined && { measureName }),
      ...(orderedAt !== undefined && { orderedAt: new Date(orderedAt) }),
      ...(completedAt !== undefined && { completedAt: completedAt ? new Date(completedAt) : null }),
    },
  });

  if (!result.ok) {
    return NextResponse.json({ ok: false, error: result.error }, { status: 400 });
  }

  return NextResponse.json({
    ok: true,
    hubspotSync: result.hubspotSync,
    hubspotError: result.hubspotError,
  });
}

/**
 * DELETE /api/portfolio/[portfolioId]/pibi-requests/[id]?dealId=...
 *
 * Approver-only. Deletes a PIBI request row and re-syncs HubSpot.
 */
export async function DELETE(
  req: NextRequest,
  props: { params: Promise<{ portfolioId: string; id: string }> },
) {
  const { portfolioId, id } = await props.params;

  const session = await getServerSession(AuthOptions);
  if (!session?.user?.email) {
    return NextResponse.json({ error: "Unauthorised" }, { status: 401 });
  }

  const dealId = req.nextUrl.searchParams.get("dealId");
  if (!dealId) {
    return NextResponse.json({ error: "dealId query param is required" }, { status: 400 });
  }

  const auth = await resolveApprover(session.user.email, portfolioId);
  if (!auth.ok) {
    return NextResponse.json({ error: auth.error }, { status: auth.status });
  }

  const result = await deletePibiRequest({ id: BigInt(id), dealId });

  if (!result.ok) {
    return NextResponse.json({ ok: false, error: result.error }, { status: 400 });
  }

  return NextResponse.json({
    ok: true,
    hubspotSync: result.hubspotSync,
    hubspotError: result.hubspotError,
  });
}
