import { useContext, useEffect, useState, type ReactElement, type ReactNode } from 'react';
import { useParams } from 'react-router-dom';
import { useQuery } from 'urql';
import { Mark } from '@mantine/core';
import {
  BusinessLedgerRecordsSummeryDocument,
  Currency,
  type BusinessLedgerRecordsSummeryQuery,
  type BusinessTransactionsFilter,
} from '../../gql/graphql.js';
import { useUrlQuery } from '../../hooks/use-url-query.js';
import { FiltersContext } from '../../providers/filters-context.js';
import { AccounterLoader, AccounterTable } from '../common/index.js';
import { BusinessExtendedInfo } from './business-extended-info.js';
import { BusinessLedgerRecordsFilters } from './business-ledger-filters.js';

type Props = {
  businessId?: string;
};

export const BusinessLedgerRecordsSingle = ({ businessId }: Props): ReactElement => {
  const { businessId: businessIdFromUrl } = useParams<{ businessId: string }>();
  const { get } = useUrlQuery();
  const { setFiltersContext } = useContext(FiltersContext);
  const id = businessId || businessIdFromUrl;
  const [filter, setFilter] = useState<BusinessTransactionsFilter>(
    get('ledgerRecordsFilters')
      ? {
          ...(JSON.parse(
            decodeURIComponent(get('ledgerRecordsFilters') as string),
          ) as BusinessTransactionsFilter),
          businessIDs: id ? [id] : [],
        }
      : {
          businessIDs: id ? [id] : [],
        },
  );
  const [{ data, fetching }] = useQuery({
    query: BusinessLedgerRecordsSummeryDocument,
    variables: {
      filters: filter,
    },
  });

  useEffect(() => {
    setFiltersContext(<BusinessLedgerRecordsFilters filter={filter} setFilter={setFilter} />);
  }, [data, filter, setFiltersContext, setFilter]);

  const businessTransactionsSum =
    data?.businessTransactionsSumFromLedgerRecords.__typename === 'CommonError'
      ? undefined
      : data?.businessTransactionsSumFromLedgerRecords.businessTransactionsSum;
  const businessLedgerRecordsSum = businessTransactionsSum
    ? [...businessTransactionsSum].sort((a, b) => a.business.name.localeCompare(b.business.name))
    : [];

  return fetching ? (
    <AccounterLoader />
  ) : (
    <AccounterTable
      moreInfo={(item): ReactElement => (
        <BusinessExtendedInfo businessID={item.business.id} filter={filter} />
      )}
      striped
      highlightOnHover
      stickyHeader
      items={businessLedgerRecordsSum}
      columns={[
        {
          title: 'Business Name',
          value: data => data.business.name,
        },
        {
          title: 'Debit',
          value: data => data.debit.formatted,
          style: { whiteSpace: 'nowrap' },
        },
        {
          title: 'Credit',
          value: data => data.credit.formatted,
          style: { whiteSpace: 'nowrap' },
        },
        {
          title: 'Total',
          value: data =>
            data.total.raw && (data.total.raw < -0.0001 || data.total.raw > 0.0001) ? (
              <Mark color={data.total.raw > 0 ? 'green' : 'red'}>{data.total.formatted}</Mark>
            ) : (
              data.total.formatted
            ),
          style: { whiteSpace: 'nowrap' },
        },
        ...getCurrencyCells(Currency.Eur),
        ...getCurrencyCells(Currency.Usd),
        ...getCurrencyCells(Currency.Gbp),
        ...getCurrencyCells(Currency.Cad),
        ...getCurrencyCells(Currency.Jpy),
        ...getCurrencyCells(Currency.Aud),
        ...getCurrencyCells(Currency.Sek),
      ]}
    />
  );
};

type BusinessLedgerRecordsSum = Extract<
  BusinessLedgerRecordsSummeryQuery['businessTransactionsSumFromLedgerRecords'],
  { businessTransactionsSum: unknown }
>['businessTransactionsSum'][number];

type CellInfo = {
  title: ReactNode;
  value: (data: BusinessLedgerRecordsSum) => string | ReactNode;
  style?: React.CSSProperties;
};

function getCurrencyCells(currency: Currency): CellInfo[] {
  return [
    {
      title: `${currency} Debit`,
      value: data => data.foreignCurrenciesSum.find(c => c.currency === currency)?.debit?.formatted,
      style: { whiteSpace: 'nowrap' },
    },
    {
      title: `${currency} Credit`,
      value: data =>
        data.foreignCurrenciesSum.find(c => c.currency === currency)?.credit?.formatted,
      style: { whiteSpace: 'nowrap' },
    },
    {
      title: `${currency} Total`,
      value: (data): ReactNode => {
        const currencyData = data.foreignCurrenciesSum.find(c => c.currency === currency);
        return currencyData?.total?.raw &&
          (currencyData.total.raw < -0.0001 || currencyData.total.raw > 0.0001) ? (
          <Mark color={currencyData.total.raw > 0 ? 'green' : 'red'}>
            {currencyData.total.formatted}
          </Mark>
        ) : (
          currencyData?.total?.formatted
        );
      },
      style: { whiteSpace: 'nowrap' },
    },
  ];
}
