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

// Assign a chosen Ordnance Survey address (from the postcode search) to an
// existing property: writes the canonical uprn/address/postcode and keeps what
// the user typed as the user-inputted fallback. Keyed by (property, portfolio)
// so a caller can only touch a property in a portfolio they addressed. The
// candidate is guaranteed residential + UPRN-bearing by the picker UI.
const patchSchema = z.object({
  uprn: z.string().regex(/^\d+$/, "UPRN must be numeric"),
  address: z.string().trim().min(1, "Address is required"),
  postcode: z.string().trim().min(1, "Postcode is required"),
  // What the user typed in the edit fields — kept as the raw fallback, mirroring
  // how the bulk finaliser stores user_inputted_* alongside the matched values.
  userInputtedAddress: z.string().trim().optional(),
  userInputtedPostcode: z.string().trim().optional(),
});

function isUniqueViolation(err: unknown): boolean {
  const code = (err as { code?: string })?.code;
  const message = (err as { message?: string })?.message ?? "";
  return code === "23505" || message.includes("uq_property_portfolio_uprn");
}

export async function PATCH(
  request: NextRequest,
  props: { params: Promise<{ portfolioId: string; propertyId: string }> },
) {
  const session = await getServerSession(AuthOptions);
  if (!session?.user?.email) {
    return NextResponse.json({ error: "Unauthorised" }, { status: 401 });
  }

  const { portfolioId, propertyId } = await props.params;
  if (!/^\d+$/.test(portfolioId) || !/^\d+$/.test(propertyId)) {
    return NextResponse.json({ error: "Invalid id" }, { status: 400 });
  }

  const parsed = patchSchema.safeParse(await request.json().catch(() => null));
  if (!parsed.success) {
    return NextResponse.json(
      { error: parsed.error.issues[0]?.message ?? "Invalid request" },
      { status: 400 },
    );
  }
  const { uprn, address, postcode, userInputtedAddress, userInputtedPostcode } =
    parsed.data;

  try {
    const updated = await db
      .update(property)
      .set({
        uprn: BigInt(uprn),
        address,
        postcode,
        ...(userInputtedAddress !== undefined ? { userInputtedAddress } : {}),
        ...(userInputtedPostcode !== undefined ? { userInputtedPostcode } : {}),
        updatedAt: new Date(),
      })
      .where(
        and(
          eq(property.id, BigInt(propertyId)),
          eq(property.portfolioId, BigInt(portfolioId)),
        ),
      )
      .returning({ id: property.id });

    if (updated.length === 0) {
      return NextResponse.json({ error: "Property not found" }, { status: 404 });
    }
    return NextResponse.json({ ok: true });
  } catch (err) {
    if (isUniqueViolation(err)) {
      return NextResponse.json(
        {
          error:
            "That UPRN is already assigned to another property in this portfolio.",
        },
        { status: 409 },
      );
    }
    console.error("PATCH /properties/[propertyId] error:", err);
    return NextResponse.json({ error: "Internal server error" }, { status: 500 });
  }
}
