import { TRPCError } from "@trpc/server";
import type { Context } from "~/server/api/trpc";
import type { Users, UsersId, UsersUpdate } from "~/schemas/public/Users";
import { upsertAnagrafica } from "~/server/services/user.service";
import { checkCtxAdmin, checkCtxSession } from "~/server/utils/ctxChecker";
import { db, type Querier } from "~/server/db";
import type { UsersAnagraficaUpdate } from "~/schemas/public/UsersAnagrafica";

type EditAccountInput = {
  id: UsersId;
  nome: string;
  cognome: string;
  email: string;
  telefono: string;
  isAdmin?: boolean;
};

export const editAccountHandler = async ({
  ctx,
  input: { id, nome, cognome, email, telefono, isAdmin },
}: {
  ctx: Context;
  input: EditAccountInput;
}) => {
  checkCtxSession({ ctx });
  try {
    const data: UsersUpdate = {
      nome: nome.trim(),
      cognome: cognome.trim(),
      email: email.trim(),
      telefono: telefono.replace(/\s/g, ""),
      username: `${nome.trim()} ${cognome.trim()}`,
    };

    if (isAdmin !== undefined) {
      data.isAdmin = isAdmin;
    }
    const user = await db
      .updateTable("users")
      .set(data)
      .where("id", "=", id)
      .returningAll()
      .execute();

    if (!user) {
      throw new TRPCError({
        code: "INTERNAL_SERVER_ERROR",
        message: "errore modifica utente",
      });
    }
    return user;
  } catch {
    throw new TRPCError({
      code: "INTERNAL_SERVER_ERROR",
      message: "errore modifica utente",
    });
  }
};

export const editAnagraficaHandler = async ({
  input,
}: {
  input: UsersAnagraficaUpdate;
}) => {
  return await upsertAnagrafica({
    db,
    data: input,
  });
};

export const deleteUserHandler = async ({
  ctx,
  id,
}: {
  ctx: Context;
  id: UsersId;
}) => {
  checkCtxAdmin({ ctx });

  try {
    await db.deleteFrom("users").where("id", "=", id).execute();
    return { success: true };
  } catch {
    throw new TRPCError({
      code: "INTERNAL_SERVER_ERROR",
      message: "errore cancellazione utente",
    });
  }
};

export const blockUserHandler = async ({
  ctx,
  id,
}: {
  ctx: Context;
  id: UsersId;
}) => {
  checkCtxAdmin({ ctx });
  return await db.transaction().execute(async (trx) => {
    return await trx
      .updateTable("users")
      .set((eb) => ({
        isBlocked: eb.not("isBlocked"),
      }))
      .where("id", "=", id)
      .where("isAdmin", "=", false)
      .returningAll()
      .execute();
  });
};

export const getUserHandler = async ({
  db,
  id,
}: {
  db: Querier;
  id: UsersId;
}): Promise<Users | null> => {
  try {
    const user = await db
      .selectFrom("users")
      .where("id", "=", id)
      .selectAll()
      .executeTakeFirst();

    if (!user) {
      return null;
    }
    return user;
  } catch {
    throw new TRPCError({
      code: "INTERNAL_SERVER_ERROR",
      message: "errore get utente",
    });
  }
};
export type getUserReturnType = Awaited<ReturnType<typeof getUserHandler>>;

export type NonNullableUser = {
  id: NonNullable<UsersId>;
  username: NonNullable<string>;
  nome: string | null;
};
export const getActiveUserWithoutChatHandler = async ({
  db,
}: {
  db: Querier;
}) => {
  const users = await db
    .selectFrom("users")
    .fullJoin("chats", "chats.user_ref", "users.id")
    .select(["users.id", "users.username", "users.nome"])
    .where("chats.chatid", "is", null)
    .where("users.isBlocked", "=", false)
    .where("users.isAdmin", "=", false)
    .execute();
  return users.filter((user): user is NonNullableUser => {
    return user.id !== null && user.username !== null;
  });
};

export const getUsersWithChatInfoHandler = async ({ db }: { db: Querier }) => {
  return await db
    .selectFrom("users")
    .select([
      "users.id",
      "users.username",
      "users.email",
      "users.isAdmin",
      "users.isBlocked",
      "users.created_at",
    ])
    .leftJoin("chats", "chats.user_ref", "users.id")
    .select(["chats.chatid"])
    .orderBy("users.id", "desc")
    .select(["users.id as id"])
    .execute();
};
