/* Config file should be manually updated every time on-chain program updates */

import { AddressLookupTableAccount, Keypair, PublicKey, TransactionInstruction, TransactionSignature } from "@solana/web3.js";
import { BN } from "@coral-xyz/anchor";

export const BASKETS_PROGRAM_ID = new PublicKey("2KehYt3KsEQR53jYcxjbQp2d2kCp4AkuQW68atufRwSr");
export const BASKETS_PROGRAM_PDA = new PublicKey("BLBYiq48WcLQ5SxiftyKmPtmsZPUBEnDEjqEnKGAR4zx");
// export const BASKETS_LOOKUP_TABLE = new PublicKey("4Bp4czjcokF4WSvLaqnhA4vdRWwV1k3JB5zEUkVRfF1M");
export const BASKETS_LOOKUP_TABLE_1 = new PublicKey("8ior8P1ouuZ6yPGLvca6h1Tvzia51uFLk6RXMGJEjTRB");
export const BASKETS_LOOKUP_TABLE_2 = new PublicKey("6TKbsk8uV7ZNJL9RKaZ1YP69datKUcdTimULm9bv8rJR");

export const TOKEN_LIST_ADDRESS = new PublicKey("3SnUughtueoVrhevXTLMf586qvKNNXggNsc7NgoMUU1t");
export const TOKEN_STATS_ADDRESS = new PublicKey("5u1AuCafhCtWENUo3m2aLKtDuoQQfWzr2bb5bDJzD47q");
export const DATABASE_ADDESS = new PublicKey("2FC4kaLTtyqSypK9rZiSMvsM3WkA6kz9CUmu57h9wecb");
export const CURVE_DATA_ADDRESS = new PublicKey("4QMjSHuM3iS7Fdfi8kZJfHRKoEJSDHEtEwqbChsTcUVK");

export const CREATE_FEE_ACCOUNT = new PublicKey("AWfpfzA6FYbqx4JLz75PDgsjH7jtBnnmJ6MXW5zNY2Ei");
export const BUY_FEE_ACCOUNT = new PublicKey("48jWdAAChBznvLngKcRMBvJZ19VbuzU7WYgNtCaQgvK7");
export const BUY_FEE_WALLET = new PublicKey("AWfpfzA6FYbqx4JLz75PDgsjH7jtBnnmJ6MXW5zNY2Ei");
export const REBALANCE_FEE_WALLET = new PublicKey("2WEjwiy3W8U3EJ5E8Zgm2kWKzEDdndboiyVJnv6yqUYB");
export const REBALANCE_FEE_ACCOUNT = new PublicKey("CXwdWJaxyMAZA88UPs3CXMKo4ykEv8No4xLWPVGmMS3L");
export const SWAP_FEE_ACCOUNT = new PublicKey("AWfpfzA6FYbqx4JLz75PDgsjH7jtBnnmJ6MXW5zNY2Ei");

export const PRISM_AGGREGATOR = new PublicKey("AGGZ2djPDEvrbgiBTV3P8UoB8Zf1kGawkWd2eu553o44");
export const JUP_AGGREGATOR = new PublicKey("JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4");

export const BEYOND_LST_BASKET = new PublicKey("5GPvpZ9Jga9JoZ5eVQms9hQARwexmCjuqDaTxF6LMdsF");

export const SWB_PID = new PublicKey("SBondMDrcV3K4kxZR1HNVT7osZxAHVHgYXL5Ze1oMUv");

export const NUM_OF_DAYS_IN_DATABASE = 460;
export const COMBINED_TOKENS_IN_A_BASKET = 15;
export const NUM_OF_TOKENS_IN_BASKET = 20;
export const NUM_OF_TOKENS_IN_ASSET_POOL = 200;
export const WEIGHT_MULTIPLIER = 10000;
export const EXPO_DIVIDER = 100;
export const BPS_DIVIDER = 10000;

export const ADDITIONAL_FEE = 15000;
export const ADDITIONAL_UNITS = 1000000;

export class BasketError extends Error {
    public txId: TransactionSignature;
    constructor (message: string, txId: TransactionSignature = "") {
        super(message);
        this.txId = txId;
    }
}

export type BasketFilter = "manager" | "host";

export type FilterOption = {
    filterType: BasketFilter,
    filterPubkey: PublicKey,
}

export enum FilterType {
    Fixed,
    MarketCap,
    Volume,
    Performance,
}

export enum WeightType {
    Fixed,
    MarketCap,
    Volume,
    Performance,
}

export enum FilterTime {
    Day,
    Week,
    Month,
    Quarter,
    HalfYear,
    Year,
}

export enum WeightTime {
    Day,
    Week,
    Month,
    Quarter,
    HalfYear,
    Year,
}

export enum SortBy {
    DescendingOrder,
    AscendingOrder,
}

export type Rule = {
    filterBy: FilterType,
    filterDays: FilterTime,
    sortBy: SortBy,
    totalWeight: number,
    fixedAsset: number,
    numAssets: number,
    weightBy: WeightType,
    weightDays: WeightTime,
    weightExpo: number,
    excludeAssets: number[],
    ruleAssets?: number[],
}

