import React, { useMemo, useState, useEffect, Fragment, useCallback, ReactNode } from "react";
import {
    ColumnDef,
    SortingState,
    ExpandedState,
    ColumnFiltersState,
    flexRender,
    getCoreRowModel,
    getPaginationRowModel,
    getSortedRowModel,
    getFilteredRowModel,
    getExpandedRowModel,
    useReactTable,
} from "@tanstack/react-table";
import { Table as BootstrapTable, Form, Button, Row, Col } from "react-bootstrap";
import { PiCaretDownBold, PiCaretUpBold, PiCaretDown, PiCaretRight, PiXBold, PiFunnel } from "react-icons/pi";
import AppPagination from "./app-pagination";

interface DataTableClientProps<TData> {
    data: TData[];
    columns: ColumnDef<TData, any>[];
    initialSorting?: SortingState;
    enableMultiSort?: boolean;
    className?: string;
    emptyMessage?: React.ReactNode;
    enablePagination?: boolean;
    defaultPageSize?: number;
    pageSizeOptions?: number[];
    searchValue?: string;
    onSearchChange?: (value: string) => void;
    searchPlaceholder?: string;
    enableSearch?: boolean;
    enableExpanding?: boolean;
    getRowCanExpand?: (row: any) => boolean;
    renderSubComponent?: (props: { row: any }) => React.ReactElement;
    showExpandAllButton?: boolean;
    enableColumnFilters?: boolean;
    initialColumnFilters?: ColumnFiltersState;
    showColumnFilters?: boolean;
    showActionButton?: boolean;
    renderActionButton?: ReactNode;
}

