import BigNumber from "bignumber.js";
import Token, { TokenInfo } from "./token";
import { ethers } from 'ethers';
import { LeveragedPool, PoolKeeper } from '@tracer-protocol/perpetual-pools-contracts/types';
import { providers as MCProvider } from '@0xsequence/multicall';
import PoolToken from "./poolToken";
import Committer from './committer';
import { OraclePriceTransformer, PoolStatePreview, TotalPoolCommitmentsBN } from "../types";
import SMAOracle from "./smaOracle";
import PoolStateHelper from "./poolStateHelper";
/**
 * Static pool info that can be passed in as props
 * Most is optional except the address, this is a requirement
 */
export interface StaticPoolInfo {
    address: string;
    name?: string;
    /**
     * Update interaval (time between upkeeps) in seconds.
     */
    updateInterval?: number;
    /**
     * Front running interaval in seconds.
     * Time before the upkeep where no more commits are permitted
     */
    frontRunningInterval?: number;
    leverage?: number;
    fee?: string;
    keeper?: string;
    oracle?: string;
    committer?: {
        address: string;
    };
    shortToken?: TokenInfo;
    longToken?: TokenInfo;
    settlementToken?: TokenInfo;
}
/**
 * Pool class constructor inputs.
 * Most values are optional, if no value is provided, the initiator will fetch
 * 	the information from the contract.
 * The only required inputs are an `address` and `rpcURL`
 */
export interface IPool extends StaticPoolInfo {
    provider: ethers.providers.JsonRpcProvider;
    oraclePriceTransformer?: OraclePriceTransformer;
}
/**
 * LeveragedPool class initiated with an an `address` and an `rpcURL`.
 * Stores relevant LeveragedPool information.
 * It is optional for the user to provide additional pool information, reducing
 * 	the number of RPC calls. This optional info is static information
 * 	of the pool, such as names and addresses
 * The constructor is private so must be instantiated with {@linkcode Pool.Create}
 */
