import { jsonError } from "../../common.js";
import sendEmail from "../../email.js";
import { sendPushNotification } from "../../gcloud.js";
import validateInactivityNotice from "./validate.js";

export async function onRequestDelete(context: RequestContext) {
  const kvResult = await context.env.DATA.get(
    `inactivity_${context.params.id}`,
  );

  if (!kvResult) return jsonError("No inactivity notice with that ID", 404);

  if (
    JSON.parse(kvResult).user.id !== context.data.current_user.id &&
    !(context.data.current_user.permissions & (1 << 0))
  )
    return jsonError(
      "You do not have permission to delete this inactivity notice",
      403,
    );

  await context.env.DATA.delete(`inactivity_${context.params.id}`);
  await context.env.D1.prepare("DELETE FROM inactivity_notices WHERE id = ?;")
    .bind(context.params.id)
    .run();

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

export async function onRequestPost(context: RequestContext) {
  const { accepted }: { accepted?: boolean } = context.data.body;

  if (typeof accepted !== "boolean")
    return jsonError("'accepted' must be a boolean", 400);

  const adminDepartments: { [k: string]: number } = {
    DM: 1 << 11,
    ET: 1 << 4,
    FM: 1 << 7,
    WM: 1 << 6,
  };

  const userAdminDepartments = Object.keys(adminDepartments).filter(
    (dept) => context.data.current_user.permissions & adminDepartments[dept],
  );

  if (!userAdminDepartments.length)
    return jsonError("You are not a manager of any departments", 403);

  const requestedNotice: { [k: string]: any } | null =
    await context.env.DATA.get(`inactivity_${context.params.id as string}`, {
      type: "json",
    });

  if (!requestedNotice)
    return jsonError("Inactivity notices does not exist", 404);

  const decisions: { [dept: string]: boolean } = {};

  for (const department of userAdminDepartments)
    decisions[department] = accepted;

  requestedNotice.decisions = decisions;

  if (Object.values(decisions).length === requestedNotice.departments.length) {
    requestedNotice.open = false;

    const approved = !Object.values(decisions).find((d) => !d);

    await context.env.D1.prepare(
      "UPDATE inactivity_notices SET open = 0 WHERE id = ?;",
    )
      .bind(context.params.id)
      .run();

    if (requestedNotice.fcm_token) {
      await sendPushNotification(
        context.env,
        `Inactivity Request ${approved ? "Approved" : "Denied"}`,
        accepted
          ? "Your inactivity request was approved."
          : "Your inactivity request was denied, please reach to management if you require more details.",
        requestedNotice.fcm_token,
      );
    } else {
      await sendEmail(
        requestedNotice.user.email,
        context.env.MAILGUN_API_KEY,
        `Inactivity Request ${approved ? "Approved" : "Denied"}`,
        `inactivity_${approved ? "approved" : "denied"}`,
        { username: requestedNotice.user.username },
      );
    }

    delete requestedNotice.fcm_token;
    delete requestedNotice.user.email;
  }

  await context.env.DATA.put(
    `inactivity_${context.params.id as string}`,
    JSON.stringify(requestedNotice),
    { expirationTtl: 63072000 },
  );

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

export async function onRequestPut(context: RequestContext) {
  const kvResult: InactivityNoticeProps | null = await context.env.DATA.get(
    `inactivity_${context.params.id}`,
    { type: "json" },
  );

  if (!kvResult) return jsonError("No inactivity notice with that ID", 404);

  if (kvResult.user.id !== context.data.current_user.id)
    return jsonError(
      "You do not have permission to modify this inactivity notice",
      403,
    );

  const d1entry = await context.env.D1.prepare(
    "SELECT open FROM inactivity_notices WHERE id = ?;",
  )
    .bind(context.params.id)
    .run();

  if (!Boolean(d1entry.results.at(0)?.open))
    return jsonError("Cannot modify a closed inactivity notice", 403);

  const { departments, end, reason, start } = context.data.body;

  const validationFailureResponse = validateInactivityNotice(
    departments,
    end,
    reason,
    start,
    context.data.departments,
  );

  if (validationFailureResponse) return validationFailureResponse;

  kvResult.departments = departments;
  kvResult.end = end;
  kvResult.reason = reason;
  kvResult.start = start;

  await context.env.DATA.put(
    `inactivity_${context.params.id}`,
    JSON.stringify(kvResult),
    {
      expirationTtl: 63072000,
    },
  );

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