import { Router, type Response } from "express";
import { z } from "zod";
import { requireBoardAccess } from "../lib/authz";
import { positionBetween } from "../lib/position";
import { prisma } from "../lib/prisma";
import { emitToBoard } from "../lib/socketBus";
import { HttpError } from "../middleware/errorHandler";
import { requireAuth } from "../middleware/requireAuth";

export const checklistsRouter = Router();
checklistsRouter.use(requireAuth);

const cardDetailInclude = {
  labels: { include: { label: true } },
  members: { include: { user: true } },
  checklists: { include: { items: { include: { assignees: { include: { user: true } } } } } },
  comments: { include: { author: true, reactions: true, mentions: true, seenBy: true }, orderBy: { createdAt: "asc" as const } },
  attachments: { include: { uploader: true } },
  customFieldValues: { include: { customField: true } },
  status: true,
};

async function loadChecklistWithCard(checklistId: string) {
  const checklist = await prisma.checklist.findUnique({
    where: { id: checklistId },
    include: { card: true },
  });
  if (!checklist) throw new HttpError(404, "Checklist not found");
  return checklist;
}

async function respondWithCard(cardId: string, boardId: string, res: Response) {
  const updated = await prisma.card.findUnique({ where: { id: cardId }, include: cardDetailInclude });
  emitToBoard(boardId, "card:updated", { card: updated });
  res.json({ card: updated });
}

const updateChecklistSchema = z.object({
  title: z.string().min(1).max(100).optional(),
  beforePosition: z.number().optional(),
  afterPosition: z.number().optional(),
});

checklistsRouter.patch("/:id", async (req, res, next) => {
  try {
    const checklist = await loadChecklistWithCard(req.params.id);
    await requireBoardAccess(req.userId!, checklist.card.boardId, "MEMBER");

    const data = updateChecklistSchema.parse(req.body);
    const { beforePosition, afterPosition, ...rest } = data;

    await prisma.checklist.update({
      where: { id: req.params.id },
      data: {
        ...rest,
        ...(beforePosition !== undefined || afterPosition !== undefined
          ? { position: positionBetween(beforePosition, afterPosition) }
          : {}),
      },
    });

    await respondWithCard(checklist.cardId, checklist.card.boardId, res);
  } catch (err) {
    next(err);
  }
});

checklistsRouter.delete("/:id", async (req, res, next) => {
  try {
    const checklist = await loadChecklistWithCard(req.params.id);
    await requireBoardAccess(req.userId!, checklist.card.boardId, "MEMBER");

    await prisma.checklist.delete({ where: { id: req.params.id } });
    await respondWithCard(checklist.cardId, checklist.card.boardId, res);
  } catch (err) {
    next(err);
  }
});

const createItemSchema = z.object({ text: z.string().min(1).max(500) });

checklistsRouter.post("/:id/items", async (req, res, next) => {
  try {
    const checklist = await loadChecklistWithCard(req.params.id);
    await requireBoardAccess(req.userId!, checklist.card.boardId, "MEMBER");

    const data = createItemSchema.parse(req.body);
    const last = await prisma.checklistItem.findFirst({
      where: { checklistId: req.params.id },
      orderBy: { position: "desc" },
    });

    await prisma.checklistItem.create({
      data: {
        checklistId: req.params.id,
        text: data.text,
        position: (last?.position ?? 0) + 1000,
      },
    });

    await respondWithCard(checklist.cardId, checklist.card.boardId, res);
  } catch (err) {
    next(err);
  }
});