export type CreateBasketParams = {
    name: string,
    symbol: string,
    uri: string,
    hostPlatform: PublicKey,
    hostPlatformFee: number,
    manager: PublicKey,
    managerFee: number,
    activelyManaged: number,
    assetPool: number[],
    refilterInterval: number,
    reweightInterval: number,
    rebalanceInterval: number,
    rebalanceThreshold: number,
    rebalanceSlippage: number,
    lpOffsetThreshold: number,
    disableRebalance: boolean,
    disableLp: boolean,
    rules: Rule[],
}


export type SimpleCreateParams = {
    name: string,
    symbol: string,
    uri: string,
    hostPlatform: PublicKey,
    hostPlatformFee: number,
    manager: PublicKey,
    managerFee: number,
    activelyManaged: number,
    rebalanceInterval: number,
    rebalanceThreshold: number,
    rebalanceSlippage: number,
    lpOffsetThreshold: number,
    disableRebalance: boolean,
    disableLp: boolean,
    composition: {token: PublicKey, weight: number}[],
    feeDelegate?: PublicKey
}


export type SimpleEditParams = {
    managerFee: number,
    rebalanceInterval: number,
    rebalanceThreshold: number,
    rebalanceSlippage: number,
    lpOffsetThreshold: number,
    disableRebalance: boolean,
    disableLp: boolean,
    composition: {token: PublicKey, weight: number}[],
    feeDelegate?: PublicKey
}

export type BasketStateChainData = {
    version: BN,
    manager: PublicKey,
    fundToken: PublicKey,
    managerFee: BN,
    supplyOutstanding: BN,
    activelyManaged: BN,
    activeBuyStates: BN,

    sellState: BN,
    rebalanceSellState: BN,

    hostPubkey: PublicKey,
    hostFee: BN,

    numOfTokens: BN,     
    currentCompToken: BN[],
    currentCompAmount: BN[],
    lastRebalanceTime: BN[],
    targetWeight: BN[],
    weightSum: BN,

    currentWeight: BN[],
    fundWorth: BN,
    lastUpdateTime: BN,

    refilterInterval: BN,
    reweightInterval: BN,
    rebalanceInterval: BN,
    rebalanceThreshold: BN,
    rebalanceSlippage: BN,
    lpOffsetThreshold: BN,
    lastRefilterTime: BN,
    lastReweightTime: BN,

    rulesReady: BN,
    assetPool: BN[],
    numOfRules: BN,      
    rules: {
        filterBy: BN,
        filterDays: BN,
        sortBy: BN,
        totalWeight: BN,
        fixedAsset: BN,
        numAssets: BN,
        weightBy: BN,  
        weightDays: BN,
        weightExpo: BN,
        excludeNum: BN,
        excludeAssets: BN[],
        ruleAssets: BN[],
    }[],

    numRuleTokens: BN,   
    ruleTokens: BN[],
    ruleTokenWeights: BN[],

    messageDigestFive: number[],

    disableRebalance: BN,
    disableLp: BN,

    allowMultiAssetContribution: number,
    symbolLength: number,
    symbol: number[],
    nameLength: number,
    name: number[],
    uriLength: number,
    uri: number[],

    feeDelegate: PublicKey,
    extraBytes: number[],
}

export type BuyStateChainData = {
    fund: PublicKey,
    buyer: PublicKey,
    fundManager: PublicKey,
    hostPlatform: PublicKey,
    buyerFundTokenAccount: PublicKey,
    usdcContributed: BN,
    usdcLeft: BN,
    token: BN[],
    amountToSpend: BN[],
    amountBought: BN[],
    creationTimestamp: BN,
    contributedValue: BN
}

export type TokenSettings = {
    id: number,
    symbol: string,
    name: string,
    tokenMint: string,
    decimals: number,
    coingeckoId: string,
    pdaTokenAccount: string,
    oracleType: string,
    oracleAccount: string,
    oracleIndex: number,
    oracleConfidencePct: number,
    fixedConfidenceBps: number,
    tokenSwapFeeBeforeTwBps: number,
    tokenSwapFeeAfterTwBps: number,
    isLive: boolean,
    lpOn: boolean,
    useCurveData: boolean,
    additionalData: number[],
}

export type JupSwapData = {
    type: String,
    programId: PublicKey,
    accounts: {
        pubkey: PublicKey;
        isSigner: boolean;
        isWritable: boolean;
    }[],
    firstIxEnd: number,
    firstIxAccounts: number,
    dataLength: number,
    data: Buffer,
    fromTokenId: number,
    midTokenPda: string,
    toTokenId: number,
    fromAmount: number,
    toAmount: number,
    slippageBps: number,
    feeBps: number,
    lookupTableAccounts: AddressLookupTableAccount[],
}

export enum Side {
    To,
    From,
}

export type RebalanceInfo = {
    tokenId: number,
    tokenAccountFrom: string,
    mintFrom: string,
    oracleFrom: string,
    tokenAccountTo: string,
    mintTo: string,
    oracleTo: string,
    amountFrom: number,
    decimals: number,
    volume: number,
    side: Side
}

export type TransactionToSend = { 
    payerKey: PublicKey, 
    instructions: TransactionInstruction[], 
    lookupTables: AddressLookupTableAccount[] 
};
