import React from 'react';
import { formatMessage, formatNumber } from '@theorchard/suite-i18n';
import { get, set } from '@theorchard/suite-utils';
import cx from 'classnames';
import { createRowInstance } from '../../base/api/rows';
import { TableCell } from '../../base/components/tableCell';
import type {
    CellProps,
    InitializedColumnDefinition,
    InitializedTableProps,
    RowInstance,
    TableExtension,
} from '../../base/types';

const isNumber = (value: unknown): value is number => typeof value === 'number';

function isNumericColumn<Data>(
    column: InitializedColumnDefinition<Data>,
    rows: RowInstance<Data>[]
) {
    return rows.some((row) => isNumber(get(row.data, column.name)));
}

function findTotalsTitleColumn<Data>(columnDefs: InitializedColumnDefinition<Data>[]) {
    if (columnDefs[0].name === 'table-selection') return columnDefs[1];
    return columnDefs[0];
}

function setTotalsTitle<Data>(row: Data, columnDefs: InitializedColumnDefinition<Data>[]) {
    const titleColumn = findTotalsTitleColumn(columnDefs);

    if (get(row, titleColumn.name) === undefined)
        set(row, titleColumn.name, formatMessage('table_total'));
}

function createTotals<Data>(rows: RowInstance<Data>[], props: InitializedTableProps<Data>): Data {
    return props.columnDefs.reduce((totals, column) => {
        return set(
            { ...totals },
            column.name,
            isNumericColumn(column, rows)
                ? rows.reduce((total, row) => {
                      const value = get(row.data, column.name);
                      if (isNumber(value)) return total + value;
                      return total;
                  }, 0)
                : undefined
        );
    }, {}) as Data;
}

function DefaultTotalCell<Data>({ value }: CellProps<Data>) {
    const renderValue = () => {
        if (isNumber(value)) return <>{formatNumber(value)}</>;
        return <>{value}</>;
    };

    return <div className="GridTable-cell-text">{renderValue()}</div>;
}

function onRowsCreated<Data>(
    rows: RowInstance<Data>[],
    props: InitializedTableProps<Data>
): RowInstance<Data>[] {
    const { showTotals, customTotals, totalsPlacement, loading } = props;

    if (!showTotals || loading) return rows;

    const totalsRow = (customTotals as Data) ?? createTotals(rows, props);
    setTotalsTitle(totalsRow, props.columnDefs);

    const totalRowInstance = {
        ...createRowInstance(totalsRow, props, '_TOTALS'),
        sticky: totalsPlacement === 'sticky-top',
        selectable: false,
        className: 'totals',
    };

    totalRowInstance.Content = ({ columns }) => (
        <>
            {columns.map((col, i) => {
                const column = {
                    ...col,
                    definition: {
                        ...col.definition,
                        Cell: col.definition.TotalCell ?? DefaultTotalCell,
                    },
                };

                return (
                    <TableCell
                        key={col.definition.name}
                        column={column}
                        row={totalRowInstance}
                        columnIndex={i}
                    />
                );
            })}
        </>
    );

    return [
        totalRowInstance,
        ...rows.map((row) => ({
            ...row,
            index: row.index + 1,
        })),
    ];
}

export const TableTotalsRowExtension: TableExtension = {
    name: 'totals-row',
    isEnabled: (props) => !!props.showTotals,
    onRowsCreated,
    onPropsInit: (props) => {
        const titleColumn = findTotalsTitleColumn(props.columnDefs);
        titleColumn.className = cx(titleColumn.className, 'col-totals-title');

        return props;
    },
};
