import React, { useState, useEffect, useRef, useMemo } from "react";
import { router } from "@inertiajs/react";
import {
    Search,
    RotateCcw,
    ChevronLeft,
    ChevronRight,
    ChevronsLeft,
    ChevronsRight,
    FolderSearch,
    Loader2,
    ArrowUpDown,
    ArrowUp,
    ArrowDown,
    LucideIcon,
    Eye,
    Edit,
    Trash2,
} from "lucide-react";

import { Input } from "@/components/ui/input";
import { Button } from "@/components/ui/button";
import {
    Select,
    SelectContent,
    SelectItem,
    SelectTrigger,
    SelectValue,
} from "@/components/ui/select";
import {
    Table,
    TableBody,
    TableCell,
    TableHead,
    TableHeader,
    TableRow,
} from "@/components/ui/table";
import {
    Tooltip,
    TooltipContent,
    TooltipProvider,
    TooltipTrigger,
} from "@/components/ui/tooltip";

export type Column<T> = {
    header: string;
    accessor?: keyof T;
    cell?: (item: T, index?: number) => React.ReactNode;
    className?: string;
    headerClassName?: string;
    sortable?: boolean;
    sortKey?: string;
};

export type FilterConfig = {
    key: string;
    label: string;
    type?: "select" | "date";
    options?: { label: string; value: string | number }[];
    value: string;
    onChange: (value: string) => void;
};

export type PaginatedData<T> = {
    data: T[];
    current_page: number;
    last_page: number;
    per_page: number;
    total: number;
    from: number;
    to: number;
    links: { url: string | null; label: string; active: boolean }[];
};

interface DataTableProps<T> {
    data: PaginatedData<T>;
    columns: Column<T>[];
    searchPlaceholder?: string;
    searchValue?: string;
    onSearchChange?: (value: string) => void;
    filters?: FilterConfig[];
    baseUrl?: string;
    primaryKey?: keyof T;
    showNumber?: boolean;
    emptyTitle?: string;
    emptyDescription?: string;
    emptyIcon?: LucideIcon;
    actions?: (item: T) => React.ReactNode;
    onView?: (item: T) => void;
    onEdit?: (item: T) => void;
    onDelete?: (item: T) => void;
    useSkeleton?: boolean;
    showTooltip?: boolean;
}