export default class Pool {
    address: string;
    provider: ethers.providers.Provider | ethers.Signer | undefined;
    multicallProvider: MCProvider.MulticallProvider | ethers.Signer | undefined;
    chainId: number | undefined;
    _contract?: LeveragedPool;
    _keeper?: PoolKeeper;
    name: string;
    updateInterval: BigNumber;
    frontRunningInterval: BigNumber;
    leverage: number;
    fee: BigNumber;
    keeper: string;
    committer: Committer;
    poolStateHelper: PoolStateHelper;
    oracle: SMAOracle;
    shortToken: PoolToken;
    longToken: PoolToken;
    settlementToken: Token;
    lastUpdate: BigNumber;
    lastPrice: BigNumber;
    shortBalance: BigNumber;
    longBalance: BigNumber;
    oraclePrice: BigNumber;
    oraclePriceTransformer: OraclePriceTransformer;
    /**
     * Private constructor to initialise a Pool instance
     * @param address LeveragedPool contract address
     * @param provider ethers RPC provider
     * @private
     */
    private constructor();
    /**
     * Replacement constructor pattern to support async initialisations
     * @param poolInfo {@link IPool| IPool interface props}
     * @returns a Promise containing an initialised Pool class ready to be used
     */
    static Create: (poolInfo: IPool) => Promise<Pool>;
    /**
     * Creates an empty pool that can be used as a default
     */
    static CreateDefault: () => Pool;
    /**
     * TODO
     */
    static DeployPool: () => void;
    /**
     * Private initialisation function called in {@link Pool.Create}
     * @private
     * @param poolInfo {@link IPool | IPool interface props}
     */
    private init;
    /**
     * Calculates the pools next value transfer in quote token units (eg USD).
     * Uses {@link getNextValueTransfer}.
     * @returns and object containing short and long value transfer.
     * 	The values will be a negation of eachother but this way reads better than
     * 	returning a winning side as well as a value
     */
    getNextValueTransfer: () => {
        shortValueTransfer: BigNumber;
        longValueTransfer: BigNumber;
    };
    /**
     * Calculates and returns the long token price.
     * Uses {@link calcTokenPrice}.
     * @returns the long token price in quote token units (eg USD)
     */
    getLongTokenPrice: () => BigNumber;
    /**
     * Calculates and returns the fee and leverage for the current Pool address.
     * Compares to a list of known deprecated Pool addresses and uses old method if necessary.
     * @returns the fee and leverage amounts
     */
    getFeeAndLeverage: (poolInfo: IPool, chainId: number, name: string, provider: ethers.providers.Provider, contract: LeveragedPool) => Promise<[string | ethers.BigNumber, number | ethers.BigNumber]>;
    /**
     * Calculates and returns the short token price.
     * Uses {@link calcTokenPrice}.
     * @returns the long token price in quote token units (eg USD)
     */
    getShortTokenPrice: () => BigNumber;
    /**
     * Calculates and returns the long token price as if the rebalance occured at t = now.
     * Uses {@link calcTokenPrice}.
     * @returns the long token price in quote token units (eg USD)
     */
    getNextLongTokenPrice: () => BigNumber;
    /**
     * Calculates and returns the short token price as if the rebalance occured at t = now.
     * Uses {@link calcTokenPrice}.
     * @returns the long token price in quote token units (eg USD)
     */
    getNextShortTokenPrice: () => BigNumber;
    /**
     * Calculates the pools current skew between long and short balances.
     * This is the ratio between the long and short pools
     * @returns the pool skew
     */
    getSkew: () => BigNumber;
    /**
     * Fetches and sets the pools long and short balances from the contract state
     * @returns the fetched long and short balances
     */
    fetchPoolBalances: () => Promise<{
        longBalance: BigNumber;
        shortBalance: BigNumber;
    }>;
    /**
     * Sets and gets the most up to date oraclePrice
     */
    fetchOraclePrice: () => Promise<BigNumber>;
    /**
     * Sets and gets the most up to date pool price.
     * This is the price the pool used last upkeep
     */
    fetchLastPrice: () => Promise<BigNumber>;
    /**
     * Sets and gets the most up to date pool price.
     * This is the price the pool used last upkeep
     */
    fetchLastPriceTimestamp: () => Promise<BigNumber>;
    /**
     * @deprecated
     * get all total pool commitments between now and `now + frontRunningInterval`
     * @returns promise resolving to an array of `TotalPoolCommitmentsBN`s
     */
    getPendingCommitsInFrontRunningInterval: () => Promise<TotalPoolCommitmentsBN[]>;
    /**
     * @deprecated
     * get total pool commitments between now and `now + updateInterval`
     * @returns promise resolving to a `TotalPoolCommitmentsBN` object
     */
    getPendingCommitsInUpdateInterval: () => Promise<TotalPoolCommitmentsBN>;
    /**
     * @deprecated
     * @param atEndOf whether to fetch preview for end of update interval or front running interval
     * @param forceRefreshInputs if `true`, will refresh
     * `this.longBalance`,
     * `this.shortBalance`,
     * `this.longToken.supply`,
     * `this.shortToken.supply`,
     * `this.lastPrice` and `this.oraclePrice` before calculating pool state preview
     * @returns
     */
    getPoolStatePreview: (atEndOf: 'frontRunningInterval' | 'updateInterval', forceRefreshInputs?: boolean) => Promise<PoolStatePreview>;
    /**
     *
     * calculate expected pool state via on chain state calculations contract
     *
     * @param atEndOf whether to fetch preview for end of update interval or front running interval
     * @returns
     */
    getExpectedPoolState: (atEndOf: 'frontRunningInterval' | 'updateInterval', forceRefreshInputs?: boolean) => Promise<PoolStatePreview>;
    /**
     * Replaces the provider and connects the contract instance, also connects the
     * 	settlementToken, short and long tokens and Committer instance
     * @param provider The new provider to connect to
     */
    connect: (provider: ethers.providers.Provider | ethers.Signer) => void;
    getAnnualFee: () => BigNumber;
    /**
     * Sets the pools long balance
     * @param longBalance balance to set
     */
    setLongBalance: (longBalance: BigNumber) => void;
    /**
     * Sets the pools short balance
     * @param shortBalance balance to set
     */
    setShortBalance: (shortbalance: BigNumber) => void;
    /**
     * Sets the pools oracle price
     * @param price new price to set
     */
    setOraclePrice: (price: BigNumber) => void;
    /**
     * Sets the pools last price
     * @param price new price to set
     */
    setLastPrice: (price: BigNumber) => void;
    /**
     * Sets the pools last price
     * @param price new price to set
     */
    setLastPriceTimestamp: (timestamp: BigNumber) => void;
}
