import React, { useRef, useState, useMemo, useCallback } from 'react';
import type { FunctionComponent } from 'react';
import numeral from 'numeral';
import { formatUpperCase } from '../../i18n.js';
import { STREAM_COUNT_BREAKDOWN_FORMAT } from '../../constants';
import { DISPLAYED_CHART_DATA_DAYS } from '../../constants/filtering';
import { track } from '../../services/analytics.service';
import { moveBottomUnknownsStreamsChart } from '../../queries/formatters/global-sound-recording-streaming-trend.js';
import { Table, TableColumn } from '../Table';
import { RowNameCell } from './components/RowNameCell';
import { ExpandButton } from './components/ExpandButton';
import { RowIcon } from './components/RowIcon';
import { withTheme } from '../../branding';
import type { ThemeProps } from '../../branding/hoc/types';
import {
    createRows,
    createTotalRow,
    getFilteredRows,
    calculateTotal,
    createColumnConfig,
    getStatStyle
} from './utils';
import type { SourceOfStreamsTableProps, RowData, ColumnConfig } from './types';
import { ROW_KEY_TOTAL, COLLAPSE_THRESHOLD } from './types';
import {
    COLUMN_KEY_1DAY,
    COLUMN_KEY_7DAYS,
    COLUMN_KEY_28DAYS,
    COLUMN_KEY_ALL_TIME
} from './constants';
import themedStyles from './styles';

