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 { instructMeasures } from "@/app/lib/instructMeasure";
import { MEASURE_NAMES } from "@/app/lib/measureDocumentRequirements";

const postSchema = z.object({
  dealId: z.string().min(1, "dealId is required"),
  measureNames: z
    .array(z.string().min(1))
    .min(1, "measureNames must not be empty"),
});

/**
 * POST /api/portfolio/[portfolioId]/instructed-measures
 *
 * Approver-only endpoint that instructs a measure on a deal. Validates the
 * measure name against the canonical `MEASURE_NAMES` catalogue, persists
 * to `user_defined_deal_measures`, auto-creates an approval row, and
 * pushes back to HubSpot. See `instructMeasure` for the full contract.
 *
 * Body:
 *   { dealId: string, measureNames: string[] }
 *
 * Response:
 *   200 { ok: true, hubspotSync: "ok" | "failed", hubspotError? }
 *   400 { ok: false, error }
 *   401 / 403 / 404 on auth/role/user errors.
 */
export async function POST(
  req: NextRequest,
  props: { params: Promise<{ portfolioId: string }> },
) {
  const { portfolioId } = 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 = postSchema.safeParse(body);
  if (!parsed.success) {
    return NextResponse.json(
      { error: parsed.error.flatten() },
      { status: 400 },
    );
  }

  const { dealId, measureNames } = parsed.data;

  // Validate all names against the canonical catalogue up-front.
  for (const name of measureNames) {
    if (!(MEASURE_NAMES as ReadonlyArray<string>).includes(name)) {
      return NextResponse.json(
        { error: `Unknown measure: ${name}` },
        { status: 400 },
      );
    }
  }

  const userRow = await db
    .select({ id: user.id })
    .from(user)
    .where(eq(user.email, session.user.email))
    .limit(1);

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

  // Caller must have any role on the portfolio (so we don't expose the
  // endpoint to strangers) AND the approver capability.
  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 NextResponse.json(
      { error: "No portfolio access" },
      { status: 403 },
    );
  }

  const capabilityRows = await db
    .select({ capability: portfolioCapabilities.capability })
    .from(portfolioCapabilities)
    .where(
      and(
        eq(portfolioCapabilities.portfolioId, BigInt(portfolioId)),
        eq(portfolioCapabilities.userId, userRow[0].id),
      ),
    );
  const capabilities = capabilityRows.map((r) => r.capability);
  if (!capabilities.includes("approver")) {
    return NextResponse.json(
      { error: "Approver capability required" },
      { status: 403 },
    );
  }

  try {
    const result = await instructMeasures({
      dealId,
      measureNames,
      userId: userRow[0].id,
    });

    if (!result.ok) {
      return NextResponse.json({ ok: false, error: result.error }, {
        status: 400,
      });
    }
    return NextResponse.json({
      ok: true,
      hubspotSync: result.hubspotSync,
      hubspotError: result.hubspotError,
    });
  } catch (err) {
    console.error("[instructed-measures POST]", err);
    return NextResponse.json(
      { error: "Internal server error" },
      { status: 500 },
    );
  }
}
