import { db } from "@/app/db/db";
import { NextRequest, NextResponse } from "next/server";
import { uploadedFiles } from "@/app/db/schema/uploaded_files";
import { user } from "@/app/db/schema/users";
import { eq, inArray } from "drizzle-orm";
import { z } from "zod";
import { getServerSession } from "next-auth";
import { AuthOptions } from "@/app/api/auth/[...nextauth]/authOptions";
import { syncContractorDocUploadToHubSpot } from "@/app/lib/hubspot/dealSync";
import { getRequiredDocs } from "@/app/lib/measureDocumentRequirements";

function computeMeasureProgress(
  proposedMeasures: string[],
  dealDocs: { fileType: string | null; measureName: string | null }[],
) {
  const installDocs = dealDocs.filter((d) => d.fileType !== null && d.measureName !== null);
  return proposedMeasures.map((measureName) => {
    const required = getRequiredDocs(measureName);
    const docsForMeasure = installDocs.filter((d) => d.measureName === measureName);
    const uploadedTypeSet = new Set(docsForMeasure.map((d) => d.fileType));
    const uploadedCount = required.filter((r) => uploadedTypeSet.has(r)).length;
    return {
      measureName,
      uploadedCount,
      requiredCount: required.length,
      isComplete: uploadedCount === required.length,
    };
  });
}

// POST — record a contractor install document in uploaded_files (fileType optional — can be classified later)
export async function POST(req: NextRequest) {
  const session = await getServerSession(AuthOptions);
  if (!session?.user?.email) {
    return NextResponse.json({ error: "Unauthorised" }, { status: 401 });
  }

  const bodySchema = z.object({
    s3FileKey: z.string(),
    s3FileBucket: z.string(),
    fileType: z.string().optional(), // optional — null means unclassified
    measureName: z.string().optional(),
    uprn: z.string().optional(),
    hubspotDealId: z.string().optional(),
    landlordPropertyId: z.string().optional(),
  });

  let body: z.infer<typeof bodySchema>;
  try {
    body = bodySchema.parse(await req.json());
  } catch {
    return NextResponse.json({ error: "Invalid body" }, { status: 400 });
  }

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

    const uploadedBy = userRow[0]?.id ?? null;

    const [inserted] = await db
      .insert(uploadedFiles)
      .values({
        s3FileBucket: body.s3FileBucket,
        s3FileKey: body.s3FileKey,
        s3UploadTimestamp: new Date(),
        fileType: (body.fileType as any) ?? null,
        source: "contractor",
        measureName: body.measureName ?? null,
        uploadedBy: uploadedBy ?? undefined,
        uprn: body.uprn ? BigInt(body.uprn) : undefined,
        hubsotDealId: body.hubspotDealId ?? null,
        landlordPropertyId: body.landlordPropertyId ?? null,
      })
      .returning({ id: uploadedFiles.id });

    if (body.hubspotDealId) {
      void syncContractorDocUploadToHubSpot({
        hubspotDealId: body.hubspotDealId,
      });
    }

    return NextResponse.json({ id: inserted.id.toString() }, { status: 201 });
  } catch (err) {
    console.error("POST /upload/contractor-install error:", err);
    return NextResponse.json({ error: "Failed to record upload" }, { status: 500 });
  }
}

// PATCH — update fileType and measureName for previously unclassified uploads
export async function PATCH(req: NextRequest) {
  const session = await getServerSession(AuthOptions);
  if (!session?.user?.email) {
    return NextResponse.json({ error: "Unauthorised" }, { status: 401 });
  }

  const bodySchema = z.object({
    updates: z.array(
      z.object({
        id: z.string(),
        fileType: z.string(),
        measureName: z.string().optional(),
      }),
    ),
    hubspotDealId: z.string().optional(),
    proposedMeasures: z.array(z.string()).optional(),
  });

  let body: z.infer<typeof bodySchema>;
  try {
    body = bodySchema.parse(await req.json());
  } catch {
    return NextResponse.json({ error: "Invalid body" }, { status: 400 });
  }

  if (body.updates.length === 0) {
    return NextResponse.json({ success: true });
  }

  try {
    // Update each record individually (small batches — no bulk update without raw SQL)
    for (const update of body.updates) {
      await db
        .update(uploadedFiles)
        .set({
          fileType: update.fileType as any,
          measureName: update.measureName ?? null,
        })
        .where(eq(uploadedFiles.id, BigInt(update.id)));
    }

    // Sync per-measure progress to HubSpot after classification
    if (body.hubspotDealId && body.proposedMeasures && body.proposedMeasures.length > 0) {
      const dealDocs = await db
        .select({ fileType: uploadedFiles.fileType, measureName: uploadedFiles.measureName })
        .from(uploadedFiles)
        .where(eq(uploadedFiles.hubsotDealId, body.hubspotDealId));

      const measureProgress = computeMeasureProgress(body.proposedMeasures, dealDocs);
      void syncContractorDocUploadToHubSpot({ hubspotDealId: body.hubspotDealId, measureProgress });
    }

    return NextResponse.json({ success: true });
  } catch (err) {
    console.error("PATCH /upload/contractor-install error:", err);
    return NextResponse.json({ error: "Failed to update classifications" }, { status: 500 });
  }
}
