import {
    Button,
    GlyphButton,
    GridTable,
    Pagination,
} from '@theorchard/suite-components';
import { CountryFlag, GlyphIcon } from '@theorchard/suite-icons';
import cx from 'classnames';
import dayjs from 'dayjs';
import React, { useState } from 'react';
import { useIsYouTubeFingerprintRulesEnabled } from 'shared/features';
import CurrentEmptyState from 'src/assets/svg/empty-state-current.svg';
import ExpiredEmptyState from 'src/assets/svg/empty-state-expired.svg';
import ScheduledEmptyState from 'src/assets/svg/empty-state-scheduled.svg';
import {
    TIKTOK_KEY,
    YOUTUBE_KEY,
} from 'src/components/fingerprintRulesOAPanel/fingerprint-rules-oa-panel';
import UpdatedAddRule from 'src/components/fingerprintRulesOAPanel/updatedAddRule';
import { PolicyType } from 'src/types';
import { paginate } from 'src/utils/pagination';
import type { GridTableSelectAll } from '@theorchard/suite-components';
import type { FC } from 'react';
import type { TimeRule } from 'src/components/fingerprintRulesOAPanel/deliveryRules/delivery-rules';
import type { EditRowData } from 'src/components/fingerprintRulesOAPanel/updatedAddRule/updated-add-rule';
import type {
    FingerprintRule,
    FingerprintRuleInput,
    Profile,
    Territory,
} from 'src/types';

export interface DeliveryRule {
    countryName: string | undefined;
    active: boolean;
    policy: string;
    service: string;
    territory: string;
    startDate?: string | undefined;
    endDate?: string | undefined;
    createdDate: string;
    lastModifiedDate: string;
    createdBy: Profile;
    lastModifiedBy: Profile;
    level: string;
}

export interface DeliveryRulesTableProps {
    accountType: string;
    tableRules: DeliveryRule[];
    higherLevelRules: FingerprintRule[];
    currentRules: FingerprintRule[];
    current: boolean;
    scheduled: boolean;
    expired: boolean;
    onDeleteRow: (message: string, rules: FingerprintRuleInput[]) => void;
    editable?: boolean;
    onEditRow: (
        rules: FingerprintRuleInput[],
        timeFilter: TimeRule | null,
        message: string
    ) => void;
    territories: Territory[] | undefined;
}

interface BulkDisableState {
    isEditDisabled: boolean;
    isDeleteDisabled: boolean;
}

interface BulkRule {
    territory: string;
    service: string;
    policy: string;
    level: string;
    startDate: string;
    endDate: string;
}

const formatRules = (rules: FingerprintRule[]): FingerprintRuleInput[] => {
    return rules.map(r => {
        const policy =
            Object.keys(PolicyType)[
                Object.values(PolicyType).indexOf(r.policy as PolicyType)
            ];
        const service = r.service.toLowerCase();
        const territory = r.territory;
        let startDate = (r.startDate as string) || null;
        if (!startDate || startDate === '-') startDate = null;
        let endDate = (r.endDate as string) || null;
        if (!endDate || endDate === '-') endDate = null;
        return {
            policy,
            service,
            territory,
            start: startDate
                ? dayjs(startDate).format('YYYY-MM-DD') + 'T00:00:00+00:00'
                : null,
            end: endDate
                ? dayjs(endDate).format('YYYY-MM-DD') + 'T00:00:00+00:00'
                : null,
        };
    });
};

