import {createContext, useRef, useState, forwardRef, useImperativeHandle} from 'react';
import {__} from '@wordpress/i18n';
import {A11yDialog} from 'react-a11y-dialog';
import A11yDialogInstance from 'a11y-dialog';
import {GiveIcon} from '@givewp/components';
import {ListTable} from '../ListTable';
import Pagination from '../Pagination';
import {Filter, getInitialFilterState} from '../Filters';
import useDebounce from '../hooks/useDebounce';
import {useResetPage} from '../hooks/useResetPage';
import ListTableApi from '../api';
import styles from './ListTablePage.module.scss';
import cx from 'classnames';
import {BulkActionSelect} from '@givewp/components/ListTable/BulkActions/BulkActionSelect';
import ToggleSwitch from '@givewp/components/ListTable/ToggleSwitch';
import DeleteIcon from '@givewp/components/ListTable/ListTablePage/DeleteIcon';
import ListTableStats, { StatConfig } from '../ListTableStats/ListTableStats';
import FilterBy from '../FilterBy';

export interface ListTablePageProps {
    //required
    title: string;
    apiSettings: {apiRoot; apiNonce; table};

    //optional
    bulkActions?: Array<BulkActionsConfig> | null;
    pluralName?: string;
    singleName?: string;
    children?: JSX.Element | JSX.Element[] | null;
    rowActions?: JSX.Element | JSX.Element[] | Function | null;
    filterSettings?;
    align?: 'start' | 'center' | 'end';
    paymentMode?: boolean;
    listTableBlankSlate: JSX.Element;
    productRecommendation?: JSX.Element;
    columnFilters?: Array<ColumnFilterConfig>;
    banner?: () => JSX.Element;
    contentMode?: boolean;
    perPage?: number;
    statsConfig?: Record<string, StatConfig>;
}

interface FilterConfigBase {
    // required
    name: string;

    // optional
    ariaLabel?: string;
    inlineSize?: string;
    text?: string;
}

interface FilterConfigWithSimpleOptions extends FilterConfigBase {
    type: 'select' | 'campaignselect' | 'search' | 'checkbox' | 'hidden';
    options?: Array<{text: string; value: string}>;
}

export interface FilterByGroupedOptions {
    id: string;
    apiParam: string;
    name: string;
    type: 'checkbox' | 'radio' | 'toggle';
    options: Array<{text: string; value: string}>;
    defaultValue?: string | string[];
    isVisible?: (values: Record<string, string[]>) => boolean;
    showTitle?: boolean;
}

interface FilterConfigWithGroupedOptions extends FilterConfigBase {
    type: 'filterby';
    groupedOptions?: Array<FilterByGroupedOptions>;
}

export type FilterConfig = FilterConfigWithSimpleOptions | FilterConfigWithGroupedOptions;

export interface ColumnFilterConfig {
    column: string;
    filter: Function;
}

interface BulkActionsConfigBase {
    //required
    label: string;
    value: string | number;
    confirm: (
        selected: Array<string | number>,
        names?: Array<string>,
        isOpen?: boolean,
        setOpen?: (isOpen?: boolean) => void
    ) => JSX.Element | JSX.Element[] | string;

    //optional
    isVisible?: (data: any, parameters: any) => boolean;
    isIdSelectable?: (id: string, data: any) => boolean;
    type?: 'normal' | 'warning' | 'danger' | 'custom';
}

// Makes the "action" property required for the standard types
interface BulkActionsConfigWithAction extends BulkActionsConfigBase {
    type: 'normal' | 'warning' | 'danger';
    action: (selected: Array<string | number>) => Promise<{errors: string | number; successes: string | number}>;
}

// Makes the "action" property required for the undefined type
interface BulkActionsConfigWithoutType extends BulkActionsConfigBase {
    type?: undefined;
    action: (selected: Array<string | number>) => Promise<{errors: string | number; successes: string | number}>;
}

// Makes the "action" property forbidden for the custom type
export interface BulkActionsConfigWithoutAction extends BulkActionsConfigBase {
    type: 'custom';
}

export type BulkActionsConfig =
    | BulkActionsConfigWithAction
    | BulkActionsConfigWithoutType
    | BulkActionsConfigWithoutAction;

export const ShowConfirmModalContext = createContext(
    (label, confirm, action, type = null, confirmButtonText = __('Confirm', 'give')) => {}
);
export const CheckboxContext = createContext(null);

export interface ListTablePageRef {
    refresh: () => Promise<any>;
}

