import { ConflictException, NotFoundException } from "@nestjs/common";
import { IdentityService } from "./identity.service";
import { Identidad, IdentidadEstado, RolPlataforma } from "./entities/identidad.entity";

function createService(overrides: Record<string, any> = {}) {
  const identidad: Identidad = {
    id: 7,
    email: "vieja@example.com",
    nombre: "Persona",
    passwordHash: "hash-viejo",
    estado: IdentidadEstado.ACTIVA,
    rolPlataforma: RolPlataforma.NINGUNO,
    createdAt: new Date(),
    updatedAt: new Date(),
  };

  const identidadRepo = {
    findOne: jest.fn(async ({ where }: any) => {
      if (where.id !== undefined) return where.id === identidad.id ? identidad : null;
      if (where.email !== undefined) return where.email === identidad.email ? identidad : null;
      return null;
    }),
    save: jest.fn(async (data: any) => ({ ...identidad, ...data })),
    ...overrides.identidadRepo,
  };

  const service = new IdentityService(
    identidadRepo as any,
    {} as any,
    {} as any,
    {} as any,
  );
  return { service, identidadRepo, identidad };
}

describe("IdentityService.updateCredenciales", () => {
  it("actualiza el email y la contraseña de la identidad", async () => {
    const { service, identidadRepo } = createService();

    const result = await service.updateCredenciales(7, {
      email: "nueva@example.com",
      passwordHash: "hash-nuevo",
    });

    expect(result.email).toBe("nueva@example.com");
    expect(result.passwordHash).toBe("hash-nuevo");
    expect(identidadRepo.save).toHaveBeenCalledWith(
      expect.objectContaining({ email: "nueva@example.com", passwordHash: "hash-nuevo" }),
    );
  });

  it("no toca la identidad si no se pasan cambios", async () => {
    const { service, identidadRepo, identidad } = createService();

    const result = await service.updateCredenciales(7, {});

    expect(result.email).toBe(identidad.email);
    expect(result.passwordHash).toBe(identidad.passwordHash);
  });

  it("lanza ConflictException si el nuevo correo ya pertenece a otra identidad", async () => {
    const otra = { id: 99, email: "ocupado@example.com" };
    const { service } = createService({
      identidadRepo: {
        findOne: jest.fn(async ({ where }: any) => {
          if (where.id === 7) {
            return {
              id: 7,
              email: "vieja@example.com",
              passwordHash: "hash-viejo",
              estado: IdentidadEstado.ACTIVA,
              rolPlataforma: RolPlataforma.NINGUNO,
            };
          }
          if (where.email === "ocupado@example.com") return otra;
          return null;
        }),
        save: jest.fn(),
      },
    });

    await expect(
      service.updateCredenciales(7, { email: "ocupado@example.com" }),
    ).rejects.toThrow(ConflictException);
  });

  it("lanza NotFoundException si la identidad no existe", async () => {
    const { service } = createService({
      identidadRepo: { findOne: jest.fn(async () => null), save: jest.fn() },
    });

    await expect(service.updateCredenciales(999, { email: "x@example.com" })).rejects.toThrow(
      NotFoundException,
    );
  });
});
