import { PageRequest } from '@ritbit/v4-proto/src/codegen/cosmos/base/query/v1beta1/pagination';
import { AxiosProxyConfig } from 'axios';
import Long from 'long';

import { BroadcastOptions, DenomConfig } from './types';

export * from '../lib/constants';

/**
 * Disclaimer: Note that as of the date hereof, the testnet and RITBIT Chain deployment are the only known deployments of the 
 * RITBIT Chain software, and other deployment options may be added.
 */

// Chain ID
export const DEV_CHAIN_ID = 'ritbit-local';
export const STAGING_CHAIN_ID = 'ritbit-testnet';
export const TESTNET_CHAIN_ID = 'ritbit-testnet';
export const LOCAL_CHAIN_ID = 'ritbit-local';
export const MAINNET_CHAIN_ID = 'ritbit-mainnet';

// ------------ API URLs ------------
export enum IndexerApiHost {
  TESTNET = 'https://indexer.testnet.tyranodex.xyz/',
  STAGING = 'https://indexer.testnet.tyranodex.xyz/',
  LOCAL = 'http://local.ritbit.ru:3002',
  MAINNET = 'https://indexer.tyranodex.xyz',
}

export enum IndexerWSHost {
  TESTNET = 'wss://indexer.testnet.tyranodex.xyz/v4/ws',
  STAGING = 'wss://indexer.testnet.tyranodex.xyz/v4/ws',
  LOCAL = 'ws://local.ritbit.ru:3003',
  MAINNET = 'wss://indexer.tyranodex.xyz/v4/ws',
}

export enum FaucetApiHost {
  TESTNET = 'https://faucet.testnet.tyranodex.xyz',
}

export enum ValidatorApiHost {
  TESTNET = 'https://rpc.testnet.tyranodex.xyz',
  STAGING = 'https://rpc.testnet.tyranodex.xyz',
  LOCAL = 'http://local.ritbit.ru:26657',
  MAINNET = 'https://rpc.tyranodex.xyz',
}

// ------------ Network IDs ------------

export enum NetworkId {
  TESTNET = 'ritbit-testnet',
  MAINNET = 'ritbit-mainnet',
}
export const NETWORK_ID_TESTNET: string = 'ritbit-testnet';
export const NETWORK_ID_MAINNET: string = 'ritbit-mainnet';

// ------------ Gas Denoms ------------
export enum SelectedGasDenom {
  NATIVE = 'NATIVE',
  USDC = 'USDC',
}

// ------------ MsgType URLs ------------
// Default CosmosSDK
// x/bank
export const TYPE_URL_MSG_SEND = '/cosmos.bank.v1beta1.MsgSend';

// x/gov
export const TYPE_URL_MSG_SUBMIT_PROPOSAL = '/cosmos.gov.v1.MsgSubmitProposal';

// x/clob
export const TYPE_URL_MSG_PLACE_ORDER = '/ritbit.clob.MsgPlaceOrder';
export const TYPE_URL_MSG_CANCEL_ORDER = '/ritbit.clob.MsgCancelOrder';
export const TYPE_URL_BATCH_CANCEL = '/ritbit.clob.MsgBatchCancel';
export const TYPE_URL_MSG_CREATE_CLOB_PAIR = '/ritbit.clob.MsgCreateClobPair';
export const TYPE_URL_MSG_UPDATE_CLOB_PAIR = '/ritbit.clob.MsgUpdateClobPair';

// x/delaymsg
export const TYPE_URL_MSG_DELAY_MESSAGE = '/ritbit.delaymsg.MsgDelayMessage';

// x/listing
export const TYPE_URL_MSG_CREATE_MARKET_PERMISSIONLESS =
  '/ritbit.listing.MsgCreateMarketPermissionless';

// x/perpetuals
export const TYPE_URL_MSG_CREATE_PERPETUAL = '/ritbit.perpetuals.MsgCreatePerpetual';

// x/prices
export const TYPE_URL_MSG_CREATE_ORACLE_MARKET = '/ritbit.prices.MsgCreateOracleMarket';

// x/sending
export const TYPE_URL_MSG_CREATE_TRANSFER = '/ritbit.sending.MsgCreateTransfer';
export const TYPE_URL_MSG_WITHDRAW_FROM_SUBACCOUNT =
  '/ritbit.sending.MsgWithdrawFromSubaccount';
export const TYPE_URL_MSG_DEPOSIT_TO_SUBACCOUNT = '/ritbit.sending.MsgDepositToSubaccount';

// x/affiliates
export const TYPE_URL_MSG_REGISTER_AFFILIATE = '/ritbit.affiliates.MsgRegisterAffiliate';