const getBulkDisableState = (
    selectedRows: string[],
    accountType: string
): BulkDisableState => {
    const isEditDisabled = false;
    const isDeleteDisabled = false;

    const extractedRules = selectedRows.map(row => {
        const splitData = row.split('_');
        return {
            territory: splitData[0],
            service: splitData[1],
            policy: splitData[2],
            level: splitData[3],
            startDate: splitData[4],
            endDate: splitData[5],
        };
    });

    //Check if higher level rule is selected
    for (let index = 0; index < extractedRules.length; index++) {
        const row = extractedRules[index];
        if (row.level !== accountType) {
            return {
                isEditDisabled: true,
                isDeleteDisabled: true,
            };
        }
    }

    //Check if higher level rule has been selected
    const tempRules: BulkRule[] = [];
    for (let index = 0; index < extractedRules.length; index++) {
        const row = extractedRules[index];
        const foundDiffRule = tempRules.find(rule => {
            if (
                rule.service !== row.service ||
                rule.policy !== row.policy ||
                rule.startDate !== row.startDate ||
                rule.endDate !== row.endDate
            )
                return rule;
        });
        if (foundDiffRule)
            return {
                isEditDisabled: true,
                isDeleteDisabled: false,
            };
        tempRules.push(row);
    }

    //Check if carveout rule has been selected
    const foundCarveout = extractedRules.find(r => r.policy === 'Carve-out');
    if (foundCarveout)
        return {
            isEditDisabled: true,
            isDeleteDisabled: false,
        };

    return {
        isEditDisabled,
        isDeleteDisabled,
    };
};

const convertRuleToRowKey = (rule: DeliveryRule) => {
    return `${rule.territory}_${rule.service}_${rule.policy}_${rule.level}_${rule.startDate}_${rule.endDate}`;
};

export const CLASS_NAME = 'DeliveryRulesTable';

