import { expect } from "chai";
import BN from "bn.js";
import { sellBaseInputInternal } from "../sdk/sell";
import { PublicKey } from "@solana/web3.js";

describe("sellBaseInput", () => {
  it("should compute final quote and minQuote correctly with typical inputs", () => {
    // Example pool reserves
    const baseReserve = new BN(1_000_000); // base tokens in pool
    const quoteReserve = new BN(2_000_000); // quote tokens in pool

    // The user wants to sell 50,000 base tokens
    const base = new BN(50_000);

    // Slippage = 1% => the user will accept at least 99% of finalQuote
    const slippage = 1;

    const result = sellBaseInputInternal(
      base,
      slippage,
      baseReserve,
      quoteReserve,
      {
        admin: PublicKey.unique(),
        lpFeeBasisPoints: new BN(30),
        protocolFeeBasisPoints: new BN(20),
        disableFlags: 0,
        protocolFeeRecipients: [],
        coinCreatorFeeBasisPoints: new BN(0),
        adminSetCoinCreatorAuthority: PublicKey.unique(),
      },
      PublicKey.default,
    );

    console.log("Final quote received:", result.uiQuote.toString());
    console.log("Min quote after slippage:", result.minQuote.toString());

    // Replace these placeholder values with the actual results once you confirm them offline:
    // For example, if you do the math manually or from a reference, set them here:
    const expectedFinalQuote = new BN(94761); // Example placeholder
    const expectedMinQuote = new BN(93813); // Example placeholder

    expect(result.uiQuote.toString()).to.equal(
      expectedFinalQuote.toString(),
      "Incorrect final quote",
    );
    expect(result.minQuote.toString()).to.equal(
      expectedMinQuote.toString(),
      "Incorrect min quote",
    );
  });

  it("should throw an error if 'baseReserve' or 'quoteReserve' is zero", () => {
    const slippage = 1;
    // baseReserve = 0
    expect(() =>
      sellBaseInputInternal(
        new BN(1000),
        slippage,
        new BN(0),
        new BN(2_000_000),
        {
          admin: PublicKey.unique(),
          lpFeeBasisPoints: new BN(30),
          protocolFeeBasisPoints: new BN(20),
          disableFlags: 0,
          protocolFeeRecipients: [],
          coinCreatorFeeBasisPoints: new BN(0),
          adminSetCoinCreatorAuthority: PublicKey.unique(),
        },
        PublicKey.default,
      ),
    ).to.throw(
      "Invalid input: 'baseReserve' or 'quoteReserve' cannot be zero.",
    );

    // quoteReserve = 0
    expect(() =>
      sellBaseInputInternal(
        new BN(1000),
        slippage,
        new BN(1_000_000),
        new BN(0),
        {
          admin: PublicKey.unique(),
          lpFeeBasisPoints: new BN(30),
          protocolFeeBasisPoints: new BN(20),
          disableFlags: 0,
          protocolFeeRecipients: [],
          coinCreatorFeeBasisPoints: new BN(0),
          adminSetCoinCreatorAuthority: PublicKey.unique(),
        },
        PublicKey.default,
      ),
    ).to.throw(
      "Invalid input: 'baseReserve' or 'quoteReserve' cannot be zero.",
    );
  });

  it("should throw an error if fees exceed total output (finalQuote negative)", () => {
    // We want quoteAmountOut > 0 but finalQuote < 0 after subtracting fees.
    const base = new BN(1);
    const baseReserve = new BN(1);
    const quoteReserve = new BN(2);
    const slippage = 1;

    expect(() =>
      sellBaseInputInternal(
        base,
        slippage,
        baseReserve,
        quoteReserve,
        {
          admin: PublicKey.unique(),
          lpFeeBasisPoints: new BN(9000),
          protocolFeeBasisPoints: new BN(2000),
          disableFlags: 0,
          protocolFeeRecipients: [],
          coinCreatorFeeBasisPoints: new BN(0),
          adminSetCoinCreatorAuthority: PublicKey.unique(),
        },
        PublicKey.default,
      ),
    ).to.throw("Fees exceed total output; final quote is negative.");
  });
});
