import { date, int, mysqlTable, varchar } from 'drizzle-orm/mysql-core';
import type { MySql2Database } from 'drizzle-orm/mysql2';
import { eq, like, or } from 'drizzle-orm';
import { mysqlEnum } from 'drizzle-orm/mysql-core/columns/enum';

type Database = MySql2Database<{ user: typeof user }>;

export const user = mysqlTable('user', {
  id: int('id').primaryKey().autoincrement(),
  firstname: varchar('firstname', { length: 255 }).notNull(),
  lastname: varchar('lastname', { length: 255 }).notNull(),
  birthday: date('birthday', { mode: 'string' }).notNull(),
  telephone: varchar('telephone', { length: 255 }),
  username: varchar('username', { length: 255 }).notNull(),
  edition: mysqlEnum(['java', 'bedrock']).notNull(),
  uuid: varchar('uuid', { length: 36 })
});

export type AddUserReq = Omit<typeof user.$inferInsert, 'id'>;

export type EditUserReq = Partial<Omit<typeof user.$inferInsert, 'id'>> & { id: number };

export type DeleteUserReq = {
  id: number;
};

export type ExistsUserReq = {
  username?: string;
  uuid?: string;
};

export type GetUsersReq = {
  username?: string | null;
  limit?: number;
};
export type GetUsersRes = (typeof user.$inferSelect)[];

export type GetUserByIdReq = {
  id: number;
};
export type GetUserByIdRes = typeof user.$inferSelect | null;

export type GetUserByUsernameReq = {
  username: string;
};
export type GetUserByUsernameRes = typeof user.$inferSelect | null;

export type GetUserByUuidReq = {
  uuid: string;
};

export async function addUser(db: Database, values: AddUserReq) {
  const userIds = await db.insert(user).values(values).$returningId();

  return userIds[0];
}

export async function editUser(db: Database, values: EditUserReq) {
  await db.update(user).set(values).where(eq(user.id, values.id));
}

export async function deleteUser(db: Database, values: DeleteUserReq) {
  await db.delete(user).where(eq(user.id, values.id));
}

export async function existsUser(db: Database, values: ExistsUserReq) {
  const u = db.query.user.findFirst({
    where: or(
      values.username != null ? eq(user.username, values.username) : undefined,
      values.uuid != null ? eq(user.uuid, values.uuid) : undefined
    )
  });

  return u ?? null;
}

export async function getUsers(db: Database, values: GetUsersReq): Promise<GetUsersRes> {
  return db.query.user.findMany({
    where: values.username != null ? like(user.username, `%${values.username}%`) : undefined,
    limit: values.limit
  });
}

export async function getUserById(db: Database, values: GetUserByIdReq): Promise<GetUserByIdRes> {
  const u = await db.query.user.findFirst({
    where: eq(user.id, values.id)
  });

  return u ?? null;
}

export async function getUserByUsername(db: Database, values: GetUserByUsernameReq): Promise<GetUserByUsernameRes> {
  const u = await db.query.user.findFirst({
    where: eq(user.username, values.username)
  });

  return u ?? null;
}

export async function getUserByUuid(db: Database, values: GetUserByUuidReq) {
  const u = await db.query.user.findFirst({
    where: eq(user.uuid, values.uuid)
  });

  return u ?? null;
}