export const DeliveryRulesTable: FC<DeliveryRulesTableProps> = ({
    accountType,
    tableRules,
    higherLevelRules,
    currentRules,
    current,
    scheduled,
    expired,
    onDeleteRow,
    editable,
    onEditRow,
    territories,
}) => {
    const isYouTubeFingerprintRulesEnabled =
        useIsYouTubeFingerprintRulesEnabled();
    const [page, setPage] = useState(0);
    const [pageSize, setPageSize] = useState(10);
    const [openSidecar, setOpenSidecar] = useState(false);
    const [rowToEdit, setRowToEdit] = useState<EditRowData>();
    const [selectedRows, setSelectedRows] = useState<string[]>([]);

    const disableSelectAll = () => setSelectAll('disabled');
    const [selectAll, setSelectAll] = useState<
        GridTableSelectAll | undefined
    >();

    const handleSelectAll = (selectAll: GridTableSelectAll) => {
        setSelectAll(selectAll);

        if (selectAll === 'enabled') {
            const affectedRows = [];
            for (const paginatedRule of paginatedRules) {
                affectedRows.push(
                    ...paginatedRule
                        .filter(rule => rule.level === accountType)
                        .map(rule => convertRuleToRowKey(rule))
                );
            }
            handleSelectedRows(affectedRows);
        }
    };

    const handlePage = (page: number) => {
        setPage(page);
        disableSelectAll();
    };

    const handlePageSize = (size: number) => {
        setPageSize(size);
        disableSelectAll();
    };

    let filteredRules: DeliveryRule[] = [];
    if (!isYouTubeFingerprintRulesEnabled) {
        filteredRules = tableRules.filter(
            r => r.service.toLowerCase() === TIKTOK_KEY
        );
    } else {
        filteredRules = tableRules.filter(
            r =>
                r.service.toLowerCase() === YOUTUBE_KEY ||
                r.service.toLowerCase() === TIKTOK_KEY
        );
    }
    const paginatedRules = paginate(filteredRules, pageSize);

    const closeSidecar = () => {
        setOpenSidecar(false);
    };

    const handleSaveEditRule = (rules: FingerprintRuleInput[]) => {
        if (!editable) return;
        let message = '';
        let isBulkMessage = false;
        if (rowToEdit && rowToEdit.territories.length > 1) isBulkMessage = true;

        if (current)
            message = isBulkMessage
                ? $t(
                      'fingerprintRules.deliveryRulesTable.editMessage.bulkCurrent'
                  )
                : $t('fingerprintRules.deliveryRulesTable.editMessage.current');
        else if (scheduled)
            message = isBulkMessage
                ? $t(
                      'fingerprintRules.deliveryRulesTable.editMessage.bulkScheduled'
                  )
                : $t(
                      'fingerprintRules.deliveryRulesTable.editMessage.scheduled'
                  );
        else if (expired)
            message = isBulkMessage
                ? $t(
                      'fingerprintRules.deliveryRulesTable.editMessage.bulkExpired'
                  )
                : $t('fingerprintRules.deliveryRulesTable.editMessage.expired');

        setSelectedRows([]);
        closeSidecar();

        return onEditRow(rules, null, message);
    };

    const handleEditRow = (row: any) => {
        let startDate = '',
            endDate = '';
        if (row.startDate && row.startDate !== '-') {
            startDate = dayjs(row.startDate).format('YYYY-MM-DD');
        }
        if (row.endDate && row.endDate !== '-') {
            endDate = dayjs(row.endDate).format('YYYY-MM-DD');
        }

        setRowToEdit({
            territories: [row.territory],
            policy: { value: row.policy },
            service: { value: row.service },
            startDate: startDate,
            endDate: endDate,
        });
        setOpenSidecar(true);
    };

    const handleDeleteRow = (row: any) => {
        const formattedRowService =
            row.service.toLowerCase() === 'global' ? '*' : row.service;
        const formattedRowTerritory =
            row.territory.toLowerCase() === 'global' ? '*' : row.territory;

        const filteredRules = currentRules.filter(rule => {
            const { policy, service, territory, startDate, endDate } = rule;
            if (
                row.policy !== policy ||
                formattedRowService !== service ||
                formattedRowTerritory !== territory ||
                row.startDate !== startDate ||
                row.endDate !== endDate
            )
                return rule;
        });

        const formattedRules = formatRules(filteredRules);

        let message = '';
        if (current)
            message = $t(
                'fingerprintRules.deliveryRulesTable.deleteMessage.current'
            );
        else if (scheduled)
            message = $t(
                'fingerprintRules.deliveryRulesTable.deleteMessage.scheduled'
            );
        else if (expired)
            message = $t(
                'fingerprintRules.deliveryRulesTable.deleteMessage.expired'
            );

        disableSelectAll();
        return onDeleteRow(message, formattedRules);
    };

    const handleSelectedRows = (rows: any) => {
        setSelectedRows(rows);
    };

    const handleBulkEditRows = () => {
        const extractedRules = selectedRows.map(row => {
            const splitData = row.split('_');
            return {
                territory: splitData[0],
                service: splitData[1],
                policy: splitData[2],
                level: splitData[3],
                startDate: splitData[4],
                endDate: splitData[5],
            };
        });
        if (extractedRules.length > 0) {
            let startDate = '',
                endDate = '';
            if (
                extractedRules[0].startDate &&
                extractedRules[0].startDate !== '-'
            ) {
                startDate = dayjs(extractedRules[0].startDate).format(
                    'YYYY-MM-DD'
                );
            }
            if (
                extractedRules[0].endDate &&
                extractedRules[0].endDate !== '-'
            ) {
                endDate = dayjs(extractedRules[0].endDate).format('YYYY-MM-DD');
            }
            setRowToEdit({
                territories: extractedRules.map(rule => rule.territory),
                policy: { value: extractedRules[0].policy },
                service: { value: extractedRules[0].service },
                startDate: startDate,
                endDate: endDate,
            });
            setOpenSidecar(true);
        }
    };

    const handleBulkDeleteRows = () => {
        const extractedRules = selectedRows.map(row => {
            const splitData = row.split('_');
            return {
                territory: splitData[0],
                service: splitData[1],
                policy: splitData[2],
                level: splitData[3],
                startDate: splitData[4],
                endDate: splitData[5],
            };
        });
        const filteredRules = currentRules.filter(rule => {
            const { policy, service, territory, startDate, endDate } = rule;
            const foundRule = extractedRules.find(extractedRule => {
                const formattedService =
                    extractedRule.service.toLowerCase() === 'global'
                        ? '*'
                        : extractedRule.service;
                const formattedTerritory =
                    extractedRule.territory.toLowerCase() === 'global'
                        ? '*'
                        : extractedRule.territory;

                if (
                    formattedTerritory === territory &&
                    formattedService === service &&
                    extractedRule.policy === policy &&
                    extractedRule.startDate === startDate &&
                    extractedRule.endDate === endDate
                )
                    return rule;
            });
            if (!foundRule) return rule;
        });
        const formattedRules = formatRules(filteredRules);

        let message = '';
        if (current)
            message = $t(
                'fingerprintRules.deliveryRulesTable.deleteMessage.bulkCurrent'
            );
        else if (scheduled)
            message = $t(
                'fingerprintRules.deliveryRulesTable.deleteMessage.bulkScheduled'
            );
        else if (expired)
            message = $t(
                'fingerprintRules.deliveryRulesTable.deleteMessage.bulkExpired'
            );

        setSelectedRows([]);
        return onDeleteRow(message, formattedRules);
    };

    const renderEmptyStateBody = () => {
        let Svg;
        if (current) Svg = CurrentEmptyState;
        else if (scheduled) Svg = ScheduledEmptyState;
        else Svg = ExpiredEmptyState;
        return (
            <div className={`${CLASS_NAME}-empty-state-body`}>
                <div>
                    <img src={String(Svg)} className={`${CLASS_NAME}-img`} />
                    {current && (
                        <p className={`${CLASS_NAME}-empty-state-body-title`}>
                            {$t(
                                'fingerprintRules.deliveryRulesTable.emptyState.title.current'
                            )}
                        </p>
                    )}
                    {scheduled && (
                        <p className={`${CLASS_NAME}-empty-state-body-title`}>
                            {$t(
                                'fingerprintRules.deliveryRulesTable.emptyState.title.scheduled'
                            )}
                        </p>
                    )}
                    {expired && (
                        <p className={`${CLASS_NAME}-empty-state-body-title`}>
                            {$t(
                                'fingerprintRules.deliveryRulesTable.emptyState.title.expired'
                            )}
                        </p>
                    )}
                    <p className={`${CLASS_NAME}-empty-state-body-subtitle`}>
                        {$t(
                            'fingerprintRules.deliveryRulesTable.emptyState.subTitle'
                        )}
                    </p>
                </div>
            </div>
        );
    };

    const renderActions = (data: DeliveryRule) => {
        const { level, policy } = data;
        if (level !== accountType)
            return (
                <div className={`${CLASS_NAME}-table-actions-cell-empty`}>
                    <p>-</p>
                </div>
            );

        return (
            <div className={`${CLASS_NAME}-table-actions-cell`}>
                {policy !== 'Carve-out' && (
                    <GlyphButton
                        className="TableActionButton editButton"
                        onClick={() => handleEditRow(data)}
                        name="edit"
                        disabled={!editable}
                    />
                )}

                <GlyphButton
                    className="TableActionButton trashButton"
                    onClick={() => handleDeleteRow(data)}
                    name="trash"
                    disabled={!editable}
                />
            </div>
        );
    };

    const renderHeader = () => {
        const bulkDisable = getBulkDisableState(selectedRows, accountType);

        return (
            <div className={`${CLASS_NAME}-table-header`}>
                {selectedRows.length > 0 && (
                    <div className={`${CLASS_NAME}-table-header-actions`}>
                        <div
                            className={`${CLASS_NAME}-table-header-actions-selected-items`}
                        >
                            <p>{`${selectedRows.length} ${$t(
                                'fingerprintRules.deliveryRulesTable.header.selectedItems'
                            )}`}</p>
                        </div>
                        <div
                            className={`${CLASS_NAME}-table-header-actions-buttons`}
                        >
                            <div className={`${CLASS_NAME}-table-actions-cell`}>
                                <Button
                                    className="TableActionButton editButton"
                                    onClick={() => handleBulkEditRows()}
                                    disabled={bulkDisable.isEditDisabled}
                                >
                                    <GlyphIcon name="edit" size={16} />
                                </Button>
                                <Button
                                    className="TableActionButton trashButton"
                                    disabled={bulkDisable.isDeleteDisabled}
                                    onClick={() => handleBulkDeleteRows()}
                                >
                                    <GlyphIcon name="trash" size={16} />
                                </Button>
                            </div>
                        </div>
                    </div>
                )}
                <div
                    className={cx(`${CLASS_NAME}-table-header-pagination`, {
                        margin: selectedRows.length > 0,
                    })}
                >
                    {paginatedRules.length > 0 && (
                        <Pagination
                            totalCount={filteredRules.length}
                            currentPage={page}
                            pageSize={pageSize}
                            onSetPageSize={handlePageSize}
                            onChange={handlePage}
                        />
                    )}
                </div>
            </div>
        );
    };

    return (
        <div className={`${CLASS_NAME}`}>
            <div className={`${CLASS_NAME}-table`}>
                <GridTable
                    variant="zebra"
                    data={paginatedRules[page]}
                    bordered={true}
                    selectable={!expired}
                    shadowed
                    emptyStateComponent={renderEmptyStateBody()}
                    paginated={filteredRules.length > 0}
                    page={page}
                    pageSize={pageSize}
                    header={filteredRules.length > 0 ? renderHeader : null}
                    rowKey={convertRuleToRowKey}
                    totalCount={filteredRules.length}
                    selectedRowKeys={selectedRows}
                    onSelectedRowsChanged={handleSelectedRows}
                    selectAllEnabled
                    selectAll={selectAll}
                    onSelectAllChanged={handleSelectAll}
                >
                    <GridTable.Column
                        name="countryName"
                        title="Country"
                        sortable
                        Cell={({ data }: { data: DeliveryRule }) => {
                            return (
                                <div
                                    className={`${CLASS_NAME}-table-country-cell`}
                                >
                                    <div
                                        className={`${CLASS_NAME}-table-country-cell-img`}
                                    >
                                        <CountryFlag
                                            countryCode={data.territory}
                                        />
                                    </div>
                                    <div>
                                        <p
                                            className={`${CLASS_NAME}-table-country-cell-title`}
                                        >
                                            {data.countryName}
                                        </p>
                                    </div>
                                </div>
                            );
                        }}
                    />
                    <GridTable.Column
                        name="service"
                        title="Service"
                        sortable={false}
                    />
                    <GridTable.Column
                        name="policy"
                        title="Rule"
                        sortable={false}
                    />
                    <GridTable.Column
                        name="level"
                        title="Rule Level"
                        sortable={false}
                    />
                    <GridTable.Column
                        name="startDate"
                        title="Start date"
                        sortable
                        align="right"
                    />
                    <GridTable.Column
                        name="endDate"
                        title="End date"
                        sortable
                        align="right"
                    />
                    <GridTable.Column
                        name="createdDate"
                        title="Created on"
                        sortable={false}
                        align="right"
                    />
                    <GridTable.Column
                        name="createdBy.profileName"
                        title="Created by"
                        sortable={false}
                    />
                    {(current || scheduled) && (
                        <GridTable.Column
                            name="action"
                            title="Actions"
                            sortable={false}
                            Cell={({ data }: { data: DeliveryRule }) =>
                                renderActions(data)
                            }
                        />
                    )}
                </GridTable>
            </div>
            <UpdatedAddRule
                title={$t('fingerprintRules.deliveryRulesTable.sidecar.title')}
                isOpen={openSidecar}
                onClose={closeSidecar}
                onConfirm={handleSaveEditRule}
                higherLevelRules={higherLevelRules}
                currentRules={currentRules}
                editRowData={rowToEdit}
                territories={territories}
            />
        </div>
    );
};

export default DeliveryRulesTable;
