import { defineEventHandler, readBody, setResponseStatus } from "h3";
import { type Client } from "@prisma/client";

import getRequestingUser from "../utils/getRequestingUser";
import { database } from "../utils/database";
import { prismaToWeb } from "~/server/utils/prismaToWeb";
import Snowflake from "~/utils/snowflake";

import { createError } from "#imports";

const clientKeys: Array<string> = [
  "name",
  "address",
  "phone",
  "email",
];

export function checkIsClient<Patch extends boolean = boolean>(
  value: any,
  patch: Patch,
): value is Patch extends true ? Partial<Omit<Client, "id">> : Omit<Client, "id"> {
  const errors = new Map<string, string>();

  if (typeof value !== "object") {
    throw createError({
      statusCode: 400,
      message: "Invalid body",
    });
  }

  if (!(typeof value.name === "string" || value.name === null || (patch && value.name === undefined))) errors.set("name", "is not string or null");
  if (!(typeof value.address === "string" || value.address === null || (patch && value.address === undefined))) errors.set("address", "is not string or null");
  if (!(typeof value.phone === "string" || value.phone === null || (patch && value.phone === undefined))) errors.set("phone", "is not string or null");
  if (!(typeof value.email === "string" || value.email === null || (patch && value.email === undefined))) errors.set("email", "is not string or null");

  for (const i in value as Partial<Omit<Client, "id">>)
    if (!clientKeys.includes(i)) errors.set(i, `excessive property`);

  if (errors.size !== 0) {
    let message = "Invalid Parameters: ";
    for (const i in errors)
      message += i + ", ";
    message = message.slice(0, -2);
    throw createError({
      statusCode: 400,
      message,
      data: {
        errors: Object.fromEntries(errors),
      },
    });
  }

  return true;
}

export default defineEventHandler(async (e) => {
  const body = await readBody(e);
  const id = new Snowflake().state;
  const user = await getRequestingUser(e);

  if (!checkIsClient(body, false)) throw createError({ message: "Invalid body", statusCode: 400 });

  const rvalue = await database.client.create({
    data: {
      ...body,
      id,
    },
  });

  setResponseStatus(e, 201);
  return prismaToWeb(rvalue);
});