import { jsonError } from "../../../common.js";

export async function onRequestDelete(context: RequestContext) {
  const eventId = context.params.id as string;
  const eventData = await context.data.prisma.event.findUnique({
    select: {
      created_by: true,
      day: true,
      month: true,
      performed_at: true,
      year: true,
    },
    where: {
      id: eventId,
    },
  });

  if (!eventData) return jsonError("No event exists with that ID", 404);

  const { current_user: currentUser } = context.data;
  const isETM = [1 << 4, 1 << 12].find((int) => currentUser.permissions & int);

  if (eventData.created_by !== currentUser.id && !isETM)
    return jsonError("You are not authorized to delete that event", 403);

  const now = new Date();
  now.setUTCHours(0, 0, 0, 0);

  const eventDate = new Date(
    eventData.year,
    eventData.month - 1,
    eventData.day,
  );

  if (!isETM && now.getTime() >= eventDate.getTime())
    return jsonError(
      "Event cannot be deleted on or after the scheduled date",
      403,
    );

  if (typeof eventData.performed_at === "number")
    return jsonError(
      "Event cannot be deleted because it has already been marked as completed or forgotten",
      400,
    );

  await context.data.prisma.event.delete({
    where: {
      id: eventId,
    },
  });

  return new Response(null, {
    status: 204,
  });
}

export async function onRequestPatch(context: RequestContext) {
  const eventId = context.params.id as string;
  const { body } = context.data;
  const eventData = await context.data.prisma.event.findUnique({
    select: {
      created_by: true,
      day: true,
      month: true,
      type: true,
      year: true,
    },
    where: {
      id: eventId,
    },
  });

  if (!eventData) return jsonError("No event exists with that ID", 404);

  const { current_user: currentUser } = context.data;

  if (
    eventData.created_by !== currentUser.id &&
    ![1 << 4, 1 << 12].find((int) => currentUser.permissions & int)
  )
    return jsonError("You are not authorized to modify this event", 403);

  const date = new Date();
  const currentDay = date.getUTCDate();

  // Set to first of month to avoid any issues with month incrementation, then add month and subtract one day to get the last day of this month
  date.setUTCDate(1);
  date.setUTCMonth(date.getUTCMonth() + 1);
  date.setUTCDate(0);

  if (
    typeof body.day !== "number" ||
    body.day > date.getUTCDate() ||
    body.day < 1 ||
    // Check for nonintegers
    Math.floor(body.day) !== body.day ||
    currentDay >= body.day
  )
    return jsonError("Invalid day", 400);

  if (
    date.getUTCFullYear() !== eventData.year ||
    date.getUTCMonth() + 1 !== eventData.month
  )
    return jsonError(
      "Only events in the current month period can be rescheduled",
      400,
    );

  if (eventData.type === "rotw") {
    const weekRanges: { [k: number]: number } = {
      0: 7,
      1: 14,
      2: 21,
      3: 28,
      4: 35,
    };
    const weekRange = Math.floor(body.day / 7);
    const matchingROTW = await context.data.prisma.event.findMany({
      select: {
        id: true,
      },
      where: {
        OR: [{ approved: true }, { pending: true }],
        day: {
          gte: weekRanges[weekRange] - 7,
          lte: weekRanges[weekRange],
        },
        month: eventData.month,
        year: eventData.year,
      },
    });

    if (matchingROTW)
      return jsonError("There is already an ROTW scheduled for that week", 400);
  } else {
    const matchingEvent = await context.data.prisma.event.findMany({
      select: {
        id: true,
      },
      where: {
        OR: [{ approved: true }, { pending: true }],
        AND: [
          { day: body.day },
          { month: eventData.month },
          { type: eventData.type },
          { year: eventData.year },
        ],
      },
    });

    if (matchingEvent)
      return jsonError(
        "There is already an event of that type scheduled for that day",
        400,
      );
  }

  await context.data.prisma.event.update({
    data: {
      day: body.day,
    },
    where: {
      id: eventId,
    },
  });

  await fetch(context.env.EVENTS_WEBHOOK, {
    body: JSON.stringify({
      embeds: [
        {
          title: "Event Rescheduled",
          color: 3756250,
          description: `${context.data.current_user.username} rescheduled their event for ${eventData.year}-${eventData.month.toString().padStart(2, "0")}-${eventData.day.toString().padStart(2, "0")} to ${eventData.year}-${eventData.month.toString().padStart(2, "0")}-${body.day}`,
        },
      ],
    }),
    headers: {
      "content-type": "application/json",
    },
    method: "POST",
  });

  return new Response(null, {
    status: 204,
  });
}

export async function onRequestPost(context: RequestContext) {
  const eventId = context.params.id as string;
  const eventData = await context.data.prisma.event.findUnique({
    select: {
      approved: true,
      performed_at: true,
    },
    where: {
      id: eventId,
    },
  });

  if (!eventData) return jsonError("No event exists with that ID", 404);

  if (!eventData.approved)
    return jsonError("Cannot perform unapproved event", 403);

  await context.data.prisma.event.update({
    data: {
      performed_at: new Date(),
    },
    where: {
      id: eventId,
    },
  });

  return new Response(null, {
    status: 204,
  });
}