export const SourceOfStreamsTable: React.FC<SourceOfStreamsTableProps> = ({
    streamsBreakdowns,
    theme,
    typography,
    colors,
    clickableRows,
    onRowPress,
    selectedRow,
    rowInteractionEventName,
    shouldExcludeAllOthers = false,
    has1DayCell = true,
    has7DaysCell = true,
    has28DaysCell = false,
    hasAllTimeCell = true,
    hasGrowthPercentage = false,
    selectedStoreName
}) => {
    const rowInteractionEventTriggered = useRef(false);
    const [isExpanded, setIsExpanded] = useState(false);
    const styles = themedStyles[theme];
    const { SEVEN_DAYS, TWENTY_EIGHT_DAYS } = DISPLAYED_CHART_DATA_DAYS;

    const rows = useMemo(() => {
        const createdRows = createRows(
            streamsBreakdowns,
            colors,
            selectedStoreName
        );

        const rowsWithIcons = createdRows.map(row => ({
            ...row,
            icon: (
                <RowIcon
                    key={row.key}
                    keyValue={row.key}
                    countryFlagStyle={styles.countryFlag}
                />
            )
        }));

        return moveBottomUnknownsStreamsChart(rowsWithIcons);
    }, [streamsBreakdowns, colors, selectedStoreName, styles.countryFlag]);

    const totalStreamsAllTime = useMemo(
        () => calculateTotal(rows, it => it.breakdown.allTime),
        [rows]
    );

    const filteredRows = useMemo(
        () => getFilteredRows(shouldExcludeAllOthers, rows),
        [shouldExcludeAllOthers, rows]
    );

    const shouldShowExpandButton = useMemo(
        () => filteredRows.length > COLLAPSE_THRESHOLD,
        [filteredRows.length]
    );

    const displayedRows = useMemo(
        () =>
            isExpanded || !shouldShowExpandButton
                ? filteredRows
                : filteredRows.slice(0, COLLAPSE_THRESHOLD),
        [isExpanded, shouldShowExpandButton, filteredRows]
    );

    const totalRow = useMemo(
        () => createTotalRow(rows, colors, selectedStoreName),
        [rows, colors, selectedStoreName]
    );

    const headerRowData = useMemo(
        () => ({
            name: formatUpperCase(totalRow.formattedNameKey),
            ...totalRow
        }),
        [totalRow]
    );

    const handleRowPress = useCallback(
        (rowData: RowData) => {
            if (
                rowInteractionEventName &&
                !rowInteractionEventTriggered.current
            ) {
                track(rowInteractionEventName);
                rowInteractionEventTriggered.current = true;
            }
            if (onRowPress) {
                onRowPress(rowData);
            }
        },
        [rowInteractionEventName, onRowPress]
    );

    const handleToggleExpand = useCallback(() => {
        setIsExpanded(prev => !prev);
    }, []);

    const rowCellTextStyle = useMemo(
        () => [
            getStatStyle(typography),
            typography.body1DS,
            styles.streamCount
        ],
        [typography, styles.streamCount]
    );

    const createColumnProps = useCallback(
        (config: ColumnConfig) => ({
            headerFormat: (columnName: string) => {
                if (config.days === 1) {
                    return formatUpperCase('period.day', { day: 1 });
                }
                return config.days
                    ? formatUpperCase('period.days', { days: config.days })
                    : formatUpperCase(`period.${columnName}`);
            },
            cellValue: config.propertySelector,
            cellTextStyle: typography.label3DS,
            cellFormat: (value: number | null) =>
                value !== null
                    ? numeral(value)
                          .format(STREAM_COUNT_BREAKDOWN_FORMAT)
                          .toUpperCase()
                    : '-',
            headerTextStyle: [typography.label3DS, styles.statHeader],
            hasGrowthPercentage: hasGrowthPercentage
        }),
        [typography, styles.statHeader, hasGrowthPercentage]
    );

    const columnProps1Day = useMemo(
        () =>
            createColumnProps(
                createColumnConfig(
                    1,
                    it => it.breakdown.oneDay,
                    COLUMN_KEY_1DAY,
                    COLUMN_KEY_1DAY
                )
            ),
        [createColumnProps]
    );

    const columnProps7Days = useMemo(
        () =>
            createColumnProps(
                createColumnConfig(
                    SEVEN_DAYS,
                    it => it.breakdown.sevenDays,
                    COLUMN_KEY_7DAYS,
                    COLUMN_KEY_7DAYS
                )
            ),
        [createColumnProps, SEVEN_DAYS]
    );

    const columnProps28Days = useMemo(
        () =>
            createColumnProps(
                createColumnConfig(
                    TWENTY_EIGHT_DAYS,
                    it => it.breakdown.twentyEightDays,
                    COLUMN_KEY_28DAYS,
                    COLUMN_KEY_28DAYS
                )
            ),
        [createColumnProps, TWENTY_EIGHT_DAYS]
    );

    const columnPropsAllTime = useMemo(
        () =>
            createColumnProps(
                createColumnConfig(
                    undefined,
                    it => it.breakdown.allTime,
                    COLUMN_KEY_ALL_TIME,
                    COLUMN_KEY_ALL_TIME
                )
            ),
        [createColumnProps]
    );

    const switchSelectorColumns = useMemo(
        () => [
            has1DayCell ? (
                <TableColumn
                    cellStyle={undefined}
                    renderCell={undefined}
                    key={COLUMN_KEY_1DAY}
                    testID={COLUMN_KEY_1DAY}
                    name={COLUMN_KEY_1DAY}
                    {...columnProps1Day}
                    cellTextStyle={rowCellTextStyle}
                />
            ) : null,
            has7DaysCell ? (
                <TableColumn
                    cellStyle={undefined}
                    renderCell={undefined}
                    key={COLUMN_KEY_7DAYS}
                    testID={COLUMN_KEY_7DAYS}
                    name={COLUMN_KEY_7DAYS}
                    {...columnProps7Days}
                    cellTextStyle={rowCellTextStyle}
                />
            ) : null,
            has28DaysCell ? (
                <TableColumn
                    cellStyle={undefined}
                    renderCell={undefined}
                    key={COLUMN_KEY_28DAYS}
                    testID={COLUMN_KEY_28DAYS}
                    name={COLUMN_KEY_28DAYS}
                    {...columnProps28Days}
                    cellTextStyle={rowCellTextStyle}
                />
            ) : null,
            hasAllTimeCell ? (
                <TableColumn
                    cellStyle={undefined}
                    renderCell={undefined}
                    key={COLUMN_KEY_ALL_TIME}
                    testID={COLUMN_KEY_ALL_TIME}
                    name={COLUMN_KEY_ALL_TIME}
                    {...columnPropsAllTime}
                    cellTextStyle={rowCellTextStyle}
                />
            ) : null
        ],
        [
            hasAllTimeCell,
            columnProps1Day,
            columnProps7Days,
            columnPropsAllTime,
            rowCellTextStyle
        ]
    );

    return (
        <>
            <Table
                style={styles.container}
                contentContainerStyle={styles.content}
                rowStyle={styles.rowDS2}
                columnHeaderStyle={styles.columnHeaderStyle}
                rowKeyTotal={ROW_KEY_TOTAL}
                data={displayedRows}
                clickableRows={clickableRows}
                highlightedItemStyle={styles.highlightedRow}
                highlightedCellTextStyle={styles.highlightedCellTextStyle}
                onRowPress={handleRowPress}
                highlightedItemKey={selectedRow}
                headerRowData={rows.length > 1 && headerRowData}
                headerRowStyle={{}}
                headerRowTextStyle={[
                    styles.headerRowText,
                    !clickableRows && styles.highlightedCellTextStyle
                ]}
                keyExtractor={(row: RowData) => row.key}
            >
                <TableColumn
                    headerTextStyle={undefined}
                    headerFormat={undefined}
                    testID={undefined}
                    cellTextStyle={undefined}
                    key="streamSource"
                    name="streamSource"
                    headerVisible={false}
                    headerStyle={styles.totalRow}
                    cellStyle={styles.totalRow}
                    renderCell={(_name: string, row: RowData) => {
                        const hasPercentage =
                            hasGrowthPercentage && rows.length > 1;
                        return (
                            <RowNameCell
                                row={row}
                                isTotal={row.key === ROW_KEY_TOTAL}
                                selectedRow={selectedRow}
                                totalStreamsAllTime={totalStreamsAllTime}
                                hasGrowthPercentage={hasPercentage}
                                selectedStoreName={selectedStoreName}
                                typography={typography}
                                styles={styles}
                            />
                        );
                    }}
                />
                {switchSelectorColumns}
            </Table>

            {shouldShowExpandButton && (
                <ExpandButton
                    isExpanded={isExpanded}
                    onToggle={handleToggleExpand}
                    styles={styles}
                />
            )}
        </>
    );
};

export default React.memo(withTheme(SourceOfStreamsTable)) as FunctionComponent<
    Omit<SourceOfStreamsTableProps, keyof ThemeProps>
>;