// x/vault
export const TYPE_URL_MSG_DEPOSIT_TO_MEGAVAULT = '/ritbit.vault.MsgDepositToMegavault';
export const TYPE_URL_MSG_WITHDRAW_FROM_MEGAVAULT = '/ritbit.vault.MsgWithdrawFromMegavault';

// x/staking
export const TYPE_URL_MSG_DELEGATE = '/cosmos.staking.v1beta1.MsgDelegate';
export const TYPE_URL_MSG_UNDELEGATE = '/cosmos.staking.v1beta1.MsgUndelegate';

// x/distribution
export const TYPE_URL_MSG_WITHDRAW_DELEGATOR_REWARD =
  '/cosmos.distribution.v1beta1.MsgWithdrawDelegatorReward';

// x/bridge
export const TYPE_URL_MSG_WITHDRAWAL = '/ritbit.bridge.MsgWithdrawal';

// x/accountplus
export const TYPE_URL_MSG_ADD_AUTHENTICATOR = '/ritbit.accountplus.MsgAddAuthenticator';
export const TYPE_URL_MSG_REMOVE_AUTHENTICATOR = '/ritbit.accountplus.MsgRemoveAuthenticator';

// ------------ Chain Constants ------------
// The following are same across different networks / deployments.
export const GOV_MODULE_ADDRESS = 'rit10d07y265gmmuvt4z0w9aw880jnsr700j086rvs';
export const DELAYMSG_MODULE_ADDRESS = 'rit1mkkvp26dngu6n8rmalaxyp3gwkjuzztqg7pc3h';
export const MEGAVAULT_MODULE_ADDRESS = 'rit18tkxrnrkqc2t0lr3zxr5g6a4hdvqksyl6u4m0h';

// ------------ Market Statistic Day Types ------------
export enum MarketStatisticDay {
  ONE = '1',
  SEVEN = '7',
  THIRTY = '30',
}

// ------------ Order Types ------------
// This should match OrderType in Abacus
export enum OrderType {
  LIMIT = 'LIMIT',
  MARKET = 'MARKET',
  STOP_LIMIT = 'STOP_LIMIT',
  TAKE_PROFIT_LIMIT = 'TAKE_PROFIT',
  STOP_MARKET = 'STOP_MARKET',
  TAKE_PROFIT_MARKET = 'TAKE_PROFIT_MARKET',
}

// ------------ Order Side ------------
// This should match OrderSide in Abacus
export enum OrderSide {
  BUY = 'BUY',
  SELL = 'SELL',
}

// ------------ Order TimeInForce ------------
// This should match OrderTimeInForce in Abacus
export enum OrderTimeInForce {
  GTT = 'GTT',
  IOC = 'IOC',
  FOK = 'FOK',
}

// ------------ Order Execution ------------
// This should match OrderExecution in Abacus
export enum OrderExecution {
  DEFAULT = 'DEFAULT',
  IOC = 'IOC',
  FOK = 'FOK',
  POST_ONLY = 'POST_ONLY',
}

// ------------ Order Status ------------
// This should match OrderStatus in Abacus
export enum OrderStatus {
  BEST_EFFORT_OPENED = 'BEST_EFFORT_OPENED',
  OPEN = 'OPEN',
  FILLED = 'FILLED',
  BEST_EFFORT_CANCELED = 'BEST_EFFORT_CANCELED',
  CANCELED = 'CANCELED',
}

export enum TickerType {
  PERPETUAL = 'PERPETUAL', // Only PERPETUAL is supported right now
}

export enum PositionStatus {
  OPEN = 'OPEN',
  CLOSED = 'CLOSED',
  LIQUIDATED = 'LIQUIDATED',
}

// ----------- Time Period for Sparklines -------------

export enum TimePeriod {
  ONE_DAY = 'ONE_DAY',
  SEVEN_DAYS = 'SEVEN_DAYS',
}

export enum PnlTickInterval {
  HOUR = 'hour',
  day = 'day',
}

// ----------- Authenticators -------------

export enum AuthenticatorType {
  ALL_OF = 'AllOf',
  ANY_OF = 'AnyOf',
  SIGNATURE_VERIFICATION = 'SignatureVerification',
  MESSAGE_FILTER = 'MessageFilter',
  CLOB_PAIR_ID_FILTER = 'ClobPairIdFilter',
  SUBACCOUNT_FILTER = 'SubaccountFilter',
}

export interface Authenticator {
  type: AuthenticatorType;
  config: string | Authenticator[];
}

export enum TradingRewardAggregationPeriod {
  DAILY = 'DAILY',
  WEEKLY = 'WEEKLY',
  MONTHLY = 'MONTHLY',
}

// ------------ API Defaults ------------
export const DEFAULT_API_TIMEOUT: number = 3_000;

