import { NextResponse } from "next/server";
import { DepartmentKey, MarketingTaskStatus } from "@prisma/client";
import { getServerSession } from "next-auth";
import { authOptions } from "@/lib/auth";
import { prisma } from "@/lib/prisma";
import { canAccessProjects, canManageProjects, mapProjectTask } from "@/lib/projects/persistence";

type UpdateTaskBody = {
  status?: string;
  evidenceLinks?: string[];
  dueDate?: string;
  dueDateRequest?: string;
  blockerNote?: string;
};

const ALLOWED_STATUS = new Set<MarketingTaskStatus>([
  MarketingTaskStatus.todo,
  MarketingTaskStatus.in_progress,
  MarketingTaskStatus.blocked,
  MarketingTaskStatus.done,
]);

function parseDate(value: string | undefined): Date | null {
  if (!value) {
    return null;
  }

  const parsed = new Date(value);
  if (Number.isNaN(parsed.getTime())) {
    return null;
  }

  return parsed;
}

export async function PATCH(request: Request, context: { params: { id: string } }) {
  const session = await getServerSession(authOptions);
  if (!session?.user) {
    return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
  }

  if (!canAccessProjects(session.user.role, session.user.department)) {
    return NextResponse.json({ error: "Forbidden" }, { status: 403 });
  }

  const taskId = context.params.id;
  const task = await prisma.marketingTask.findFirst({
    where: {
      id: taskId,
      initiative: { department: DepartmentKey.proyectos },
    },
    include: {
      evidenceLinks: {
        orderBy: { createdAt: "asc" },
      },
    },
  });

  if (!task) {
    return NextResponse.json({ error: "Task not found." }, { status: 404 });
  }

  const canManage = canManageProjects(session.user.role, session.user.department);
  const isOwnTaskEmployee =
    session.user.role === "employee" &&
    session.user.department === DepartmentKey.proyectos &&
    task.assigneeId === session.user.id;

  if (!canManage && !isOwnTaskEmployee) {
    return NextResponse.json({ error: "You can only edit your own assigned tasks." }, { status: 403 });
  }

  const body = (await request.json()) as UpdateTaskBody;
  const status = body.status;
  const evidenceLinks = body.evidenceLinks ?? [];
  const dueDate = parseDate(body.dueDate);
  const dueDateRequest = body.dueDateRequest?.trim() ?? "";
  const blockerNote = body.blockerNote?.trim() ?? "";

  const hasUpdates =
    Boolean(status) ||
    body.evidenceLinks !== undefined ||
    body.dueDate !== undefined ||
    dueDateRequest.length > 0 ||
    blockerNote.length > 0;

  if (!hasUpdates) {
    return NextResponse.json({ error: "Nothing to update." }, { status: 400 });
  }

  if (status && !ALLOWED_STATUS.has(status as MarketingTaskStatus)) {
    return NextResponse.json({ error: "Invalid task status." }, { status: 400 });
  }

  if (body.dueDate !== undefined) {
    if (!canManage) {
      return NextResponse.json({ error: "Only owners and leaders can change due dates directly." }, { status: 403 });
    }
    if (!dueDate) {
      return NextResponse.json({ error: "Invalid dueDate." }, { status: 400 });
    }
  }

  const cleanEvidenceLinks = Array.from(
    new Set(
      evidenceLinks
        .map((value) => value.trim())
        .filter((value) => value.length > 0)
    )
  );

  const noteChunks: string[] = [];
  if (dueDateRequest.length > 0) {
    noteChunks.push(`[REQ_FECHA] ${dueDateRequest}`);
  }
  if (blockerNote.length > 0) {
    noteChunks.push(`[BLOQUEO] ${blockerNote}`);
  }

  const updated = await prisma.$transaction(async (tx) => {
    await tx.marketingTask.update({
      where: { id: taskId },
      data: {
        status: status as MarketingTaskStatus | undefined,
        dueDate: dueDate ?? undefined,
        description:
          noteChunks.length > 0
            ? `${task.description}\n[${new Date().toISOString()}] ${noteChunks.join(" | ")}`.trim()
            : undefined,
      },
    });

    if (body.evidenceLinks !== undefined) {
      await tx.marketingTaskEvidence.deleteMany({
        where: { taskId },
      });

      if (cleanEvidenceLinks.length > 0) {
        await tx.marketingTaskEvidence.createMany({
          data: cleanEvidenceLinks.map((url) => ({
            taskId,
            url,
            createdById: session.user.id,
          })),
        });
      }
    }

    return tx.marketingTask.findUniqueOrThrow({
      where: { id: taskId },
      include: {
        evidenceLinks: {
          orderBy: { createdAt: "asc" },
        },
      },
    });
  });

  return NextResponse.json({
    ok: true,
    task: mapProjectTask(updated),
  });
}