export default function DataTableClient<TData>({
    data,
    columns,
    initialSorting = [],
    enableMultiSort = false,
    className = "table-theme align-middle",
    emptyMessage = "No data available",
    enablePagination = false,
    defaultPageSize = 10,
    pageSizeOptions = [10, 20, 30, 40, 50],
    searchValue,
    onSearchChange,
    searchPlaceholder = "Search...",
    enableSearch = false,
    enableExpanding = false,
    getRowCanExpand = () => true,
    renderSubComponent,
    showExpandAllButton = true,
    enableColumnFilters = false,
    initialColumnFilters = [],
    showColumnFilters = false,
    showActionButton = false,
    renderActionButton,
}: DataTableClientProps<TData>) {
    const [sorting, setSorting] = useState<SortingState>(initialSorting);
    const [pageIndex, setPageIndex] = useState(0);
    const [pageSize, setPageSize] = useState(defaultPageSize);
    const [globalFilter, setGlobalFilter] = useState<string>(searchValue || "");
    const [expanded, setExpanded] = useState<ExpandedState>({});
    const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>(initialColumnFilters);
    const [showFilters, setShowFilters] = useState(false);

    // Sync external search value with internal state
    useEffect(() => {
        if (searchValue !== undefined) {
            setGlobalFilter(searchValue);
        }
    }, [searchValue]);

    // Create columns with expander if expanding is enabled
    const tableColumns = useMemo(() => {
        if (!enableExpanding) return columns;

        const expanderColumn: ColumnDef<TData, any> = {
            id: 'expander',
            header: () => null,
            size: 40,
            cell: ({ row }) => (
                row.getCanExpand() ? (
                    <div className="d-flex align-items-center justify-content-center">
                        <Button
                            variant="link"
                            size="sm"
                            className="btn-icon p-1 text-muted border-0"
                            onClick={row.getToggleExpandedHandler()}
                            style={{ lineHeight: 1 }}
                        >
                            {row.getIsExpanded() ? <PiCaretDown size={14} /> : <PiCaretRight size={14} />}
                        </Button>
                    </div>
                ) : null
            ),
        };

        return [expanderColumn, ...columns];
    }, [columns, enableExpanding]);

    const table = useReactTable({
        data,
        columns: tableColumns,
        state: {
            sorting,
            pagination: {
                pageIndex,
                pageSize,
            },
            globalFilter,
            expanded,
            columnFilters: enableColumnFilters ? columnFilters : undefined,
        },
        enableMultiSort,
        onSortingChange: setSorting,
        onGlobalFilterChange: setGlobalFilter,
        onExpandedChange: setExpanded,
        onColumnFiltersChange: enableColumnFilters ? setColumnFilters : undefined,
        getRowCanExpand: enableExpanding ? getRowCanExpand : undefined,
        globalFilterFn: 'includesString',
        getCoreRowModel: getCoreRowModel(),
        getSortedRowModel: getSortedRowModel(),
        getFilteredRowModel: getFilteredRowModel(),
        getExpandedRowModel: getExpandedRowModel(),
        getPaginationRowModel: getPaginationRowModel(),
    });

    // Create pagination meta for AppPagination
    const paginationMeta = useMemo(() => {
        const totalPages = table.getPageCount();
        const filteredRowCount = table.getFilteredRowModel().rows.length;
        return {
            current_page: pageIndex + 1,
            last_page: totalPages,
            per_page: pageSize,
            total: filteredRowCount,
            from: filteredRowCount ? pageIndex * pageSize + 1 : 0,
            to: Math.min((pageIndex + 1) * pageSize, filteredRowCount),
        };
    }, [pageIndex, pageSize, table.getPageCount(), table.getFilteredRowModel().rows.length]);

    // Handle external search value changes
    const handleSearchChange = (value: string) => {
        setGlobalFilter(value);
        setPageIndex(0); // Reset to first page when searching
        if (onSearchChange) {
            onSearchChange(value);
        }
    };

    // Expand/Collapse all functions
    const expandAll = () => {
        const expandedState: ExpandedState = {};
        table.getRowModel().rows.forEach(row => {
            if (row.getCanExpand()) {
                expandedState[row.id] = true;
            }
        });
        setExpanded(expandedState);
    };

    const collapseAll = () => {
        setExpanded({});
    };

    // Count expanded rows
    const expandedCount = useMemo(() => {
        return Object.values(expanded).filter(Boolean).length;
    }, [expanded]);

    // Column filter helpers
    const clearAllFilters = () => {
        setColumnFilters([]);
        setPageIndex(0);
    };

    const hasActiveFilters = columnFilters.length > 0;

    // Filter component for individual columns - memoized to prevent cursor blur
    const ColumnFilter = useCallback(({ column }: { column: any }) => {
        const firstValue = table.getPreFilteredRowModel().flatRows[0]?.getValue(column.id);
        const columnFilterValue = column.getFilterValue();

        return typeof firstValue === 'number' ? (
            <div className="d-flex gap-1">
                <Form.Control
                    type="number"
                    size="sm"
                    placeholder="Min"
                    value={(columnFilterValue as [number, number])?.[0] ?? ''}
                    onChange={(e) => {
                        const val = e.target.value;
                        column.setFilterValue((old: [number, number]) => [
                            val ? parseInt(val, 10) : undefined,
                            old?.[1]
                        ]);
                    }}
                />
                <Form.Control
                    type="number"
                    size="sm"
                    placeholder="Max"
                    value={(columnFilterValue as [number, number])?.[1] ?? ''}
                    onChange={(e) => {
                        const val = e.target.value;
                        column.setFilterValue((old: [number, number]) => [
                            old?.[0],
                            val ? parseInt(val, 10) : undefined
                        ]);
                    }}
                />
            </div>
        ) : (
            <Form.Control
                type="search"
                size="sm"
                placeholder="Filter..."
                value={(columnFilterValue ?? '') as string}
                onChange={(e) => column.setFilterValue(e.target.value)}
            />
        );
    }, [table]);

    return (
        <>
            {(enableSearch || (enableExpanding && showExpandAllButton) || enableColumnFilters) && (
                <div className="mb-3">
                    <div className="d-flex flex-wrap align-items-center justify-content-between gap-3 mb-3">
                        {enableSearch && (
                            <Form.Control
                                type="search"
                                placeholder={searchPlaceholder}
                                value={globalFilter}
                                onChange={(e) => handleSearchChange(e.target.value)}
                                style={{ maxWidth: '300px' }}
                            />
                        )}

                        <div className="d-flex flex-wrap align-items-center gap-2">
                            {showActionButton && renderActionButton}

                            {enableExpanding && showExpandAllButton && (
                                <>
                                    <Button
                                        variant="secondary-subtle"
                                        size="sm"
                                        onClick={expandAll}
                                        title="Expand All"
                                    >
                                        Expand All
                                    </Button>
                                    <Button
                                        variant="secondary-subtle"
                                        size="sm"
                                        onClick={collapseAll}
                                        title="Collapse All"
                                    >
                                        Collapse All
                                    </Button>
                                    {expandedCount > 0 && (
                                        <small className="text-muted ms-2">
                                            {expandedCount} expanded
                                        </small>
                                    )}
                                </>
                            )}

                            {enableColumnFilters && showColumnFilters && (
                                <>
                                    <Button
                                        variant={showFilters ? "primary" : "secondary-subtle"}
                                        size="sm"
                                        onClick={() => setShowFilters(!showFilters)}
                                        title="Toggle Column Filters"
                                        className="btn-icon-label"
                                    >
                                        <PiFunnel size={14} />
                                        <span>Filters</span>
                                    </Button>
                                    {hasActiveFilters && (
                                        <Button
                                            variant="danger-subtle"
                                            size="sm"
                                            onClick={clearAllFilters}
                                            title="Clear All Filters"
                                        >
                                            <PiXBold size={12} className="me-1" />
                                            Clear
                                        </Button>
                                    )}
                                    {hasActiveFilters && (
                                        <small className="text-muted">
                                            {columnFilters.length} filter{columnFilters.length !== 1 ? 's' : ''}
                                        </small>
                                    )}
                                </>
                            )}
                        </div>
                    </div>

                    {enableColumnFilters && showFilters && (
                        <div className="border rounded p-3 bg-light-subtle">
                            <Row className="g-3">
                                {table.getAllColumns()
                                    .filter(column =>
                                        column.getCanFilter() &&
                                        column.id !== 'expander' &&
                                        column.columnDef.enableColumnFilter !== false
                                    )
                                    .map(column => {
                                        // Get header label - handle both string and function headers
                                        let headerLabel = column.id;
                                        if (typeof column.columnDef.header === 'string') {
                                            headerLabel = column.columnDef.header;
                                        } else if (typeof column.columnDef.header === 'function') {
                                            const headerResult = column.columnDef.header({
                                                column: column,
                                                header: table.getHeaderGroups()[0].headers.find(h => h.column.id === column.id)!,
                                                table: table
                                            });
                                            // If header returns a string, use it
                                            if (typeof headerResult === 'string') {
                                                headerLabel = headerResult;
                                            }
                                            // If header returns JSX with text content, try to extract it
                                            else if (headerResult && typeof headerResult === 'object' && 'props' in headerResult) {
                                                if (headerResult.props.children) {
                                                    headerLabel = headerResult.props.children;
                                                }
                                            }
                                        }

                                        return (
                                            <Col key={column.id} sm={6} md={4} lg={3}>
                                                <Form.Label className="small fw-medium text-muted mb-1">
                                                    {headerLabel}
                                                </Form.Label>
                                                <ColumnFilter column={column} />
                                            </Col>
                                        );
                                    })
                                }
                            </Row>
                        </div>
                    )}
                </div>
            )}

            <BootstrapTable responsive hover className={className}>
                <thead>
                    {table.getHeaderGroups().map(headerGroup => (
                        <tr key={headerGroup.id}>
                            {headerGroup.headers.map(header => (
                                <th key={header.id} style={{ width: header.getSize() !== 150 ? header.getSize() : undefined }}>
                                    {header.isPlaceholder ? null : (
                                        <div
                                            className={
                                                header.column.getCanSort()
                                                    ? "cursor-pointer select-none d-flex align-items-center gap-2"
                                                    : "d-flex align-items-center gap-2"
                                            }
                                            onClick={header.column.getCanSort()
                                                ? () => header.column.toggleSorting()
                                                : undefined}
                                        >
                                            {flexRender(
                                                header.column.columnDef.header,
                                                header.getContext()
                                            )}
                                            {{
                                                asc: <PiCaretUpBold className="text-primary" />,
                                                desc: <PiCaretDownBold className="text-primary" />,
                                            }[header.column.getIsSorted() as string] ?? null}
                                        </div>
                                    )}
                                </th>
                            ))}
                        </tr>
                    ))}
                </thead>
                <tbody>
                    {table.getRowModel().rows.length > 0 ? (
                        table.getRowModel().rows.map(row => (
                            <Fragment key={row.id}>
                                <tr>
                                    {row.getVisibleCells().map(cell => (
                                        <td key={cell.id}>
                                            {flexRender(
                                                cell.column.columnDef.cell,
                                                cell.getContext()
                                            )}
                                        </td>
                                    ))}
                                </tr>
                                {enableExpanding && row.getIsExpanded() && renderSubComponent && (
                                    <tr key={`${row.id}-expanded`}>
                                        <td colSpan={tableColumns.length} className="p-0">
                                            {renderSubComponent({ row: row.original })}
                                        </td>
                                    </tr>
                                )}
                            </Fragment>
                        ))
                    ) : (
                        <tr>
                            <td colSpan={tableColumns.length} className="text-center py-4">
                                {emptyMessage}
                            </td>
                        </tr>
                    )}
                </tbody>
            </BootstrapTable>

            {enablePagination && paginationMeta.total > 0 && (
                <AppPagination
                    meta={paginationMeta}
                    onPageChange={(page) => setPageIndex(page - 1)}
                    onPerPageChange={(perPage) => {
                        setPageSize(perPage);
                        setPageIndex(0); // Reset to first page when changing page size
                    }}
                    perPageOptions={pageSizeOptions}
                />
            )}
        </>
    );
}
