import { Chain, Timeframe } from '../../../../../enums';
import {
  ContractPointer,
  NFTCollectionSale,
  NFTCollectionSales,
  Value,
} from '../../../../../types';
import { RestfulProvider } from '../../RestfulProvider';
import { NftCollectionDataProvider } from '../NftCollectionDataProvider';
import { numberToValue } from '../../../../../utils/numberToValue';
import { numberToAmount } from '../../../../../utils/numberToAmount';

// Docs: https://docs.diadata.org/documentation/api-1/nft-data-api-endpoints

export class DiaNonFungible extends RestfulProvider
  implements NftCollectionDataProvider {
  constructor(_config: any) {
    const apiHost = 'https://api.diadata.org/v1/';
    super(_config, apiHost);
  }

  // https://api.diadata.org/v1/NFTFloor/:blockchain/:address
  async getFloor(_contract: ContractPointer): Promise<Value> {
    const host = this.getApiHost();
    const chain = this.getBlockchain(_contract.chain);
    const uri = `${host}NFTFloor/${chain}/${_contract.address}`;
    const json: any = await this.gotJson(uri);

    const currencyInfo = this.getCurrencyInfoFromChain(_contract.chain);
    return numberToValue(Number(json.Floor_Price), currencyInfo);
  }

  async getFloorChart(
    _contract: ContractPointer,
    _timeframe?: Timeframe
  ): Promise<any> {
    throw new Error('Method not implemented.');
  }

  // https://api.diadata.org/v1/NFTTradesCollection/:blockchain/:address
  async getHistoricSales(
    _contract: ContractPointer,
    _startTime?: number,
    _endTime?: number
  ): Promise<NFTCollectionSales> {
    const host = this.getApiHost();
    const chain = this.getBlockchain(_contract.chain);
    const uri = `${host}NFTTradesCollection/${chain}/${_contract.address}`;
    const options = {
      searchParams: {
        starttime: _startTime,
        endtime: _endTime,
      },
    };

    const currencyInfo = this.getCurrencyInfoFromChain(_contract.chain);
    const json: any = await this.gotJson(uri, options);

    const sales: NFTCollectionSale[] = [];
    for (const trade of json) {
      const sale: NFTCollectionSale = {
        timestamp: trade.Timestamp,
        blockNumber: Number(trade.BlockNumber),
        tokenId: String(trade.NFTid),
        price: numberToAmount(Number(trade.Price), currencyInfo),
        buyer: trade.ToAddress,
        seller: trade.FromAddress,
        transactionHash: trade.TxHash,
        exchange: trade.Exchange,
        bundleSale: Boolean(trade.BundleSale),
      };
      sales.push(sale);
    }

    return {
      contract: _contract,
      currencyInfo,
      numSales: sales.length,
      sales,
    };
  }

  async getMarketCap(_contract: ContractPointer): Promise<Value> {
    throw new Error('Method not implemented.');
  }

  async getMetadata(_contract: ContractPointer): Promise<any> {
    throw new Error('Method not implemented.');
  }

  getBlockchain(_chain?: Chain): string {
    switch (_chain) {
      case undefined:
      case Chain.ETHEREUM:
        return 'Ethereum';
      default:
        throw new Error(`${_chain} is not supported by ${this.getName()}.`);
    }
  }

  getName(): string {
    return 'DIA';
  }
}
