import { NextResponse } from "next/server";
import { and, eq, isNull } from "drizzle-orm";
import { revalidatePath } from "next/cache";
import { db } from "@/db";
import { menuItemSbisLinks, menuItems, sbisCatalogItems } from "@/db/schema";
import { adminAuthorized } from "@/lib/admin-auth";
import { recordAudit } from "@/lib/audit";

function fail(error: string, status = 400) { return NextResponse.json({ error }, { status }); }

export async function POST(request: Request) {
  if (!(await adminAuthorized(request, true))) return fail("Unauthorized", 401);
  if (!db) return fail("Database is not configured", 503);
  const body = await request.json() as { menuItemId?: unknown; sbisId?: unknown };
  const menuItemId = Number(body.menuItemId);
  // Bot catalog ids are numeric (contract §3); accept both shapes.
  const sbisId = typeof body.sbisId === "number" ? String(Math.trunc(body.sbisId)) : typeof body.sbisId === "string" ? body.sbisId.trim() : "";
  if (!Number.isInteger(menuItemId) || !sbisId) return fail("Укажите карточку сайта и sbis_id");
  try {
    const [[item], [catalog], [itemLink], [sbisLink]] = await Promise.all([
      db.select({ id: menuItems.id }).from(menuItems).where(eq(menuItems.id, menuItemId)).limit(1),
      db.select({ sbisId: sbisCatalogItems.sbisId }).from(sbisCatalogItems).where(eq(sbisCatalogItems.sbisId, sbisId)).limit(1),
      db.select({ id: menuItemSbisLinks.id }).from(menuItemSbisLinks).where(and(eq(menuItemSbisLinks.menuItemId, menuItemId), isNull(menuItemSbisLinks.unlinkedAt))).limit(1),
      db.select({ id: menuItemSbisLinks.id }).from(menuItemSbisLinks).where(and(eq(menuItemSbisLinks.sbisId, sbisId), isNull(menuItemSbisLinks.unlinkedAt))).limit(1)
    ]);
    if (!item) return fail("Карточка сайта не найдена", 404);
    if (!catalog) return fail("Позиция отсутствует в актуальном каталоге СБИС", 409);
    if (itemLink) return fail("Карточка уже привязана; сначала отвяжите её", 409);
    if (sbisLink) return fail("Эта позиция СБИС уже привязана к другой карточке", 409);
    await db.insert(menuItemSbisLinks).values({ menuItemId, sbisId, linkedBy: "admin" });
    await recordAudit("sbis_link", { entityType: "menu_item", entityId: menuItemId, details: { sbis_id: sbisId } });
    revalidatePath("/menu");
    return NextResponse.json({ ok: true });
  } catch (error) { return fail(error instanceof Error ? error.message : "Не удалось привязать позицию", 503); }
}

export async function DELETE(request: Request) {
  if (!(await adminAuthorized(request, true))) return fail("Unauthorized", 401);
  if (!db) return fail("Database is not configured", 503);
  const body = await request.json() as { menuItemId?: unknown; reason?: unknown };
  const menuItemId = Number(body.menuItemId);
  if (!Number.isInteger(menuItemId)) return fail("Укажите карточку сайта");
  const reason = typeof body.reason === "string" ? body.reason.slice(0, 200) : "admin";
  await db.update(menuItemSbisLinks).set({ unlinkedAt: new Date(), unlinkReason: reason }).where(and(eq(menuItemSbisLinks.menuItemId, menuItemId), isNull(menuItemSbisLinks.unlinkedAt)));
  await recordAudit("sbis_unlink", { entityType: "menu_item", entityId: menuItemId, details: { reason } });
  revalidatePath("/menu");
  return NextResponse.json({ ok: true });
}

export async function PUT(request: Request) {
  if (!(await adminAuthorized(request, true))) return fail("Unauthorized", 401);
  if (!db) return fail("Database is not configured", 503);
  const body = await request.json() as { menuItemId?: unknown; sbisId?: unknown };
  const menuItemId = Number(body.menuItemId);
  const sbisId = body.sbisId === null ? null : typeof body.sbisId === "number" ? String(Math.trunc(body.sbisId)) : typeof body.sbisId === "string" ? body.sbisId.trim() || null : null;
  if (!Number.isInteger(menuItemId)) return fail("Укажите карточку сайта");
  try {
    const [[item], [catalog], [current], [target]] = await Promise.all([
      db.select({ id: menuItems.id }).from(menuItems).where(eq(menuItems.id, menuItemId)).limit(1),
      sbisId ? db.select({ sbisId: sbisCatalogItems.sbisId }).from(sbisCatalogItems).where(eq(sbisCatalogItems.sbisId, sbisId)).limit(1) : Promise.resolve([]),
      db.select({ id: menuItemSbisLinks.id, sbisId: menuItemSbisLinks.sbisId }).from(menuItemSbisLinks).where(and(eq(menuItemSbisLinks.menuItemId, menuItemId), isNull(menuItemSbisLinks.unlinkedAt))).limit(1),
      sbisId ? db.select({ id: menuItemSbisLinks.id, menuItemId: menuItemSbisLinks.menuItemId }).from(menuItemSbisLinks).where(and(eq(menuItemSbisLinks.sbisId, sbisId), isNull(menuItemSbisLinks.unlinkedAt))).limit(1) : Promise.resolve([])
    ]);
    if (!item) return fail("Карточка сайта не найдена", 404);
    if (sbisId && !catalog) return fail("Позиция отсутствует в каталоге СБИС", 409);
    if (target && target.menuItemId !== menuItemId) return fail("Эта позиция СБИС уже привязана к другой карточке", 409);
    if ((current?.sbisId || null) === sbisId) return NextResponse.json({ ok: true, unchanged: true });
    await db.transaction(async (tx) => {
      if (current) await tx.update(menuItemSbisLinks).set({ unlinkedAt: new Date(), unlinkReason: sbisId ? "relinked" : "admin" }).where(eq(menuItemSbisLinks.id, current.id));
      if (sbisId) await tx.insert(menuItemSbisLinks).values({ menuItemId, sbisId, linkedBy: "admin-relink" });
    });
    await recordAudit(sbisId ? "sbis_relink" : "sbis_unlink", { entityType: "menu_item", entityId: menuItemId, details: { from_sbis_id: current?.sbisId || null, to_sbis_id: sbisId } });
    revalidatePath("/menu");
    return NextResponse.json({ ok: true });
  } catch (error) {
    const message = error instanceof Error ? error.message : "Не удалось изменить привязку";
    return fail(message.includes("active_") || message.includes("unique") ? "Позиция СБИС уже используется другой карточкой" : message, message.includes("active_") || message.includes("unique") ? 409 : 503);
  }
}