export const MAX_MEMO_CHARACTERS: number = 256;

export const SHORT_BLOCK_WINDOW: number = 20;

export const SHORT_BLOCK_FORWARD: number = 15;

// Querying
export const PAGE_REQUEST: PageRequest = {
  key: new Uint8Array(),
  offset: Long.UZERO,
  limit: Long.MAX_UNSIGNED_VALUE,
  countTotal: true,
  reverse: false,
};

export class IndexerConfig {
  public restEndpoint: string;
  public websocketEndpoint: string;
  public proxy?: AxiosProxyConfig;

  constructor(restEndpoint: string, websocketEndpoint: string, proxy?: AxiosProxyConfig) {
    this.restEndpoint = restEndpoint;
    this.websocketEndpoint = websocketEndpoint;
    this.proxy = proxy;
  }
}

export class ValidatorConfig {
  public restEndpoint: string;
  public chainId: string;
  public denoms: DenomConfig;
  public broadcastOptions?: BroadcastOptions;
  public defaultClientMemo?: string;
  public useTimestampNonce?: boolean;
  public timestampNonceOffsetMs?: number;

  constructor(
    restEndpoint: string,
    chainId: string,
    denoms: DenomConfig,
    broadcastOptions?: BroadcastOptions,
    defaultClientMemo?: string,
    useTimestampNonce?: boolean,
    timestampNonceOffsetMs?: number,
  ) {
    this.restEndpoint = restEndpoint?.endsWith('/') ? restEndpoint.slice(0, -1) : restEndpoint;
    this.chainId = chainId;

    this.denoms = denoms;
    this.broadcastOptions = broadcastOptions;
    this.defaultClientMemo = defaultClientMemo;
    this.useTimestampNonce = useTimestampNonce;
    this.timestampNonceOffsetMs = timestampNonceOffsetMs;
  }
}

export class Network {
  constructor(
    public env: string,
    public indexerConfig: IndexerConfig,
    public validatorConfig: ValidatorConfig,
  ) {}

  static testnet(): Network {
    const indexerConfig = new IndexerConfig(IndexerApiHost.TESTNET, IndexerWSHost.TESTNET);
    const validatorConfig = new ValidatorConfig(
      ValidatorApiHost.TESTNET,
      TESTNET_CHAIN_ID,
      {
        CHAINTOKEN_DENOM: 'urit',
        USDC_DENOM: 'uusdc',
        USDC_GAS_DENOM: 'uusdc',
        USDC_DECIMALS: 6,
        CHAINTOKEN_DECIMALS: 18,
      },
      undefined,
      'Client Example',
    );
    return new Network('testnet', indexerConfig, validatorConfig);
  }

  static staging(): Network {
    const indexerConfig = new IndexerConfig(IndexerApiHost.STAGING, IndexerWSHost.STAGING);
    const validatorConfig = new ValidatorConfig(
      ValidatorApiHost.STAGING,
      STAGING_CHAIN_ID,
      {
        CHAINTOKEN_DENOM: 'urit',
        USDC_DENOM: 'uusdc',
        USDC_GAS_DENOM: 'uusdc',
        USDC_DECIMALS: 6,
        CHAINTOKEN_DECIMALS: 18,
      },
      undefined,
      'Client Example',
    );
    return new Network('staging', indexerConfig, validatorConfig);
  }

  static local(): Network {
    const indexerConfig = new IndexerConfig(IndexerApiHost.LOCAL, IndexerWSHost.LOCAL);
    const validatorConfig = new ValidatorConfig(
      ValidatorApiHost.LOCAL,
      LOCAL_CHAIN_ID,
      {
        CHAINTOKEN_DENOM: 'urit',
        USDC_DENOM: 'uusdc',
        USDC_GAS_DENOM: 'uusdc',
        USDC_DECIMALS: 6,
        CHAINTOKEN_DECIMALS: 18,
      },
      undefined,
      'Client Example',
    );
    return new Network('local', indexerConfig, validatorConfig);
  }

  static mainnet(): Network {
    const indexerConfig = new IndexerConfig(IndexerApiHost.MAINNET, IndexerWSHost.MAINNET);
    const validatorConfig = new ValidatorConfig(
      ValidatorApiHost.MAINNET,
      MAINNET_CHAIN_ID,
      {
        CHAINTOKEN_DENOM: 'urit',
        USDC_DENOM: 'uusdc',
        USDC_GAS_DENOM: 'uusdc',  
        USDC_DECIMALS: 6,
        CHAINTOKEN_DECIMALS: 18,
      },
      undefined,
      'Client Example',
    );
    return new Network('mainnet', indexerConfig, validatorConfig);
  }

  getString(): string {
    return this.env;
  }
}
