const {
  PAYOUT_FAILURE_MESSAGES,
  DEFAULT_PAYOUT_FAILURE,
  getPayoutFailureMessage,
} = require("../../../utils/payoutErrors");

describe("Payout Errors Utility", () => {
  describe("PAYOUT_FAILURE_MESSAGES", () => {
    const requiredProperties = ["message", "action", "requiresBankUpdate"];

    const allFailureCodes = [
      "account_closed",
      "account_frozen",
      "bank_account_restricted",
      "bank_ownership_changed",
      "could_not_process",
      "debit_not_authorized",
      "declined",
      "insufficient_funds",
      "invalid_account_number",
      "incorrect_account_holder_name",
      "incorrect_account_holder_type",
      "invalid_currency",
      "no_account",
      "unsupported_card",
    ];

    test.each(allFailureCodes)("%s exists in PAYOUT_FAILURE_MESSAGES", (code) => {
      expect(PAYOUT_FAILURE_MESSAGES).toHaveProperty(code);
    });

    test.each(allFailureCodes)("%s has all required properties", (code) => {
      const failureInfo = PAYOUT_FAILURE_MESSAGES[code];
      for (const prop of requiredProperties) {
        expect(failureInfo).toHaveProperty(prop);
      }
    });

    test.each(allFailureCodes)("%s has non-empty message and action", (code) => {
      const failureInfo = PAYOUT_FAILURE_MESSAGES[code];
      expect(failureInfo.message.length).toBeGreaterThan(0);
      expect(failureInfo.action.length).toBeGreaterThan(0);
    });

    test.each(allFailureCodes)("%s has boolean requiresBankUpdate", (code) => {
      const failureInfo = PAYOUT_FAILURE_MESSAGES[code];
      expect(typeof failureInfo.requiresBankUpdate).toBe("boolean");
    });

    // Codes that require bank account update
    const codesRequiringBankUpdate = [
      "account_closed",
      "bank_account_restricted",
      "bank_ownership_changed",
      "insufficient_funds",
      "invalid_account_number",
      "incorrect_account_holder_name",
      "incorrect_account_holder_type",
      "invalid_currency",
      "no_account",
      "unsupported_card",
    ];

    test.each(codesRequiringBankUpdate)(
      "%s requires bank update",
      (code) => {
        expect(PAYOUT_FAILURE_MESSAGES[code].requiresBankUpdate).toBe(true);
      }
    );

    // Codes that don't require bank account update (temporary issues)
    const temporaryCodes = [
      "account_frozen",
      "could_not_process",
      "debit_not_authorized",
      "declined",
    ];

    test.each(temporaryCodes)(
      "%s does not require bank update (temporary issue)",
      (code) => {
        expect(PAYOUT_FAILURE_MESSAGES[code].requiresBankUpdate).toBe(false);
      }
    );
  });

  describe("DEFAULT_PAYOUT_FAILURE", () => {
    test("has all required properties", () => {
      expect(DEFAULT_PAYOUT_FAILURE).toHaveProperty("message");
      expect(DEFAULT_PAYOUT_FAILURE).toHaveProperty("action");
      expect(DEFAULT_PAYOUT_FAILURE).toHaveProperty("requiresBankUpdate");
    });

    test("has non-empty message and action", () => {
      expect(DEFAULT_PAYOUT_FAILURE.message.length).toBeGreaterThan(0);
      expect(DEFAULT_PAYOUT_FAILURE.action.length).toBeGreaterThan(0);
    });

    test("defaults to requiring bank update", () => {
      expect(DEFAULT_PAYOUT_FAILURE.requiresBankUpdate).toBe(true);
    });
  });

  describe("getPayoutFailureMessage", () => {
    test("returns correct message for known failure code", () => {
      const result = getPayoutFailureMessage("account_closed");

      expect(result.message).toBe("Your bank account has been closed.");
      expect(result.action).toBe(
        "Please update your bank account in your payout settings."
      );
      expect(result.requiresBankUpdate).toBe(true);
    });

    test("returns correct message for account_frozen", () => {
      const result = getPayoutFailureMessage("account_frozen");

      expect(result.message).toBe("Your bank account is frozen.");
      expect(result.action).toContain("contact your bank");
      expect(result.requiresBankUpdate).toBe(false);
    });

    test("returns correct message for invalid_account_number", () => {
      const result = getPayoutFailureMessage("invalid_account_number");

      expect(result.message).toContain("invalid");
      expect(result.requiresBankUpdate).toBe(true);
    });

    test("returns correct message for could_not_process", () => {
      const result = getPayoutFailureMessage("could_not_process");

      expect(result.message).toContain("could not process");
      expect(result.action).toContain("retry");
      expect(result.requiresBankUpdate).toBe(false);
    });

    test("returns default message for unknown failure code", () => {
      const result = getPayoutFailureMessage("unknown_code_xyz");

      expect(result).toEqual(DEFAULT_PAYOUT_FAILURE);
    });

    test("returns default message for null failure code", () => {
      const result = getPayoutFailureMessage(null);

      expect(result).toEqual(DEFAULT_PAYOUT_FAILURE);
    });

    test("returns default message for undefined failure code", () => {
      const result = getPayoutFailureMessage(undefined);

      expect(result).toEqual(DEFAULT_PAYOUT_FAILURE);
    });

    test("returns default message for empty string failure code", () => {
      const result = getPayoutFailureMessage("");

      expect(result).toEqual(DEFAULT_PAYOUT_FAILURE);
    });
  });
});