const ListTablePage = forwardRef<ListTablePageRef, ListTablePageProps>(({
    title,
    apiSettings,
    bulkActions = null,
    filterSettings = [],
    singleName = __('item', 'give'),
    pluralName = __('items', 'give'),
    rowActions = null,
    children = null,
    align = 'start',
    paymentMode,
    listTableBlankSlate,
    productRecommendation,
    columnFilters = [],
    banner,
    contentMode,
    perPage = 30,
    statsConfig,
}: ListTablePageProps, ref) => {
    const [page, setPage] = useState<number>(1);
    const [filters, setFilters] = useState(getInitialFilterState(filterSettings));
    const [isOpen, setOpen] = useState(false);
    const [modalContent, setModalContent] = useState<{
        confirm;
        action?;
        label;
        confirmButtonText?: string;
        type?: 'normal' | 'warning' | 'danger' | 'custom';
    }>({
        confirm: (selected) => {},
        action: (selected) => {},
        label: '',
        confirmButtonText: '',
    });
    const [selectedAction, setSelectedAction] = useState<string>('');
    const [selectedIds, setSelectedIds] = useState([]);
    const [selectedNames, setSelectedNames] = useState([]);
    const dialog = useRef() as {current: A11yDialogInstance};
    const checkboxRefs = useRef([]);
    const [sortField, setSortField] = useState<{sortColumn: string; sortDirection: string}>({
        sortColumn: 'id',
        sortDirection: 'desc',
    });
    const [testMode, setTestMode] = useState(paymentMode);

    const {sortColumn, sortDirection} = sortField;
    const locale = navigator.language || navigator.languages[0];
    const testModeFilter = filterSettings.find((filter) => filter.name === 'toggle');

    const parameters = {
        page,
        perPage,
        sortColumn,
        sortDirection,
        locale,
        testMode,
        ...filters,
    };

    const archiveApi = useRef(new ListTableApi(apiSettings)).current;

    const {data, error, isValidating, mutate} = archiveApi.useListTable(parameters);
    const {data: statsData, error: statsError, isValidating: statsIsValidating, mutate: mutateStats} = statsConfig ? archiveApi.useStats(testMode) : {data: null, error: null, isValidating: false, mutate: async () => {}};

    useResetPage(data, page, setPage, filters);

    useImperativeHandle(ref, () => ({
        refresh: async () => {
           await mutate();
           statsConfig && await mutateStats();
        }
    }), [mutate, mutateStats, statsConfig]);

    const handleFilterChange = (name, value) => {
        setFilters((prevState) => {
            if (!value || (Array.isArray(value) && value.length === 0)) {
                const {[name]: _, ...rest} = prevState as Record<string, string[]>;
                return rest;
            }
            return {...prevState, [name]: value};
        });
    };

    const handleDebouncedFilterChange = useDebounce(handleFilterChange);

    const showConfirmActionModal = (
        label,
        confirm,
        action,
        type?: 'normal' | 'warning' | 'danger' | 'custom' | null,
        confirmButtonText?: string
    ) => {
        setModalContent({label, confirm, action, type, confirmButtonText});
        dialog.current.show();
    };

    const openBulkActionModal = (event) => {
        event.preventDefault();

        if (window.GiveDonations && window.GiveDonations.addonsBulkActions) {
            bulkActions = [...bulkActions, ...window.GiveDonations.addonsBulkActions];
        }

        const bulkAction = bulkActions.find((config) => selectedAction === config.value);

        if (!bulkAction) return;

        const selected = [];
        const names = [];
        const selectedRefs = checkboxRefs.current.filter((checkbox) => {
            const isSelectable = bulkAction?.isIdSelectable?.(checkbox.dataset.id, data) ?? true;
            return checkbox.checked && isSelectable;
        });
        selectedRefs.forEach((checkbox) => {
            selected.push(checkbox.dataset.id);
            names.push(checkbox.dataset.name);
        });
        setSelectedIds(selected);
        setSelectedNames(names);
        if (selected.length) {
            setModalContent({...bulkAction});
            if ('custom' === bulkAction.type) {
                setOpen(true);
                bulkAction?.confirm(selected, names, isOpen, setOpen);
            } else {
                dialog.current.show();
            }
        }
    };

    const setSortDirectionForColumn = (column, direction) => {
        setSortField((previousState) => {
            return {
                ...previousState,
                sortColumn: column,
                sortDirection: direction,
            };
        });
    };

    const showPagination = () => (
        <Pagination
            currentPage={page}
            totalPages={data ? data.totalPages : 1}
            disabled={!data}
            totalItems={data ? parseInt(data.totalItems) : -1}
            setPage={setPage}
            singleName={__('result', 'give')}
            pluralName={__('results', 'give')}
        />
    );

    const PageActions = ({PageActionsTop}: {PageActionsTop?: boolean}) => {
        return (
            <div className={cx(styles.pageActions, {[styles.alignEnd]: !bulkActions})}>
                {PageActionsTop ? (
                    <BulkActionSelect
                        selectedState={[selectedAction, setSelectedAction]}
                        parameters={parameters}
                        data={data}
                        bulkActions={bulkActions}
                        showModal={openBulkActionModal}
                    />
            ) : (
                    <>
                        {page && setPage && showPagination()}
                    </>
                )}
            </div>
        );
    };

    const TestModeFilter = () => (
        <ToggleSwitch ariaLabel={testModeFilter?.ariaLabel} onChange={setTestMode} checked={testMode} />
    );

    const TestModeBadge = () => <span className={styles.testModeBadge}>{testModeFilter?.text}</span>;

    const SearchSection = () => (
        <section role="search" className={styles.searchContainer}>
            <div className={styles.flexRow}>
                <PageActions PageActionsTop />
            </div>
            <div className={styles.flexRow}>
                {filterSettings.map((filter) => (
                    filter.type === 'filterby' ? (
                        <FilterBy
                            key={filter.name}
                            groupedOptions={filter.groupedOptions}
                            onChange={handleFilterChange}
                            values={filters}
                        />
                    ) : (
                        <Filter
                            key={filter.name}
                            value={filters[filter.name]}
                            filter={filter}
                            onChange={handleFilterChange}
                            debouncedOnChange={handleDebouncedFilterChange}
                        />
                    )
                ))}
            </div>
        </section>
    );

    return (
        <>
            <article className={styles.page}>
                {!contentMode && (
                    <>
                        <header className={styles.pageHeader}>
                            <div className={styles.flexRow}>
                                <GiveIcon size={'2.25rem'} />
                                <h1 className={styles.pageTitle}>{title}</h1>
                                {testModeFilter && testMode && <TestModeBadge />}
                            </div>
                            {children && <div className={styles.flexRow}>{children}</div>}
                        </header>

                        <div className={cx('wp-header-end', 'hidden')} />

                        {banner && <section role="banner">{banner()}</section>}
                        {testModeFilter && (
                            <div className={styles.filtersRow}>
                                <TestModeFilter />
                            </div>
                        )}
                        {statsConfig && !statsIsValidating && <ListTableStats config={statsConfig} values={statsData} />}
                    </>
                )}

                <div className={styles.pageContent}>
                    <SearchSection />
                    {contentMode && children ? <>{children}</> : <></>}
                    <CheckboxContext.Provider value={checkboxRefs}>
                        <ShowConfirmModalContext.Provider value={showConfirmActionModal}>
                            <ListTable
                                apiSettings={apiSettings}
                                sortField={sortField}
                                setSortDirectionForColumn={setSortDirectionForColumn}
                                singleName={singleName}
                                pluralName={pluralName}
                                title={title}
                                rowActions={rowActions}
                                parameters={parameters}
                                data={data}
                                error={error}
                                isLoading={isValidating}
                                align={align}
                                testMode={testMode}
                                listTableBlankSlate={listTableBlankSlate}
                                productRecommendation={productRecommendation}
                                columnFilters={columnFilters}
                                includeBulkActionsCheckbox={bulkActions?.length > 0}
                            />
                        </ShowConfirmModalContext.Provider>
                    </CheckboxContext.Provider>
                    <PageActions />
                </div>
            </article>
            <A11yDialog
                id="giveListTableModal"
                dialogRef={(instance) => (dialog.current = instance)}
                title={
                    <>
                        {modalContent?.type === 'danger' && <DeleteIcon />}
                        {modalContent?.label}
                    </>
                }
                titleId={styles.modalTitle}
                classNames={{
                    container: styles.container,
                    overlay: styles.overlay,
                    dialog: cx(styles.dialog, {
                        [styles.warning]: modalContent?.type === 'warning',
                        [styles.danger]: modalContent?.type === 'danger',
                    }),
                    closeButton: 'hidden',
                }}
            >
                <div className={styles.modalContent}>
                    {modalContent?.confirm(selectedIds, selectedNames, isOpen, setOpen) || null}
                </div>
                <div className={styles.gutter}>
                    <button id={styles.cancel} onClick={(event) => dialog.current?.hide()}>
                        {__('Cancel', 'give')}
                    </button>
                    <button
                        id={styles.confirm}
                        onClick={async (event) => {
                            dialog.current?.hide();
                            try {
                                await modalContent.action(selectedIds);
                                await mutate();
                                await mutateStats();
                            } catch (error) {
                                console.error('Bulk action error:', error);

                                // Create a user-friendly error message
                                let errorMessage = __('An error occurred while performing this action.', 'give');

                                if (error.message && error.message.includes('permission')) {
                                    errorMessage = __('You don\'t have permission to perform this action.', 'give');
                                } else if (error.message && error.message.includes('403')) {
                                    errorMessage = __('Access denied. You don\'t have permission to perform this action.', 'give');
                                } else if (error.message) {
                                    // Try to extract a meaningful message from the error
                                    const match = error.message.match(/You don't have permission[^"]*|You don&#039;t have permission[^"]*/i);
                                    if (match) {
                                        errorMessage = match[0].replace(/&#039;/g, "'");
                                    }
                                }

                                // Show error as a notice/alert
                                alert(errorMessage);
                            }
                        }}
                    >
                        {modalContent?.confirmButtonText ?? __('Confirm', 'give')}
                    </button>
                </div>
            </A11yDialog>
        </>
    );
});

ListTablePage.displayName = 'ListTablePage';

export default ListTablePage;
