import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';
import { Observable, combineLatest, BehaviorSubject, of } from 'rxjs';
import { map, share, switchMap } from 'rxjs/operators';
import { SeoService } from 'src/app/services/seo.service';
import { StateService } from 'src/app/services/state.service';
import { WebsocketService } from 'src/app/services/websocket.service';
import { BisqApiService } from '../bisq-api.service';
import { Trade } from '../bisq.interfaces';

@Component({
  selector: 'app-main-bisq-dashboard',
  templateUrl: './bisq-main-dashboard.component.html',
  styleUrls: ['./bisq-main-dashboard.component.scss'],
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class BisqMainDashboardComponent implements OnInit {
  tickers$: Observable<any>;
  volumes$: Observable<any>;
  trades$: Observable<Trade[]>;
  sort$ = new BehaviorSubject<string>('trades');
  hlocData$: Observable<any>;
  usdPrice$: Observable<number>;
  isLoadingGraph = true;
  bisqMarketPrice = 0;

  allowCryptoCoins = ['usdc', 'l-btc', 'bsq'];

  constructor(
    private websocketService: WebsocketService,
    private bisqApiService: BisqApiService,
    public stateService: StateService,
    private seoService: SeoService,
  ) { }

  ngOnInit(): void {
    this.seoService.setTitle(`Markets`);
    this.websocketService.want(['blocks']);

    this.usdPrice$ = this.stateService.conversions$.asObservable().pipe(
      map((conversions) => conversions.USD)
    );

    this.volumes$ = this.bisqApiService.getAllVolumesDay$()
      .pipe(
        map((volumes) => {
          const data = volumes.map((volume) => {
            return {
              time: volume.period_start,
              value: volume.volume,
            };
          });

          const linesData = volumes.map((volume) => {
            return {
              time: volume.period_start,
              value: volume.num_trades,
            };
          });

          return {
            data: data,
            linesData: linesData,
          };
        })
      );

    const getMarkets = this.bisqApiService.getMarkets$().pipe(share());

    this.tickers$ = combineLatest([
      this.bisqApiService.getMarketsTicker$(),
      getMarkets,
      this.bisqApiService.getMarketVolumesByTime$('7d'),
    ])
    .pipe(
      map(([tickers, markets, volumes]) => {

        const newTickers = [];
        for (const t in tickers) {

          if (!this.stateService.env.OFFICIAL_BISQ_MARKETS) {
            const pair = t.split('_');
            if (pair[1] === 'btc' && this.allowCryptoCoins.indexOf(pair[0]) === -1) {
              continue;
            }
          }

          const mappedTicker: any = tickers[t];

          mappedTicker.pair_url = t;
          mappedTicker.pair = t.replace('_', '/').toUpperCase();
          mappedTicker.market = markets[t];
          mappedTicker.volume = volumes[t];
          mappedTicker.name = `${mappedTicker.market.rtype === 'crypto' ? mappedTicker.market.lname : mappedTicker.market.rname} (${mappedTicker.market.rtype === 'crypto' ? mappedTicker.market.lsymbol : mappedTicker.market.rsymbol}`;
          newTickers.push(mappedTicker);
        }
        return newTickers;
      }),
      switchMap((tickers) => combineLatest([this.sort$, of(tickers)])),
      map(([sort, tickers]) => {
        if (sort === 'trades') {
          tickers.sort((a, b) => (b.volume && b.volume.num_trades || 0) - (a.volume && a.volume.num_trades || 0));
        } else if (sort === 'volumes') {
          tickers.sort((a, b) => (b.volume && b.volume.volume || 0) - (a.volume && a.volume.volume || 0));
        } else if (sort === 'name') {
          tickers.sort((a, b) => a.name.localeCompare(b.name));
        }
        return tickers.slice(0, 10);
      })
    );

    this.trades$ = combineLatest([
      this.bisqApiService.getMarketTrades$('all'),
      getMarkets,
    ])
    .pipe(
      map(([trades, markets]) => {
        if (!this.stateService.env.OFFICIAL_BISQ_MARKETS) {
          trades = trades.filter((trade) => {
            const pair = trade.market.split('_');
            return !(pair[1] === 'btc' && this.allowCryptoCoins.indexOf(pair[0]) === -1);
          });
        }
        return trades.map((trade => {
          trade._market = markets[trade.market];
          return trade;
        })).slice(0, 10);
      })
    );

    this.hlocData$ = this.bisqApiService.getMarketsHloc$('btc_usd', 'day')
      .pipe(
      map((hlocData) => {
        this.isLoadingGraph = false;

        hlocData = hlocData.map((h) => {
          h.time = h.period_start;
          return h;
        });

        const hlocVolume = hlocData.map((h) => {
          return {
            time: h.time,
            value: h.volume_right,
            color: h.close > h.avg ? 'rgba(0, 41, 74, 0.7)' : 'rgba(0, 41, 74, 1)',
          };
        });

        // Add whitespace
        if (hlocData.length > 1) {
          const newHloc = [];
          newHloc.push(hlocData[0]);

          const period = 86400;
          let periods = 0;
          const startingDate = hlocData[0].period_start;
          let index = 1;
          while (true) {
            periods++;
            if (hlocData[index].period_start > startingDate + period * periods) {
              newHloc.push({
                time: startingDate + period * periods,
              });
            } else {
              newHloc.push(hlocData[index]);
              index++;
              if (!hlocData[index]) {
                break;
              }
            }
          }
          hlocData = newHloc;
        }

        this.bisqMarketPrice = hlocData[hlocData.length - 1].close;

        return {
          hloc: hlocData,
          volume: hlocVolume,
        };
      }),
    );
  }

  trackByFn(index: number) {
    return index;
  }

  sort(by: string) {
    this.sort$.next(by);
  }

}
