import { NextResponse } from "next/server";

import {
  getContratDetails,
  updateContratFeed,
  deleteContratFeed,
  findForbiddenContractField,
} from "../../../../server/contrats.server";
import {
  employeeScopeFromAccess,
  requirePermission,
} from "../../../../lib/authorization";
import { contratUpdateSchema } from "../../../../validators/contrats";

type PrismaErrorWithCode = {
  code?: string;
};

function hasPrismaCode(error: unknown, code: string): error is PrismaErrorWithCode {
  return (
    typeof error === "object" &&
    error !== null &&
    "code" in error &&
    (error as PrismaErrorWithCode).code === code
  );
}

type RouteContext = {
  params: Promise<{
    id: string;
  }>;
};

function parseId(idParam: string) {
  const id = Number(idParam);

  if (!Number.isInteger(id))
    return null;

  return id;
}

export async function GET(_request: Request, { params }: RouteContext) {
  const auth = await requirePermission(_request, "contrats", "read");

  if (!auth.ok) return auth.response;
  const { id: idParam } = await params;
  const id = Number(idParam);

  if (!Number.isInteger(id)) {
    return NextResponse.json(
      { message: "Invalid ID parameter" },
      { status: 400 },
    );
  }

  const data = await getContratDetails(id);

  if (!data.contrat) {
    return NextResponse.json(
      { message: "Contrat not found" },
      { status: 404 },
    );
  }

  if (
    findForbiddenContractField(
      data.contrat,
      employeeScopeFromAccess(auth.access),
    )
  ) {
    return NextResponse.json(
      { message: "Contrat not found" },
      { status: 404 },
    );
  }

  return NextResponse.json({
    message: "Contrat retrieved successfully",
    ...data,
  });
}

export async function PUT(request: Request, { params }: RouteContext) {
  const auth = await requirePermission(request, "contrats", "write");

  if (!auth.ok) return auth.response;
  const { id: idParam } = await params;
  const id = parseId(idParam);

  if (id == null) {
    return NextResponse.json(
      { message: "Invalid ID parameter" },
      { status: 400 },
    );
  }

  let body: unknown;

  try {
    body = await request.json();
  } catch {
    return NextResponse.json(
      { message: "Invalide JSON body" },
      { status: 400 },
    );
  }

  const parsed = contratUpdateSchema.safeParse(body);

  if (!parsed.success) {
    return NextResponse.json(
      { message: "Invalid body parameters", issues: parsed.error.flatten() },
      { status: 400 },
    );
  }

  const existing = await getContratDetails(id);

  if (!existing.contrat) {
    return NextResponse.json(
      { message: "Contrat not found" },
      { status: 404 },
    );
  }

  if (
    findForbiddenContractField(
      existing.contrat,
      employeeScopeFromAccess(auth.access),
    )
  ) {
    return NextResponse.json(
      { message: "Contrat not found" },
      { status: 404 },
    );
  }

  const forbiddenField = findForbiddenContractField(
    { ...existing.contrat, ...parsed.data },
    employeeScopeFromAccess(auth.access),
  );

  if (forbiddenField) {
    return NextResponse.json(
      {
        message: `Valeur non autorisée pour le champ ${forbiddenField}.`,
        forbiddenField,
      },
      { status: 403 },
    );
  }

  const data = await updateContratFeed(id, parsed.data);
  
    if (!data.contrat) {
      return NextResponse.json(
        { message: "Contrat not found" },
        { status: 404 },
      );
    }

  return NextResponse.json({
    message: "Contrat updated successfully",
    ...data, 
  });
}

export async function DELETE(_request: Request, { params }: RouteContext) {
  const auth = await requirePermission(_request, "contrats", "write");

  if (!auth.ok) return auth.response;
  const { id: idParam } = await params;
  const id = parseId(idParam);

  if (id == null) {
    return NextResponse.json(
      { message: "Invalid ID parameter" },
      { status: 400 },
    );
  }


  const existing = await getContratDetails(id);

  if (
    !existing.contrat ||
    findForbiddenContractField(
      existing.contrat,
      employeeScopeFromAccess(auth.access),
    )
  ) {
    return NextResponse.json(
      { message: "Contrat not found" },
      { status: 404 },
    );
  }

  let data;

  try {
    data = await deleteContratFeed(id);
  } catch (error: unknown) {
    if (hasPrismaCode(error, "P2003")) {
      return NextResponse.json(
        { message: "Impossible to delete contract: dependent records exist" },
        { status: 409 },
      );
    }

    return NextResponse.json(
      { message: "Internal Server Error" },
      { status: 500 },
    );
  }

  if (!data.contrat) {
    return NextResponse.json(
      { message: "Contrat not found" },
      { status: 404 },
    );
  }

  return NextResponse.json({
    message: "Contrat deleted successfully",
    ...data,
  });
}
