import type { UsersId, NewUsers } from "~/schemas/public/Users";
import { db, type Querier } from "~/server/db";
import { TRPCError } from "@trpc/server";
import type { UsersAnagraficaUpdate } from "~/schemas/public/UsersAnagrafica";
import type { Session } from "~/server/api/trpc";

export const findUser_byId = async ({ id }: { id: string }) => {
  try {
    return await db
      .selectFrom("users")
      .selectAll()
      .where("id", "=", id as UsersId)
      .executeTakeFirst();
  } catch (e) {
    throw new TRPCError({
      code: "INTERNAL_SERVER_ERROR",
      message: "Errore findUser_byId: " + (e as Error).message,
    });
  }
};
export const findUser_byEmail = async ({ email }: { email: string }) => {
  try {
    return await db
      .selectFrom("users")
      .selectAll()
      .where("email", "=", email)
      .executeTakeFirst();
  } catch (e) {
    throw new TRPCError({
      code: "INTERNAL_SERVER_ERROR",
      message: "Errore findUser_byEmail: " + (e as Error).message,
    });
  }
};
export const findUser_byId_MINI = async ({
  userId,
}: {
  userId: UsersId;
}): Promise<Session | undefined> => {
  try {
    return await db
      .selectFrom("users")
      .select(["id", "username", "nome", "email", "isAdmin", "isBlocked"])
      .where("id", "=", userId)
      .executeTakeFirst();
  } catch (e) {
    throw new TRPCError({
      code: "INTERNAL_SERVER_ERROR",
      message: "errore findUser_byId_MINI: " + (e as Error).message,
    });
  }
};

export const getUser = async ({
  db,
  userId,
}: {
  db: Querier;
  userId: UsersId;
}) => {
  try {
    return await db
      .selectFrom("users")
      .selectAll()
      .where("id", "=", userId)
      .executeTakeFirstOrThrow();
  } catch (e) {
    throw new TRPCError({
      code: "INTERNAL_SERVER_ERROR",
      message: "errore getUtente: " + (e as Error).message,
    });
  }
};

export const addUser = async ({
  db,
  data,
}: {
  db: Querier;
  data: NewUsers;
}) => {
  try {
    const user = await db
      .insertInto("users")
      .values({
        ...data,
      })
      .onConflict((oc) => oc.column("email").doNothing())
      .returningAll()
      .executeTakeFirst();

    return user;
  } catch (e) {
    throw new TRPCError({
      code: "INTERNAL_SERVER_ERROR",
      message: "Errore addUser: " + (e as Error).message,
    });
  }
};

export type UserWithAnagrafica = Awaited<
  ReturnType<typeof getUserWithAnagraficaHandler>
>;
export const getUserWithAnagraficaHandler = async ({
  db,
  userId,
}: {
  db: Querier;
  userId: UsersId;
}) => {
  try {
    return await db
      .selectFrom("users")
      .select([
        "id",
        "nome",
        "cognome",
        "email",
        "telefono",
        "created_at",
        "isAdmin",
        "isBlocked",
        "isAdminMade",
      ])
      .where("id", "=", userId)
      .leftJoin("users_anagrafica", "users_anagrafica.userid", "users.id")
      .selectAll("users_anagrafica")
      .executeTakeFirstOrThrow();
  } catch (e) {
    throw new TRPCError({
      code: "INTERNAL_SERVER_ERROR",
      message: "Errore interno: " + (e as Error).message,
    });
  }
};

export const upsertAnagrafica = async ({
  db,
  data,
}: {
  db: Querier;
  data: UsersAnagraficaUpdate;
}) => {
  try {
    const { idanagrafica, userid, ...rest } = data;
    if (!userid) {
      throw new TRPCError({
        code: "BAD_REQUEST",
        message: "Errore interno, utente non trovato",
      });
    }
    if (idanagrafica) {
      return await db
        .updateTable("users_anagrafica")
        .set({
          ...rest,
        })
        .where("userid", "=", userid)
        .returningAll()
        .executeTakeFirst();
    } else {
      return await db
        .insertInto("users_anagrafica")
        .values({
          userid,
          ...rest,
        })
        .onConflict((oc) => oc.column("userid").doNothing())
        .returningAll()
        .executeTakeFirst();
    }
  } catch (e) {
    throw new TRPCError({
      code: "INTERNAL_SERVER_ERROR",
      message: "Errore updateAnagrafica: " + (e as Error).message,
    });
  }
};
