import { api } from "../http/instances";
import { CrudService } from "../crud";
import { UserEntity } from "../entities/dtos";
import * as T from "./dtos";

const USUARIOS_CADASTRO_ENTITY = "UsuariosCadastro";

const USERS_ENTITY = "Users";

export class UserAlreadyHasAccessError extends Error {
  constructor() {
    super("Usuário já possui acesso à plataforma.");
    this.name = "UserAlreadyHasAccessError";
  }
}

export type RegisterUserResult = "created" | "promoted";

export const AuthService = {
  async signIn(credentials: T.SignInRequest): Promise<T.SignInResponse> {
    const response = await api.post<T.SignInResponse>("/autenticar", credentials);
    return response.data;
  },

  async getUsuarioLogado(): Promise<T.UsuarioLogadoResponse> {
    const response = await api.get<T.UsuarioLogadoResponse>("/usuario");
    return response.data;
  },

  async getUserById(id: string): Promise<UserEntity> {
    return CrudService.retrieve<UserEntity>(USERS_ENTITY, id);
  },

  async getAllUsers(): Promise<UserEntity[]> {
    return CrudService.retrieveAllPages<UserEntity>(USERS_ENTITY);
  },

  async registerUser(name: string, email: string): Promise<RegisterUserResult> {
    const normalizedEmail = email.trim().toLowerCase();
    const existingUser = (await this.getAllUsers()).find(
      (u) => u.email?.trim().toLowerCase() === normalizedEmail,
    );

    if (existingUser) {
      if (existingUser.role === "ADMIN" || existingUser.role === "EMBRAPA") {
        throw new UserAlreadyHasAccessError();
      }

      await CrudService.update<UserEntity>(USERS_ENTITY, String(existingUser.id), {
        ...existingUser,
        role: "EMBRAPA",
      });
      return "promoted";
    }

    const password = Array.from(
      crypto.getRandomValues(new Uint8Array(8)),
      (b) => b.toString(16).padStart(2, "0"),
    ).join("");

    const cadastroRes = await api.post<{ idt: number }>("/update", {
      entity: USUARIOS_CADASTRO_ENTITY,
      idValue: "",
      data: {
        matricula: "",
        email,
        nome: name,
        senha: password,
        stsativo: true,
        ststrabalhaembrapa: true,
      },
    });

    const usuariosCadastroId = cadastroRes.data.idt;

    try {
      await api.post("/update", {
        entity: USERS_ENTITY,
        idValue: "",
        data: {
          email,
          name,
          cpf: null,
          passwordHash: password,
          role: "EMBRAPA",
          createdAt: new Date().toISOString().slice(0, 23),
          usuariosCadastroId,
        },
      });
    } catch (err) {
      await CrudService.remove(USUARIOS_CADASTRO_ENTITY, String(usuariosCadastroId));
      throw err;
    }

    await api.post("/gerarSenha", {
      email,
      corpo: "Seu acesso ao sistema IDH Leite foi criado. Utilize a senha temporária gerada neste e-mail. Recomendamos alterar sua senha após o primeiro acesso.",
    });

    return "created";
  },

  async deleteUser(id: string): Promise<void> {
    await CrudService.remove(USERS_ENTITY, id);
  },

  async changePassword(params: T.ChangePasswordParams): Promise<void> {
    await api.post("/update", {
      entity: USUARIOS_CADASTRO_ENTITY,
      idValue: String(params.usuariosCadastroId),
      data: {
        idt: params.usuariosCadastroId,
        matricula: params.matricula,
        email: params.email,
        nome: params.name,
        senha: params.newPassword,
      },
    });
  },
};
