import { Result } from "../result";

describe("Result", () => {
  test("debe crear un resultado exitoso con datos", () => {
    const result = Result.ok("Success data");
    expect(result.isSuccess).toBe(true);
    expect(result.isFailure).toBe(false);
    expect(result.data).toBe("Success data");
  });

  test("debe crear un resultado fallido con un error", () => {
    const error = new Error("Something went wrong");
    const result = Result.fail(error);
    expect(result.isSuccess).toBe(false);
    expect(result.isFailure).toBe(true);
    expect(result.error).toBe(error);
  });

  test("debe lanzar un error al intentar obtener data de un resultado fallido", () => {
    const result = Result.fail(new Error("Failure"));
    expect(() => result.getData()).toThrow("Cannot get value data from a failed result.");
  });

  test("debe lanzar un error al intentar obtener error de un resultado exitoso", () => {
    const result = Result.ok("Success");
    expect(() => result.getError()).toThrow("Cannot get error from a successful result.");
  });

  test("debe devolver el valor por defecto cuando se usa getOrElse en un resultado fallido", () => {
    const result = Result.fail(new Error("Failure"));
    expect(result.getOrElse("Default value")).toBe("Default value");
  });

  test("debe devolver el valor correcto cuando se usa getOrElse en un resultado exitoso", () => {
    const result = Result.ok("Success");
    expect(result.getOrElse("Default value")).toBe("Success");
  });

  test("debe ejecutar la función correcta en match dependiendo del resultado", () => {
    const successResult = Result.ok("Success");
    const failureResult = Result.fail(new Error("Failure"));

    const successMatch = successResult.match(
      (data) => `Success: ${data}`,
      (error) => `Error: ${error}}`
    );
    expect(successMatch).toBe("Success: Success");

    const failureMatch = failureResult.match(
      (data) => `Success: ${data}`,
      (error) => `Error: ${error.message}`
    );
    expect(failureMatch).toBe("Error: Failure");
  });

  test("combine debe devolver el primer resultado fallido si hay alguno", () => {
    const success1 = Result.ok("Success 1");
    const failure = Result.fail(new Error("Failure"));
    const success2 = Result.ok("Success 2");

    const combined = Result.combine([success1, failure, success2]);
    expect(combined.isFailure).toBe(true);
    expect(combined.error.message).toBe("Failure");
  });

  test("combine debe devolver un resultado exitoso si todos los resultados son exitosos", () => {
    const success1 = Result.ok("Success 1");
    const success2 = Result.ok("Success 2");

    const combined = Result.combine([success1, success2]);
    expect(combined.isSuccess).toBe(true);
  });
});
