"use server";

import { revalidatePath } from "next/cache";
import { db, Database } from "@link-stack/bridge-common";
import { FieldDescription, Entity } from "../lib/service";
import crypto from "crypto";

const generateToken = () => {
  const length = 20;
  const randomBytes = crypto.randomBytes(length);
  const randomString = randomBytes.toString("hex").slice(0, length);

  return randomString;
};

type CreateActionArgs = {
  entity: Entity;
  table: keyof Database;
  fields: FieldDescription[];
  currentState: any;
  formData: FormData;
};

export const createAction = async ({
  entity,
  table,
  fields,
  currentState,
  formData,
}: CreateActionArgs) => {
  const newRecord = fields.reduce(
    (acc: Record<string, any>, field: FieldDescription) => {
      if (field.autogenerated === "token") {
        acc[field.name] = generateToken();
        return acc;
      }

      acc[field.name] = formData.get(field.name)?.toString() ?? null;
      return acc;
    },
    {},
  );

  const record = await db
    .insertInto(table)
    .values(newRecord)
    .returning(["id"])
    .executeTakeFirstOrThrow();

  revalidatePath(`/${entity}`);

  return {
    ...currentState,
    values: { ...newRecord, id: record.id },
    success: true,
  };
};

type UpdateActionArgs = {
  entity: Entity;
  table: keyof Database;
  fields: FieldDescription[];
  currentState: any;
  formData: FormData;
};

export const updateAction = async ({
  entity,
  table,
  fields,
  currentState,
  formData,
}: UpdateActionArgs) => {
  const id = currentState.values.id;
  const updatedRecord = fields.reduce(
    (acc: Record<string, any>, field: FieldDescription) => {
      acc[field.name] = formData.get(field.name)?.toString() ?? null;
      return acc;
    },
    {},
  );

  await db
    .updateTable(table)
    .set(updatedRecord)
    .where("id", "=", id)
    .executeTakeFirst();

  revalidatePath(`/${entity}/${id}`);

  return {
    ...currentState,
    values: updatedRecord,
    success: true,
  };
};

type DeleteActionArgs = {
  entity: Entity;
  table: keyof Database;
  id: string;
};

export const deleteAction = async ({ entity, table, id }: DeleteActionArgs) => {
  await db.deleteFrom(table).where("id", "=", id).execute();

  revalidatePath(`/${entity}`);

  return true;
};

export const selectAllAction = async (table: keyof Database) => {
  return db.selectFrom(table).selectAll().execute();
};

type SelectOneArgs = {
  table: keyof Database;
  id: string;
};

export const selectOneAction = async ({ table, id }: SelectOneArgs) => {
  return db
    .selectFrom(table)
    .selectAll()
    .where("id", "=", id)
    .executeTakeFirst();
};
