import { jest } from "@jest/globals";
import axios from "axios";
import PsbService from "../../src/thirdParties/psbService.js";

describe("9PSB Service (Unit Tests)", () => {
  let postSpy;

  beforeEach(() => {
    postSpy = jest.spyOn(axios, "post");
  });

  afterEach(() => {
    postSpy.mockRestore();
  });

  describe("Authentication", () => {
    it("should fetch IVA token successfully", async () => {
      postSpy.mockResolvedValueOnce({
        data: { access_token: "iva_token_abc", expires_in: 3600 },
      });

      const token = await PsbService.authenticate();
      expect(token).toBe("iva_token_abc");
      expect(postSpy).toHaveBeenCalledWith(
        expect.stringContaining("/virtualaccount/authenticate"),
        expect.objectContaining({
          publickey: expect.any(String),
          privatekey: expect.any(String),
        })
      );
    });

    it("should fetch WAAS token successfully", async () => {
      postSpy.mockResolvedValueOnce({
        data: { accessToken: "waas_token_xyz" },
      });

      const resp = await PsbService.authenticateWaas9PSB();
      expect(PsbService.extractToken(resp)).toBe("waas_token_xyz");
      expect(postSpy).toHaveBeenCalledWith(
        expect.stringContaining("/authenticate"),
        expect.objectContaining({
          username: expect.any(String),
          password: expect.any(String),
          clientId: expect.any(String),
          clientSecret: expect.any(String),
        }),
        expect.any(Object)
      );
    });
  });

  describe("Virtual Account Creation", () => {
    it("should call create static account endpoint with correct payload", async () => {
      postSpy
        .mockResolvedValueOnce({
          data: { access_token: "token_123" }, // For auth
        })
        .mockResolvedValueOnce({
          data: {
            status: "SUCCESS",
            customer: { account: { number: "1234567890" } },
          }, // For create
        });

      const response = await PsbService.createStaticAccount({
        reference: "ref-1",
        amount: 0,
        description: "Test account",
        name: "Test Customer",
      });

      expect(response.customer.account.number).toBe("1234567890");
      expect(postSpy).toHaveBeenNthCalledWith(
        2,
        expect.stringContaining("/virtualaccount/create"),
        expect.objectContaining({
          transaction: { reference: "ref-1" },
          order: expect.objectContaining({ amount: 0, description: "Test account" }),
          customer: { account: { name: "Test Customer", type: "STATIC" } },
        }),
        expect.any(Object)
      );
    });
  });

  describe("WAAS Operations", () => {
    it("should fetch banks list", async () => {
      postSpy
        .mockResolvedValueOnce({
          data: { accessToken: "waas_token" }, // auth
        })
        .mockResolvedValueOnce({
          data: [{ bankName: "9PSB", bankCode: "120001" }], // get_banks
        });

      const response = await PsbService.getBanks("AIRPERO");
      expect(response).toEqual([{ bankName: "9PSB", bankCode: "120001" }]);
    });

    it("should resolve account names via Other Banks Enquiry", async () => {
      postSpy
        .mockResolvedValueOnce({
          data: { accessToken: "waas_token" }, // auth
        })
        .mockResolvedValueOnce({
          data: { accountName: "John Doe", status: "SUCCESS" }, // enquiry
        });

      const response = await PsbService.otherBanksEnquiry({
        customer: { account: { number: "0000000000", bank: "120001" } },
      }, "AIRPERO");

      expect(response.accountName).toBe("John Doe");
    });

    it("should trigger payout transfer", async () => {
      postSpy
        .mockResolvedValueOnce({
          data: { accessToken: "waas_token" }, // auth
        })
        .mockResolvedValueOnce({
          data: { status: "SUCCESS", message: "Payout initiated" }, // transfer
        });

      const response = await PsbService.walletOtherBanks({
        transaction: { reference: "tx-ref" },
        order: { amount: 500 },
      }, "AIRPERO");

      expect(response.status).toBe("SUCCESS");
    });

    it("should requery wallet transactions", async () => {
      postSpy
        .mockResolvedValueOnce({
          data: { accessToken: "waas_token" }, // auth
        })
        .mockResolvedValueOnce({
          data: { status: "SUCCESS", transactionId: "tx-123" }, // requery
        });

      const response = await PsbService.walletRequery({
        transactionId: "tx-123",
      }, "AIRPERO");

      expect(response.status).toBe("SUCCESS");
    });
  });
});