export function DataTable<T extends Record<string, any>>({
    data,
    columns,
    searchPlaceholder = "Cari data...",
    searchValue = "",
    onSearchChange,
    filters = [],
    baseUrl,
    primaryKey = "id" as keyof T,
    showNumber = false,
    emptyTitle = "Data tidak ditemukan",
    emptyDescription = "Coba ubah kata kunci pencarian atau reset filter Anda.",
    emptyIcon: EmptyIcon = FolderSearch,
    actions,
    onView,
    onEdit,
    onDelete,
    useSkeleton = false,
    showTooltip = true,
}: DataTableProps<T>) {
    const [search, setSearch] = useState(searchValue);
    const [perPage, setPerPage] = useState(String(data?.per_page || 10));
    const [isLoading, setIsLoading] = useState(false);
    const [sort, setSort] = useState<{
        key: string;
        direction: "asc" | "desc" | "";
    }>({
        key: "",
        direction: "",
    });

    const isInitialRender = useRef(true);
    const searchDebounceTimer = useRef<ReturnType<typeof setTimeout> | null>(
        null,
    );

    const renderActionButton = (buttonEl: React.ReactNode, label: string) => {
        if (!showTooltip) return buttonEl;

        return (
            <Tooltip>
                <TooltipTrigger asChild>{buttonEl}</TooltipTrigger>
                <TooltipContent side="top">
                    <p className="text-xs">{label}</p>
                </TooltipContent>
            </Tooltip>
        );
    };

    const renderDefaultActions = (item: T) => (
        <div className="flex items-center justify-center gap-1">
            {onView &&
                renderActionButton(
                    <Button
                        variant="ghost"
                        size="icon"
                        onClick={() => onView(item)}
                        className="h-8 w-8 text-muted-foreground hover:text-indigo-600 hover:bg-indigo-50 rounded-lg transition-colors"
                    >
                        <Eye className="h-4 w-4" />
                    </Button>,
                    "Lihat Detail",
                )}

            {onEdit &&
                renderActionButton(
                    <Button
                        variant="ghost"
                        size="icon"
                        onClick={() => onEdit(item)}
                        className="h-8 w-8 text-muted-foreground hover:text-amber-600 hover:bg-amber-50 rounded-lg transition-colors"
                    >
                        <Edit className="h-4 w-4" />
                    </Button>,
                    "Edit",
                )}

            {onDelete &&
                renderActionButton(
                    <Button
                        variant="ghost"
                        size="icon"
                        onClick={() => onDelete(item)}
                        className="h-8 w-8 text-muted-foreground hover:text-rose-600 hover:bg-rose-50 rounded-lg transition-colors"
                    >
                        <Trash2 className="h-4 w-4" />
                    </Button>,
                    "Hapus",
                )}
        </div>
    );

    const finalColumns: Column<T>[] = useMemo(() => {
        let cols = [...columns];

        if (showNumber) {
            const numberColumn: Column<T> = {
                header: "No",
                className: "w-12 text-center",
                headerClassName:
                    "w-12 text-center text-foreground/80 font-semibold",
                cell: (_, index) => (data?.from || 1) + (index ?? 0),
            };
            cols = [numberColumn, ...cols];
        }

        const hasActions = actions || onView || onEdit || onDelete;
        if (hasActions) {
            const actionColumn: Column<T> = {
                header: "Aksi",
                headerClassName: "text-center",
                className: "text-center w-28",
                cell: (item) =>
                    actions ? actions(item) : renderDefaultActions(item),
            };
            cols = [...cols, actionColumn];
        }

        return cols;
    }, [
        columns,
        showNumber,
        actions,
        onView,
        onEdit,
        onDelete,
        data?.from,
        showTooltip,
    ]);

    const applyFilters = (extraParams: Record<string, any> = {}) => {
        const targetUrl = baseUrl || window.location.pathname;
        setIsLoading(true);

        const filterParams: Record<string, any> = {};
        filters.forEach((f) => {
            if (f.value && f.value !== "all") filterParams[f.key] = f.value;
        });

        router.get(
            targetUrl,
            {
                search,
                per_page: perPage,
                sort_by: sort.key || undefined,
                sort_dir: sort.direction || undefined,
                ...filterParams,
                ...extraParams,
            },
            {
                preserveState: true,
                replace: true,
                onFinish: () => setIsLoading(false),
            },
        );
    };

    useEffect(() => {
        if (isInitialRender.current) {
            isInitialRender.current = false;
            return;
        }

        if (searchDebounceTimer.current) {
            clearTimeout(searchDebounceTimer.current);
        }

        searchDebounceTimer.current = setTimeout(() => {
            applyFilters({ search, page: 1 });
        }, 500);

        return () => {
            if (searchDebounceTimer.current) {
                clearTimeout(searchDebounceTimer.current);
            }
        };
    }, [search]);

    const handleSort = (column: Column<T>) => {
        if (!column.sortable) return;
        const key = column.sortKey || (column.accessor as string);
        if (!key) return;

        let nextDirection: "asc" | "desc" | "" = "asc";
        if (sort.key === key) {
            if (sort.direction === "asc") nextDirection = "desc";
            else if (sort.direction === "desc") nextDirection = "";
        }

        const newSort = {
            key: nextDirection ? key : "",
            direction: nextDirection,
        };
        setSort(newSort);
        applyFilters({
            sort_by: newSort.key || undefined,
            sort_dir: newSort.direction || undefined,
            page: 1,
        });
    };

    const handlePerPageChange = (val: string) => {
        setPerPage(val);
        applyFilters({ per_page: val, page: 1 });
    };

    const handleReset = () => {
        if (searchDebounceTimer.current) {
            clearTimeout(searchDebounceTimer.current);
        }

        setSearch("");
        setSort({ key: "", direction: "" });
        filters.forEach((f) => f.onChange(""));

        const targetUrl = baseUrl || window.location.pathname;
        setIsLoading(true);

        router.get(
            targetUrl,
            {},
            {
                preserveState: true,
                replace: true,
                onFinish: () => setIsLoading(false),
            },
        );
    };

    const hasActiveFilters = Boolean(
        (search && search.trim() !== "") ||
        filters.some(
            (f) =>
                f.value !== undefined &&
                f.value !== null &&
                String(f.value).trim() !== "" &&
                String(f.value) !== "all",
        ) ||
        sort.key,
    );

    const getPageNumbers = () => {
        const current = data?.current_page || 1;
        const last = data?.last_page || 1;
        const delta = 1;
        const range = [];
        for (
            let i = Math.max(2, current - delta);
            i <= Math.min(last - 1, current + delta);
            i++
        ) {
            range.push(i);
        }

        if (current - delta > 2) range.unshift("...");
        if (current + delta < last - 1) range.push("...");

        range.unshift(1);
        if (last > 1) range.push(last);
        return [...new Set(range)];
    };

    return (
        <TooltipProvider>
            <div className="space-y-4">
                {/* Control Bar */}
                <div className="flex flex-col gap-3 lg:flex-row lg:items-center lg:justify-between">
                    <div className="flex flex-1 flex-wrap items-center gap-2">
                        <div className="relative flex-1 min-w-50 max-w-sm">
                            <Search className="absolute left-3 top-1/2 size-4 -translate-y-1/2 text-muted-foreground/80" />
                            <Input
                                placeholder={searchPlaceholder}
                                value={search}
                                onChange={(e) => {
                                    setSearch(e.target.value);
                                    onSearchChange?.(e.target.value);
                                }}
                                className="pl-9 rounded-xl bg-card"
                            />
                        </div>

                        {filters.map((filter) =>
                            filter.type === "date" ? (
                                <Input
                                    key={filter.key}
                                    type="date"
                                    value={filter.value || ""}
                                    onChange={(e) => {
                                        const newValue = e.target.value;
                                        filter.onChange(newValue);
                                        applyFilters({
                                            [filter.key]: newValue,
                                            page: 1,
                                        });
                                    }}
                                    className="w-40 rounded-xl bg-card text-xs text-muted-foreground"
                                />
                            ) : (
                                <Select
                                    key={filter.key}
                                    value={filter.value || "all"}
                                    onValueChange={(val) => {
                                        const newValue =
                                            val === "all" ? "" : val;
                                        filter.onChange(newValue);
                                        applyFilters({
                                            [filter.key]: newValue,
                                            page: 1,
                                        });
                                    }}
                                >
                                    <SelectTrigger className="w-auto min-w-45 rounded-xl bg-card">
                                        <SelectValue
                                            placeholder={filter.label}
                                        />
                                    </SelectTrigger>
                                    <SelectContent>
                                        <SelectItem value="all">
                                            Semua {filter.label}
                                        </SelectItem>
                                        {filter.options?.map((opt) => (
                                            <SelectItem
                                                key={opt.value}
                                                value={String(opt.value)}
                                            >
                                                {opt.label}
                                            </SelectItem>
                                        ))}
                                    </SelectContent>
                                </Select>
                            ),
                        )}

                        {hasActiveFilters && (
                            <Button
                                type="button"
                                variant="ghost"
                                onClick={handleReset}
                                className="rounded-xl text-muted-foreground hover:text-foreground"
                            >
                                <RotateCcw className="size-4 mr-1" /> Reset
                            </Button>
                        )}
                    </div>

                    <div className="flex items-center gap-2 self-end lg:self-auto">
                        <span className="text-xs font-medium text-muted-foreground">
                            Tampilkan:
                        </span>
                        <Select
                            value={perPage}
                            onValueChange={handlePerPageChange}
                        >
                            <SelectTrigger className="w-20 rounded-xl bg-card">
                                <SelectValue />
                            </SelectTrigger>
                            <SelectContent>
                                <SelectItem value="10">10</SelectItem>
                                <SelectItem value="20">20</SelectItem>
                                <SelectItem value="50">50</SelectItem>
                                <SelectItem value="100">100</SelectItem>
                            </SelectContent>
                        </Select>
                    </div>
                </div>

                {/* Table Container dengan h-auto */}
                <div className="relative h-auto">
                    {isLoading && !useSkeleton && (
                        <div className="absolute inset-0 bg-card/70 backdrop-blur-[1px] z-30 flex items-center justify-center rounded-2xl transition-all">
                            <Loader2 className="size-8 animate-spin text-indigo-600" />
                        </div>
                    )}

                    <div className="overflow-hidden rounded-2xl border border-border bg-card shadow-sm">
                        <Table>
                            <TableHeader className="bg-muted/50 text-[11px] font-semibold uppercase tracking-wide text-muted-foreground">
                                <TableRow>
                                    {finalColumns.map((col, index) => {
                                        const currentKey =
                                            col.sortKey ||
                                            (col.accessor as string);
                                        const isSorted =
                                            sort.key && sort.key === currentKey;

                                        return (
                                            <TableHead
                                                key={index}
                                                onClick={() => handleSort(col)}
                                                className={`${
                                                    col.headerClassName ||
                                                    "w-12 text-center text-foreground/80 font-semibold whitespace-nowrap"
                                                } ${col.sortable ? "cursor-pointer select-none hover:bg-muted/80" : ""}`}
                                            >
                                                <div className="inline-flex items-center gap-1.5">
                                                    <span>{col.header}</span>
                                                    {col.sortable && (
                                                        <span className="text-muted-foreground/80">
                                                            {isSorted ? (
                                                                sort.direction ===
                                                                "asc" ? (
                                                                    <ArrowUp className="size-3 text-indigo-600" />
                                                                ) : (
                                                                    <ArrowDown className="size-3 text-indigo-600" />
                                                                )
                                                            ) : (
                                                                <ArrowUpDown className="size-3 opacity-60" />
                                                            )}
                                                        </span>
                                                    )}
                                                </div>
                                            </TableHead>
                                        );
                                    })}
                                </TableRow>
                            </TableHeader>
                            <TableBody>
                                {isLoading && useSkeleton ? (
                                    Array.from({
                                        length: Number(perPage) || 5,
                                    }).map((_, rIdx) => (
                                        <TableRow
                                            key={rIdx}
                                            className="animate-pulse"
                                        >
                                            {finalColumns.map((_, cIdx) => (
                                                <TableCell key={cIdx}>
                                                    <div className="h-4 bg-slate-200/80 rounded-md w-full my-1"></div>
                                                </TableCell>
                                            ))}
                                        </TableRow>
                                    ))
                                ) : data?.data && data.data.length > 0 ? (
                                    data.data.map((item, index) => (
                                        <TableRow
                                            key={String(
                                                item[primaryKey] ?? index,
                                            )}
                                            className="hover:bg-muted/50/50"
                                        >
                                            {finalColumns.map((col, cIndex) => (
                                                <TableCell
                                                    key={cIndex}
                                                    className={col.className}
                                                >
                                                    {col.cell
                                                        ? col.cell(item, index)
                                                        : col.accessor
                                                          ? typeof item[
                                                                col.accessor
                                                            ] === "object" &&
                                                            item[
                                                                col.accessor
                                                            ] !== null
                                                              ? (
                                                                    item[
                                                                        col
                                                                            .accessor
                                                                    ] as any
                                                                )?.name || "-"
                                                              : (item[
                                                                    col.accessor
                                                                ] as React.ReactNode)
                                                          : null}
                                                </TableCell>
                                            ))}
                                        </TableRow>
                                    ))
                                ) : (
                                    <TableRow>
                                        <TableCell
                                            colSpan={finalColumns.length}
                                            className="h-40 text-center text-muted-foreground/80"
                                        >
                                            <div className="flex flex-col items-center justify-center space-y-2 py-6">
                                                <div className="rounded-full bg-muted p-3 text-muted-foreground/80">
                                                    <EmptyIcon className="size-6" />
                                                </div>
                                                <p className="text-xs font-semibold text-muted-foreground">
                                                    {emptyTitle}
                                                </p>
                                                <p className="text-[11px] text-muted-foreground/80 max-w-sm">
                                                    {emptyDescription}
                                                </p>
                                            </div>
                                        </TableCell>
                                    </TableRow>
                                )}
                            </TableBody>
                        </Table>
                    </div>

                    {/* Pagination */}
                    <div className="mt-4 flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between px-1">
                        <p className="text-xs text-muted-foreground">
                            Menampilkan{" "}
                            <span className="font-semibold text-foreground/80">
                                {data?.from || 0}
                            </span>{" "}
                            -{" "}
                            <span className="font-semibold text-foreground/80">
                                {data?.to || 0}
                            </span>{" "}
                            dari{" "}
                            <span className="font-semibold text-foreground/80">
                                {data?.total || 0}
                            </span>{" "}
                            data
                        </p>

                        <div className="flex items-center gap-1">
                            <Button
                                variant="outline"
                                size="icon"
                                disabled={data?.current_page === 1}
                                onClick={() => applyFilters({ page: 1 })}
                                className="size-8 rounded-lg"
                            >
                                <ChevronsLeft className="size-4" />
                            </Button>
                            <Button
                                variant="outline"
                                size="icon"
                                disabled={data?.current_page === 1}
                                onClick={() =>
                                    applyFilters({
                                        page: (data?.current_page || 1) - 1,
                                    })
                                }
                                className="size-8 rounded-lg"
                            >
                                <ChevronLeft className="size-4" />
                            </Button>

                            <div className="hidden md:flex items-center gap-1 px-1">
                                {getPageNumbers().map((page, idx) =>
                                    page === "..." ? (
                                        <span
                                            key={idx}
                                            className="px-2 text-xs text-muted-foreground/80"
                                        >
                                            ...
                                        </span>
                                    ) : (
                                        <Button
                                            key={idx}
                                            variant={
                                                data?.current_page === page
                                                    ? "default"
                                                    : "outline"
                                            }
                                            size="sm"
                                            onClick={() =>
                                                applyFilters({ page })
                                            }
                                            className={`h-8 w-8 rounded-lg text-xs font-medium ${
                                                data?.current_page === page
                                                    ? "bg-indigo-600 text-white hover:bg-indigo-700"
                                                    : "text-muted-foreground"
                                            }`}
                                        >
                                            {page}
                                        </Button>
                                    ),
                                )}
                            </div>

                            <span className="px-3 text-xs font-medium text-muted-foreground md:hidden">
                                {data?.current_page || 1} /{" "}
                                {data?.last_page || 1}
                            </span>

                            <Button
                                variant="outline"
                                size="icon"
                                disabled={
                                    data?.current_page === data?.last_page
                                }
                                onClick={() =>
                                    applyFilters({
                                        page: (data?.current_page || 1) + 1,
                                    })
                                }
                                className="size-8 rounded-lg"
                            >
                                <ChevronRight className="size-4" />
                            </Button>
                            <Button
                                variant="outline"
                                size="icon"
                                disabled={
                                    data?.current_page === data?.last_page
                                }
                                onClick={() =>
                                    applyFilters({ page: data?.last_page })
                                }
                                className="size-8 rounded-lg"
                            >
                                <ChevronsRight className="size-4" />
                            </Button>
                        </div>
                    </div>
                </div>
            </div>
        </TooltipProvider>
    );
}
