import { Prisma } from "@prisma/client";
import { NextResponse } from "next/server";
import { requireAdminApiUser } from "@/lib/auth/admin";
import { prisma } from "@/lib/prisma";
import { canTransitionProposalStatus, parseProposalStatus } from "@/lib/proposals/status";
import { removeStoredProposalDocument } from "@/lib/proposals/storage";

function isSchemaNotReadyError(error: unknown) {
  return error instanceof Prisma.PrismaClientKnownRequestError && (error.code === "P2021" || error.code === "P2022");
}

function parseString(value: unknown) {
  return typeof value === "string" ? value.trim() : "";
}

function toProposalPayload(
  proposal: {
    id: string;
    title: string;
    issuingEntity: string;
    summary: string;
    status: string;
    sourceLicitationId: string | null;
    createdAt: Date;
    updatedAt: Date;
    documents: Array<{
      id: string;
      fileName: string;
      mimeType: string;
      sizeBytes: number;
      createdAt: Date;
      filePath?: string;
    }>;
  } & {
    currentStep?: number;
    completionPercent?: number;
    readyForSubmissionAt?: Date | null;
  },
) {
  return {
    id: proposal.id,
    title: proposal.title,
    issuingEntity: proposal.issuingEntity,
    summary: proposal.summary,
    currentStep: proposal.currentStep ?? 1,
    completionPercent: proposal.completionPercent ?? 0,
    readyForSubmissionAt: proposal.readyForSubmissionAt ? proposal.readyForSubmissionAt.toISOString() : null,
    status: proposal.status,
    sourceLicitationId: proposal.sourceLicitationId,
    createdAt: proposal.createdAt.toISOString(),
    updatedAt: proposal.updatedAt.toISOString(),
    documents: proposal.documents.map((document) => ({
      id: document.id,
      fileName: document.fileName,
      mimeType: document.mimeType,
      sizeBytes: document.sizeBytes,
      createdAt: document.createdAt.toISOString(),
    })),
  };
}

export async function GET(_: Request, context: { params: Promise<{ id: string }> }) {
  const user = await requireAdminApiUser();

  if (!user) {
    return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
  }

  try {
    const { id } = await context.params;

    const proposal = await prisma.proposal.findFirst({
      where: {
        id,
        userId: user.id,
      },
      select: {
        id: true,
        title: true,
        issuingEntity: true,
        summary: true,
        status: true,
        sourceLicitationId: true,
        createdAt: true,
        updatedAt: true,
        documents: {
          orderBy: [{ createdAt: "desc" }],
          select: {
            id: true,
            fileName: true,
            mimeType: true,
            sizeBytes: true,
            createdAt: true,
          },
        },
      },
    });

    if (!proposal) {
      return NextResponse.json({ error: "Propuesta no encontrada." }, { status: 404 });
    }

    return NextResponse.json({
      ok: true,
      proposal: toProposalPayload(proposal),
    });
  } catch (error) {
    if (isSchemaNotReadyError(error)) {
      return NextResponse.json(
        { error: "La base de datos aun no tiene las tablas de Gestion de Licitaciones. Ejecuta prisma migrate para continuar." },
        { status: 503 },
      );
    }

    return NextResponse.json({ error: "No fue posible obtener la propuesta." }, { status: 400 });
  }
}

export async function PATCH(request: Request, context: { params: Promise<{ id: string }> }) {
  const user = await requireAdminApiUser();

  if (!user) {
    return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
  }

  try {
    const { id } = await context.params;
    const body = (await request.json()) as Record<string, unknown>;

    const proposal = await prisma.proposal.findFirst({
      where: {
        id,
        userId: user.id,
      },
      select: {
        id: true,
        title: true,
        issuingEntity: true,
        summary: true,
        status: true,
        sourceLicitationId: true,
        createdAt: true,
        updatedAt: true,
        documents: {
          orderBy: [{ createdAt: "desc" }],
          select: {
            id: true,
            fileName: true,
            mimeType: true,
            sizeBytes: true,
            createdAt: true,
          },
        },
      },
    });

    if (!proposal) {
      return NextResponse.json({ error: "Propuesta no encontrada." }, { status: 404 });
    }

    const title = parseString(body.title);
    const issuingEntity = parseString(body.issuingEntity);
    const summary = parseString(body.summary);
    const nextStatus = parseProposalStatus(body.status);

    if (body.status != null && !nextStatus) {
      return NextResponse.json({ error: "Estatus invalido." }, { status: 400 });
    }

    if (nextStatus && !canTransitionProposalStatus(proposal.status, nextStatus)) {
      return NextResponse.json({ error: "La transicion de estatus no es valida." }, { status: 400 });
    }

    const updated = await prisma.proposal.update({
      where: { id: proposal.id },
      data: {
        ...(title ? { title } : {}),
        ...(issuingEntity ? { issuingEntity } : {}),
        ...(summary || body.summary === "" ? { summary } : {}),
        ...(nextStatus ? { status: nextStatus } : {}),
      },
      select: {
        id: true,
        title: true,
        issuingEntity: true,
        summary: true,
        status: true,
        sourceLicitationId: true,
        createdAt: true,
        updatedAt: true,
        documents: {
          orderBy: [{ createdAt: "desc" }],
          select: {
            id: true,
            fileName: true,
            mimeType: true,
            sizeBytes: true,
            createdAt: true,
          },
        },
      },
    });

    return NextResponse.json({
      ok: true,
      proposal: toProposalPayload(updated),
    });
  } catch (error) {
    if (isSchemaNotReadyError(error)) {
      return NextResponse.json(
        { error: "La base de datos aun no tiene las tablas de Gestion de Licitaciones. Ejecuta prisma migrate para continuar." },
        { status: 503 },
      );
    }

    return NextResponse.json({ error: "No fue posible actualizar la propuesta." }, { status: 400 });
  }
}

export async function DELETE(_: Request, context: { params: Promise<{ id: string }> }) {
  const user = await requireAdminApiUser();

  if (!user) {
    return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
  }

  try {
    const { id } = await context.params;

    const proposal = await prisma.proposal.findFirst({
      where: {
        id,
        userId: user.id,
      },
      select: {
        id: true,
        documents: true,
      },
    });

    if (!proposal) {
      return NextResponse.json({ error: "Propuesta no encontrada." }, { status: 404 });
    }

    for (const document of proposal.documents) {
      await removeStoredProposalDocument(document.filePath);
    }

    await prisma.proposal.delete({ where: { id: proposal.id } });

    return NextResponse.json({ ok: true });
  } catch (error) {
    if (isSchemaNotReadyError(error)) {
      return NextResponse.json(
        { error: "La base de datos aun no tiene las tablas de Gestion de Licitaciones. Ejecuta prisma migrate para continuar." },
        { status: 503 },
      );
    }

    return NextResponse.json({ error: "No fue posible eliminar la propuesta." }, { status: 400 });
  }
}
