// @flow

import React, { PureComponent, Fragment, type Element } from 'react';
import { InfiniteLoader, AutoSizer, List } from 'react-virtualized';
import styled from 'styled-components';
import dateFns from 'date-fns';

import { TransactionItemComponent } from '../components/transaction-item';
import { TextComponent } from '../components/text';
import { EmptyTransactionsComponent } from '../components/empty-transactions';

import type { MapDispatchToProps, MapStateToProps } from '../containers/transactions';

type Props = MapDispatchToProps & MapStateToProps;

const PAGE_SIZE = 15;
const ROW_HEIGHT = 60;
const ROW_HEIGHT_WITH_HEADER = 88;

const Day = styled(TextComponent)`
  text-transform: uppercase;
  color: ${props => props.theme.colors.transactionsDate};
  font-size: ${props => `${props.theme.fontSize.regular * 0.9}em`};
  font-weight: ${props => String(props.theme.fontWeight.bold)};
  margin-top: 10px;
  margin-bottom: 5px;
`;

const RoundedTransactionWrapper = styled.div`
  overflow: hidden;

  ${props => (props.roundPosition === 'top'
    ? `
      border-top-left-radius: ${props.theme.boxBorderRadius};
      border-top-right-radius: ${props.theme.boxBorderRadius};
    `
    : `
      border-bottom-left-radius: ${props.theme.boxBorderRadius};
      border-bottom-right-radius: ${props.theme.boxBorderRadius};
    `)}
`;

const ListWrapper = styled.div`
  margin-top: 10px;
`;

export class TransactionsView extends PureComponent<Props> {
  componentDidMount() {
    const { getTransactions, resetTransactionsList } = this.props;

    resetTransactionsList();
    getTransactions({
      count: PAGE_SIZE,
      offset: 0,
      shieldedTransactionsCount: 0,
    });
  }

  isRowLoaded = ({ index }: { index: number }) => {
    const { hasNextPage, transactions } = this.props;
    const transactionsSize = transactions.length;

    return !hasNextPage || index < transactionsSize;
  };

  renderTransactionWrapper = ({
    index,
    transactionDate,
    previousTransactionDate,
    nextTransactionDate,
    component,
  }: {|
    index: number,
    transactionDate: Date,
    previousTransactionDate: ?Date,
    nextTransactionDate: ?Date,
    component: Element<*>,
  |}) => {
    if (
      index === 0
      || (previousTransactionDate && !dateFns.isSameDay(transactionDate, previousTransactionDate))
    ) {
      return <RoundedTransactionWrapper roundPosition='top'>{component}</RoundedTransactionWrapper>;
    }

    if (
      nextTransactionDate
      && (nextTransactionDate && !dateFns.isSameDay(transactionDate, nextTransactionDate))
    ) {
      return (
        <RoundedTransactionWrapper roundPosition='bottom'>{component}</RoundedTransactionWrapper>
      );
    }

    return component;
  };

  renderTransactions = ({ index }: { index: number }) => {
    const { transactions, zecPrice } = this.props;

    const transaction = transactions[index];
    const previousTransaction = transactions[index - 1];
    const nextTransaction = transactions[index + 1];

    const transactionItem = this.renderTransactionWrapper({
      transactionDate: new Date(transaction.date),
      previousTransactionDate: previousTransaction ? new Date(previousTransaction.date) : null,
      nextTransactionDate: nextTransaction ? new Date(nextTransaction.date) : null,
      component: (
        <TransactionItemComponent
          confirmed={transaction.confirmed}
          confirmations={transaction.confirmations}
          address={transaction.address}
          amount={transaction.amount}
          date={transaction.date}
          transactionId={transaction.transactionId}
          type={transaction.type}
          zecPrice={zecPrice}
        />
      ),
      index,
    });
    if (
      index === 0
      || (previousTransaction
        && !dateFns.isSameDay(new Date(previousTransaction.date), new Date(transaction.date)))
    ) {
      return (
        <Fragment>
          <Day value={dateFns.format(new Date(transaction.date), 'MMM DD, YYYY')} />
          {transactionItem}
        </Fragment>
      );
    }

    return transactionItem;
  };

  renderRow = ({ index, key, style }: { index: number, key: string, style: Object }) => (
    <div key={key} style={style}>
      {this.isRowLoaded({ index }) ? this.renderTransactions({ index }) : 'Loading...'}
    </div>
  );

  getRowHeight = ({ index }: { index: number }) => {
    const { transactions } = this.props;

    const transaction = transactions[index];

    if (
      index === 0
      || !dateFns.isSameDay(new Date(transactions[index - 1].date), new Date(transaction.date))
    ) {
      return ROW_HEIGHT_WITH_HEADER;
    }

    return ROW_HEIGHT;
  };

  loadNextPage = () => {
    const { transactions, getTransactions } = this.props;

    const shieldedTransactionsCount = transactions.filter(
      transaction => transaction.address === '(Shielded)',
    ).length;

    getTransactions({ count: PAGE_SIZE, offset: transactions.length, shieldedTransactionsCount });
  };

  loadMoreRows = async () => {
    const { isLoading } = this.props;

    return isLoading ? Promise.resolve([]) : this.loadNextPage();
  };

  render() {
    const { error, transactions, hasNextPage } = this.props;

    const transactionsSize = transactions.length;
    const isRowLoaded = ({ index }) => !hasNextPage || index < transactionsSize;
    const rowCount = transactionsSize ? transactionsSize + 1 : transactionsSize;

    if (error) {
      return <TextComponent value={error} />;
    }

    return (
      <InfiniteLoader
        isRowLoaded={isRowLoaded}
        loadMoreRows={this.loadMoreRows}
        rowCount={rowCount}
      >
        {({ onRowsRendered, registerChild }) => (
          <AutoSizer>
            {({ width, height }) => (
              <ListWrapper>
                <List
                  noRowsRenderer={EmptyTransactionsComponent}
                  ref={registerChild}
                  onRowsRendered={onRowsRendered}
                  rowRenderer={this.renderRow}
                  rowHeight={this.getRowHeight}
                  rowCount={transactionsSize}
                  width={width}
                  height={height - 20}
                />
              </ListWrapper>
            )}
          </AutoSizer>
        )}
      </InfiniteLoader>
    );
  }
}
