import React, { memo, useMemo, useCallback } from 'react';
import { useSelector } from 'react-redux';

import {
  format as formatDate,
  parseISO,
  isValid as isDateValid,
} from 'date-fns';

import {
  getAccountsById,
  getCategoriesById,
} from 'loot-core/src/client/reducers/queries';
import { integerToCurrency } from 'loot-core/src/shared/util';

import { useSelectedItems, useSelectedDispatch } from '../../hooks/useSelected';
import ArrowsSynchronize from '../../icons/v2/ArrowsSynchronize';
import { styles } from '../../style';
import { Table, Row, Field, Cell, SelectCell } from '../table';
import DisplayId from '../util/DisplayId';

function serializeTransaction(transaction, dateFormat) {
  let { date } = transaction;

  if (!isDateValid(parseISO(date))) {
    date = null;
  }

  return {
    ...transaction,
    date: date ? formatDate(parseISO(date), dateFormat) : null,
  };
}

const TransactionRow = memo(function TransactionRow({
  transaction,
  fields,
  payees,
  categories,
  accounts,
  selected,
}) {
  // TODO: Convert these to use fetched queries
  let c = getCategoriesById(categories)[transaction.category];
  let a = getAccountsById(accounts)[transaction.account];

  let dispatchSelected = useSelectedDispatch();

  return (
    <Row>
      <SelectCell
        exposed={true}
        focused={false}
        onSelect={e => {
          dispatchSelected({ type: 'select', id: transaction.id, event: e });
        }}
        selected={selected}
      />
      {fields.map((field, i) => {
        switch (field) {
          case 'date':
            return (
              <Field key={i} width={100}>
                {transaction.date}
              </Field>
            );
          case 'imported_payee':
            return (
              <Field key={i} width="flex">
                {transaction.imported_payee}
              </Field>
            );
          case 'payee':
            return (
              <Cell
                key={i}
                width="flex"
                exposed={true}
                style={{
                  flexDirection: 'row',
                  alignItems: 'center',
                  justifyContent: 'flex-start',
                }}
              >
                {() => (
                  <>
                    {transaction.schedule && (
                      <ArrowsSynchronize
                        style={{
                          width: 13,
                          height: 13,
                          margin: '0 5px',
                        }}
                      />
                    )}
                    <DisplayId type="payees" id={transaction.payee} />
                  </>
                )}
              </Cell>
            );
          case 'category':
            return (
              <Field key={i} width="flex" title={c && c.name}>
                {c ? c.name : ''}
              </Field>
            );
          case 'account':
            return (
              <Field key={i} width="flex" title={a.name}>
                {a.name}
              </Field>
            );
          case 'notes':
            return (
              <Field key={i} width="flex" title={transaction.notes}>
                {transaction.notes}
              </Field>
            );
          case 'amount':
            return (
              <Field
                key={i}
                width={75}
                style={[{ textAlign: 'right' }, styles.tnum]}
              >
                {integerToCurrency(transaction.amount)}
              </Field>
            );
          default:
            return null;
        }
      })}
    </Row>
  );
});

export default function SimpleTransactionsTable({
  transactions,
  schedules,
  renderEmpty,
  fields = ['date', 'payee', 'amount'],
  style,
}) {
  let { payees, categories, accounts, dateFormat } = useSelector(state => {
    return {
      payees: state.queries.payees,
      accounts: state.queries.accounts,
      categories: state.queries.categories.grouped,
      dateFormat: state.prefs.local.dateFormat || 'MM/dd/yyyy',
    };
  });
  let selectedItems = useSelectedItems();
  let dispatchSelected = useSelectedDispatch();
  let memoFields = useMemo(() => fields, [JSON.stringify(fields)]);

  let serializedTransactions = useMemo(() => {
    return transactions.map(trans => serializeTransaction(trans, dateFormat));
  }, [transactions]);

  let renderItem = useCallback(
    ({ item }) => {
      return (
        <TransactionRow
          transaction={item}
          payees={payees}
          categories={categories}
          accounts={accounts}
          fields={memoFields}
          selected={selectedItems && selectedItems.has(item.id)}
        />
      );
    },
    [payees, categories, memoFields, selectedItems],
  );

  return (
    <Table
      style={style}
      items={serializedTransactions}
      renderEmpty={renderEmpty}
      headers={
        <>
          <SelectCell
            exposed={true}
            focused={false}
            selected={selectedItems.size > 0}
            width={20}
            onSelect={e => dispatchSelected({ type: 'select-all', event: e })}
          />
          {fields.map((field, i) => {
            switch (field) {
              case 'date':
                return (
                  <Field key={i} width={100}>
                    Date
                  </Field>
                );
              case 'imported_payee':
                return (
                  <Field key={i} width="flex">
                    Imported payee
                  </Field>
                );
              case 'payee':
                return (
                  <Field key={i} width="flex">
                    Payee
                  </Field>
                );
              case 'category':
                return (
                  <Field key={i} width="flex">
                    Category
                  </Field>
                );
              case 'account':
                return (
                  <Field key={i} width="flex">
                    Account
                  </Field>
                );
              case 'notes':
                return (
                  <Field key={i} width="flex">
                    Notes
                  </Field>
                );
              case 'amount':
                return (
                  <Field key={i} width={75} style={{ textAlign: 'right' }}>
                    Amount
                  </Field>
                );
              default:
                return null;
            }
          })}
        </>
      }
      renderItem={renderItem}
    />
  );
}