import { useQuery, gql } from '@apollo/client'
import { toUnit, formatCryptoAddress } from '@lamassu/coins/lightUtils'
import BigNumber from 'bignumber.js'
import * as R from 'ramda'
import React, { useEffect, useState } from 'react'
import { useLocation } from 'wouter'
import LogsDowloaderPopover from '../../components/LogsDownloaderPopper'
import SearchBox from '../../components/SearchBox'
import SearchFilter from '../../components/SearchFilter'
import { HelpTooltip } from '../../components/Tooltip'
import DataTable from '../../components/tables/DataTable'
import TxInIcon from '../../styling/icons/direction/cash-in.svg?react'
import TxOutIcon from '../../styling/icons/direction/cash-out.svg?react'
import CustomerLinkIcon from '../../styling/icons/month arrows/right.svg?react'
import CustomerLinkWhiteIcon from '../../styling/icons/month arrows/right_white.svg?react'

import { SupportLinkButton } from '../../components/buttons'
import { errorColor } from '../../styling/variables'
import * as Customer from '../../utils/customer'
import { formatDate } from '../../utils/timezones'

import DetailsRow from './DetailsCard'
import { getStatus } from './helper'
import TitleSection from '../../components/layout/TitleSection.jsx'

const NUM_LOG_RESULTS = 1000

const GET_DATA = gql`
  query getData {
    config
  }
`

const GET_TRANSACTIONS_CSV = gql`
  query transactions(
    $simplified: Boolean
    $limit: Int
    $from: DateTimeISO
    $until: DateTimeISO
    $timezone: String
    $excludeTestingCustomers: Boolean
  ) {
    transactionsCsv(
      simplified: $simplified
      limit: $limit
      from: $from
      until: $until
      timezone: $timezone
      excludeTestingCustomers: $excludeTestingCustomers
    )
  }
`

const GET_TRANSACTION_FILTERS = gql`
  query filters {
    transactionFilters {
      type
      value
      label
    }
  }
`

const GET_TRANSACTIONS = gql`
  query transactions(
    $limit: Int
    $from: DateTimeISO
    $until: DateTimeISO
    $txClass: String
    $deviceId: String
    $customerName: String
    $fiatCode: String
    $cryptoCode: String
    $toAddress: String
    $status: String
    $swept: Boolean
  ) {
    transactions(
      limit: $limit
      from: $from
      until: $until
      txClass: $txClass
      deviceId: $deviceId
      customerName: $customerName
      fiatCode: $fiatCode
      cryptoCode: $cryptoCode
      toAddress: $toAddress
      status: $status
      swept: $swept
    ) {
      id
      txClass
      txHash
      toAddress
      commissionPercentage
      expired
      machineName
      operatorCompleted
      sendConfirmed
      dispense
      hasError: error
      errorCode
      deviceId
      fiat
      fee
      fixedFee
      fiatCode
      cryptoAtoms
      cryptoCode
      toAddress
      created
      customerName
      customerIdCardData
      customerIdCardPhotoPath
      customerFrontCameraPath
      txCustomerPhotoPath
      customerPhone
      customerEmail
      discount
      customerId
      isAnonymous
      batched
      batchTime
      rawTickerPrice
      batchError
      walletScore
      profit
      swept
    }
  }
`

const getFiltersObj = filters =>
  R.reduce((s, f) => ({ ...s, [f.type]: f.value }), {}, filters)

const Transactions = () => {
  const [, navigate] = useLocation()

  const [filters, setFilters] = useState([])
  const { data: filtersResponse, loading: filtersLoading } = useQuery(
    GET_TRANSACTION_FILTERS,
  )
  const [variables, setVariables] = useState({ limit: NUM_LOG_RESULTS })
  const {
    data: txData,
    loading: transactionsLoading,
    refetch,
    startPolling,
    stopPolling,
  } = useQuery(GET_TRANSACTIONS, { variables })

  useEffect(() => {
    startPolling(10000)
    return stopPolling
  })

  const txList = txData?.transactions ?? []

  const { data: configResponse, configLoading } = useQuery(GET_DATA)
  const timezone = R.path(['config', 'locale_timezone'], configResponse)

  const redirect = customerId => {
    return navigate(`/compliance/customer/${customerId}`)
  }

  const elements = [
    {
      header: '',
      width: 32,
      size: 'sm',
      view: it => (it.txClass === 'cashOut' ? <TxOutIcon /> : <TxInIcon />),
    },
    {
      header: 'Machine',
      name: 'machineName',
      width: 160,
      size: 'sm',
      view: R.path(['machineName']),
    },
    {
      header: 'Customer',
      width: 202,
      size: 'sm',
      view: it => (
        <div className="flex items-center justify-between mr-4">
          <div className="overflow-hidden whitespace-nowrap text-ellipsis">
            {Customer.displayName(it)}
          </div>
          {!it.isAnonymous && (
            <div
              data-cy="customer-link"
              onClick={() => redirect(it.customerId)}>
              {it.hasError || it.batchError ? (
                <CustomerLinkWhiteIcon />
              ) : (
                <CustomerLinkIcon />
              )}
            </div>
          )}
        </div>
      ),
    },
    {
      header: 'Cash',
      width: 144,
      textAlign: 'right',
      size: 'sm',
      view: it => `${Number.parseFloat(it.fiat)} ${it.fiatCode}`,
    },
    {
      header: 'Crypto',
      width: 150,
      textAlign: 'right',
      size: 'sm',
      view: it =>
        `${toUnit(new BigNumber(it.cryptoAtoms), it.cryptoCode)} ${
          it.cryptoCode
        }`,
    },
    {
      header: 'Address',
      view: it => formatCryptoAddress(it.cryptoCode, it.toAddress),
      className: 'overflow-hidden whitespace-nowrap text-ellipsis',
      size: 'sm',
      width: 140,
    },
    {
      header: 'Date',
      view: it =>
        timezone && formatDate(it.created, timezone, 'yyyy-MM-dd HH:mm'),
      textAlign: 'right',
      size: 'sm',
      width: 195,
    },
    {
      header: 'Status',
      view: it => {
        if (getStatus(it) === 'Pending')
          return (
            <div className="flex items-center">
              {'Pending'}
              <HelpTooltip width={285}>
                <SupportLinkButton
                  link="https://support.lamassu.is/hc/en-us/articles/115001210452-Cancelling-cash-out-transactions"
                  label="Cancelling cash-out transactions"
                  bottomSpace="0"
                />
              </HelpTooltip>
            </div>
          )
        else return getStatus(it)
      },
      textAlign: 'left',
      size: 'sm',
      width: 80,
    },
  ]

  const onFilterChange = filters => {
    const filtersObject = getFiltersObj(filters)

    setFilters(filters)

    setVariables({
      limit: NUM_LOG_RESULTS,
      txClass: filtersObject.type,
      deviceId: filtersObject.machine,
      customerName: filtersObject.customer,
      fiatCode: filtersObject.fiat,
      cryptoCode: filtersObject.crypto,
      toAddress: filtersObject.address,
      status: filtersObject.status,
      swept: filtersObject.swept && filtersObject.swept === 'Swept',
    })

    refetch && refetch()
  }

  const onFilterDelete = filter => {
    const newFilters = R.filter(
      f => !R.whereEq(R.pick(['type', 'value'], f), filter),
    )(filters)

    setFilters(newFilters)

    const filtersObject = getFiltersObj(newFilters)

    setVariables({
      limit: NUM_LOG_RESULTS,
      txClass: filtersObject.type,
      deviceId: filtersObject.machine,
      customerName: filtersObject.customer,
      fiatCode: filtersObject.fiat,
      cryptoCode: filtersObject.crypto,
      toAddress: filtersObject.address,
      status: filtersObject.status,
      swept: filtersObject.swept && filtersObject.swept === 'Swept',
    })

    refetch && refetch()
  }

  const deleteAllFilters = () => {
    setFilters([])
    const filtersObject = getFiltersObj([])

    setVariables({
      limit: NUM_LOG_RESULTS,
      txClass: filtersObject.type,
      deviceId: filtersObject.machine,
      customerName: filtersObject.customer,
      fiatCode: filtersObject.fiat,
      cryptoCode: filtersObject.crypto,
      toAddress: filtersObject.address,
      status: filtersObject.status,
      swept: filtersObject.swept && filtersObject.swept === 'Swept',
    })

    refetch && refetch()
  }

  const filterOptions = R.path(['transactionFilters'])(filtersResponse)

  const loading = transactionsLoading || filtersLoading || configLoading

  const errorLabel = (
    <svg width={12} height={12}>
      <rect width={12} height={12} rx={3} fill={errorColor} />
    </svg>
  )

  return (
    <>
      <TitleSection
        title="Transactions"
        labels={[
          { icon: <TxInIcon />, label: 'Cash-in' },
          { icon: <TxOutIcon />, label: 'Cash-out' },
          { icon: errorLabel, label: 'Transaction error' },
        ]}
        appendix={
          <div className="flex ml-4 gap-4">
            <SearchBox
              loading={filtersLoading}
              filters={filters}
              options={filterOptions}
              inputPlaceholder={'Search transactions'}
              onChange={onFilterChange}
            />
            {txList && (
              <LogsDowloaderPopover
                title="Download logs"
                name="transactions"
                query={GET_TRANSACTIONS_CSV}
                getLogs={logs => R.path(['transactionsCsv'])(logs)}
                simplified
                timezone={timezone}
                args={{ timezone }}
              />
            )}
          </div>
        }
      />
      {filters.length > 0 && (
        <SearchFilter
          entries={txList.length}
          filters={filters}
          onFilterDelete={onFilterDelete}
          deleteAllFilters={deleteAllFilters}
        />
      )}
      <DataTable
        loading={loading}
        emptyText="No transactions so far"
        elements={elements}
        data={txList}
        Details={DetailsRow}
        expandable
        rowSize="sm"
        timezone={timezone}
      />
    </>
  )
}

export default Transactions
