"use client";
import { InnerCard } from "@/components/menu-slider";
import { Person } from "@/components/tanstack-table/makeData";
import { getCustomerTableColumns } from "@/constant";
import useColumnVisibility from "@/hooks/useColumnVisibility";
import usePagination from "@/hooks/usePagination";
import useRowSelection from "@/hooks/useRowSelection";
import useTable from "@/hooks/useTable";
import Axios from "@/lib/Axios";
import useMenuSliderStore from "@/store/useMenuSliderStore";
import { CustomerDataT } from "@/types/customer";
import { PaginationStructT } from "@/types/global";
import { UserListT } from "@/types/user";
import { useMutation, useQuery } from "@tanstack/react-query";
import React, { useEffect, useMemo, useState, useRef, useCallback } from "react";
import Link from "next/link";
import { Button } from "@/components/ui/button";
import { Check, Filter, FilterX, Loader, Plus, Upload } from "lucide-react";
import { Input } from "@/components/ui/input";
import useGlobalSearchStore from "@/store/useGlobalSearchStore";
import { useDebounce } from "use-debounce";
import { useCustomerStore } from "@/store/useCustomerStore";
import { Combobox } from "@/components/combobox";
import { SearchReportTo } from "@/components/pages/add-emp/searchReportTo";
import { toast } from "@/components/ui/use-toast";
import { AxiosError, AxiosResponse } from "axios";
import { RespError } from "@/types/auth";
import { cn } from "@/lib/utils";
import { useRouter } from "next/navigation";
import useUserStore from "@/store/useUserStore";
import { ImportCustomersDialog } from "@/components/pages/customer/ImportCustomersDialog";

type TableHydrateT = {
  offset: number;
  limit: number;
  initData?: PaginationStructT<UserListT[]> | null;
};

const fallBack: any[] = [];

export default function CustomerTable({
  offset = 0,
  limit = 10, // This is now ignored for fetching, but can be used for initial visible count
  initData,
}: TableHydrateT) {
  const { pagination, setPagination } = usePagination(
    Number(offset),
    Number(limit)
  );
  const { rowSelection, setRowSelection } = useRowSelection();
  const [_, setData] = React.useState<Person[]>(() => []);

  const { gSearch, setGSearch } = useGlobalSearchStore();
  const [scope, setScope] = useState<string[]>([]);
  const [debouncedSearchQuery] = useDebounce(gSearch, 500);
  const [debouncedScopeQuery] = useDebounce(scope, 500);

  const [allData, setAllData] = useState<CustomerDataT[]>([]);
  const [totalCount, setTotalCount] = useState<number>(0);
  const tableContainerRef = useRef<HTMLDivElement>(null);
  const loadMoreRef = useRef<HTMLDivElement>(null);
  const [isLoading, setIsLoading] = useState(true);
  const [isLoadingMore, setIsLoadingMore] = useState(false);
  const [hasMore, setHasMore] = useState(true);
  const [currentOffset, setCurrentOffset] = useState(0);
  const [isImportDialogOpen, setIsImportDialogOpen] = useState(false);
  const isLoadingMoreRef = useRef(false);
  const PAGE_SIZE = 30;
  
  // Get user data for admin check
  const userData = useUserStore((state) => state.data);
  const canImportCustomers = userData?.role === 'Admin' || userData?.role === 'Owner';

  const { columnVisibility, setColumnVisibility } = useColumnVisibility();
  const { columns } = useMemo(
    () => getCustomerTableColumns(async () => {}),
    []
  );

  const tableData = useMemo(() => allData ?? fallBack, [allData]);
  const { setInnerElement, setOptionsElement, open } = useMenuSliderStore();
  const { customers, setCustomers } = useCustomerStore();

  useEffect(() => {
    console.log(rowSelection);
    setCustomers(Object.keys(rowSelection).map(Number));
  }, [rowSelection]);
    const router = useRouter();

  const rowHandler = ({ id }: CustomerDataT) => {
    // setColumnVisibility({
    //   action: false,
    // });
    // setInnerElement(CustomerMenuDetails(data, refetch));
    // setOptionsElement(Options(data));
    // MenuSliderHandler();
    // setColumnVisibility({
    //   action: true,
    // });
  };

  // Fetch customers with pagination
  const fetchCustomers = useCallback(async (offset: number, limit: number, append: boolean = false, searchQuery?: string, searchScope?: string[]) => {
    if (append) {
      if (isLoadingMoreRef.current) return; // Prevent duplicate calls
      isLoadingMoreRef.current = true;
      setIsLoadingMore(true);
    } else {
      setIsLoading(true);
    }
    try {
      const params: any = {
        offset: offset,
        limit: limit,
      };
      
      // Add search parameter if provided
      if (searchQuery && searchQuery.trim()) {
        params.search = searchQuery.trim();
        // When searching, fetch all results (use large limit)
        params.limit = 10000;
        params.offset = 0;
        
        // Add scope filters if provided
        if (searchScope && searchScope.length > 0) {
          params.scope = searchScope.join(',');
        }
      }
      
      const resp = await Axios.get<any>("/customer/management/", {
        params,
      });
      
      // Handle both response structures (count from PaginationStructT or total from backend)
      const fetchedTotalCount = resp.data.count || resp.data.total || 0;
      const newData = resp.data.data || [];
      
      // Update total count state
      setTotalCount(fetchedTotalCount);
      
      console.log("Fetch customers:", { 
        offset, 
        limit, 
        newDataLength: newData.length, 
        fetchedTotalCount, 
        append,
        currentOffset 
      });
      
      // When searching, we fetch all results at once, so no appending needed
      if (searchQuery && searchQuery.trim()) {
        setAllData(newData);
        setHasMore(false); // No more to load when searching (we got all results)
        setCurrentOffset(newData.length);
      } else if (append) {
        setAllData((prev) => {
          const updated = [...prev, ...newData];
          // Check if there are more items to load
          const hasMoreData = updated.length < fetchedTotalCount;
          console.log("Appending data:", { 
            prevLength: prev.length, 
            newLength: newData.length, 
            updatedLength: updated.length, 
            fetchedTotalCount, 
            hasMoreData 
          });
          setHasMore(hasMoreData);
          return updated;
        });
        setCurrentOffset(offset + newData.length);
      } else {
        setAllData(newData);
        // Check if there are more items to load
        const hasMoreData = newData.length < fetchedTotalCount;
        console.log("Initial load:", { 
          newDataLength: newData.length, 
          fetchedTotalCount, 
          hasMoreData 
        });
        setHasMore(hasMoreData);
        setCurrentOffset(offset + newData.length);
      }
    } catch (e) {
      console.error("Error fetching customers:", e);
    } finally {
      setIsLoading(false);
      setIsLoadingMore(false);
      isLoadingMoreRef.current = false;
    }
  }, []);

  // Fetch initial customers on mount (only if no search query)
  useEffect(() => {
    if (!debouncedSearchQuery) {
      fetchCustomers(0, PAGE_SIZE, false);
    }
  }, [fetchCustomers, debouncedSearchQuery]);

  // Handle search - fetch all results when search query or scope changes
  useEffect(() => {
    if (debouncedSearchQuery && debouncedSearchQuery.trim()) {
      // When searching, fetch all results from API
      fetchCustomers(0, 10000, false, debouncedSearchQuery, debouncedScopeQuery);
    } else if (debouncedSearchQuery === '') {
      // When search is cleared, reset to initial pagination
      setAllData([]);
      setCurrentOffset(0);
      setHasMore(true);
      fetchCustomers(0, PAGE_SIZE, false);
    }
  }, [debouncedSearchQuery, debouncedScopeQuery, fetchCustomers]);

  // Intersection Observer - primary method for detecting when to load more
  // Disable when searching (we load all results at once)
  useEffect(() => {
    const observerTarget = loadMoreRef.current;
    if (!observerTarget || isLoading || isLoadingMore || !hasMore || debouncedSearchQuery) return;

    let observer: IntersectionObserver | null = null;

    // Use a small delay to ensure DOM is ready
    const timeoutId = setTimeout(() => {
      // Find the scrollable container (tbody, container, or viewport)
      const container = tableContainerRef.current;
      const table = container?.querySelector('#tanstack-table');
      const tbody = table?.querySelector('tbody');
      
      // Try tbody first, then container, then viewport (null)
      let rootElement: Element | null = null;
      if (tbody && tbody.scrollHeight > tbody.clientHeight) {
        rootElement = tbody;
        console.log("Using tbody as root for Intersection Observer");
      } else if (container && container.scrollHeight > container.clientHeight) {
        rootElement = container;
        console.log("Using container as root for Intersection Observer");
      } else {
        console.log("Using viewport as root for Intersection Observer");
      }

      observer = new IntersectionObserver(
        (entries) => {
          const firstEntry = entries[0];
          console.log("Intersection Observer triggered:", { 
            isIntersecting: firstEntry.isIntersecting, 
            isLoadingMore: isLoadingMoreRef.current, 
            hasMore,
            currentOffset,
            rootElement: rootElement?.tagName 
          });
          if (firstEntry.isIntersecting && !isLoadingMoreRef.current && hasMore) {
            console.log("Loading more via Intersection Observer");
            fetchCustomers(currentOffset, PAGE_SIZE, true);
          }
        },
        {
          root: rootElement,
          rootMargin: "500px", // Start loading 500px before reaching the bottom (more aggressive)
          threshold: 0.01, // Lower threshold for earlier trigger
        }
      );

      observer.observe(observerTarget);
    }, 100);

    return () => {
      clearTimeout(timeoutId);
      if (observer) {
        observer.disconnect();
      }
    };
  }, [currentOffset, isLoading, isLoadingMore, hasMore, fetchCustomers, allData.length]);

  // Fallback scroll handler - checks multiple scrollable containers
  // Disable when searching (we load all results at once)
  useEffect(() => {
    if (isLoading || isLoadingMore || !hasMore || debouncedSearchQuery) return;

    const handleScroll = () => {
      if (isLoadingMoreRef.current || !hasMore) return;

      // Find the actual scrollable container
      const container = tableContainerRef.current;
      const table = container?.querySelector('#tanstack-table');
      const tbody = table?.querySelector('tbody');
      
      let scrollTop = 0;
      let scrollHeight = 0;
      let clientHeight = 0;

      // Check tbody first (most likely scrollable)
      if (tbody && tbody.scrollHeight > tbody.clientHeight) {
        scrollTop = tbody.scrollTop;
        scrollHeight = tbody.scrollHeight;
        clientHeight = tbody.clientHeight;
      }
      // Check container
      else if (container && container.scrollHeight > container.clientHeight) {
        scrollTop = container.scrollTop;
        scrollHeight = container.scrollHeight;
        clientHeight = container.clientHeight;
      }
      // Check window
      else {
        scrollTop = window.scrollY || document.documentElement.scrollTop;
        scrollHeight = document.documentElement.scrollHeight;
        clientHeight = window.innerHeight;
      }

      // Load more when near bottom (within 500px for earlier trigger - more aggressive)
      const isNearBottom = scrollTop + clientHeight >= scrollHeight - 500;
      const distanceFromBottom = scrollHeight - (scrollTop + clientHeight);
      console.log("Scroll handler:", { 
        scrollTop, 
        scrollHeight, 
        clientHeight, 
        distanceFromBottom,
        isNearBottom, 
        isLoadingMore: isLoadingMoreRef.current, 
        hasMore,
        currentOffset,
        scrollableElement: tbody ? 'tbody' : container ? 'container' : 'window'
      });
      if (isNearBottom && !isLoadingMoreRef.current && hasMore) {
        console.log("Loading more via scroll handler");
        fetchCustomers(currentOffset, PAGE_SIZE, true);
      }
    };

    // Attach listeners to all potential scroll containers
    const container = tableContainerRef.current;
    const table = container?.querySelector('#tanstack-table');
    const tbody = table?.querySelector('tbody');

    if (tbody) {
      tbody.addEventListener("scroll", handleScroll);
    }
    if (container) {
      container.addEventListener("scroll", handleScroll);
    }
    window.addEventListener("scroll", handleScroll);

    return () => {
      if (tbody) {
        tbody.removeEventListener("scroll", handleScroll);
      }
      if (container) {
        container.removeEventListener("scroll", handleScroll);
      }
      window.removeEventListener("scroll", handleScroll);
    };
  }, [currentOffset, isLoading, isLoadingMore, hasMore, fetchCustomers, debouncedSearchQuery]);

  // Fetch all customers - made reusable for refresh after import
  const fetchAllCustomers = useCallback(async () => {
    setAllData([]);
    setCurrentOffset(0);
    setHasMore(true);
    await fetchCustomers(0, PAGE_SIZE, false);
  }, [fetchCustomers]);

  // Reset visibleCount if search/filter changes (optional, if you add search)
  // useEffect(() => { setVisibleCount(30); }, [search/filter state]);

  type Filter = {
    key: string;
    name?: string;
  };

  const filters: Filter[] = [
    {
      key: "first_name",
      name: "First Name",
    },
    {
      key: "last_name",
      name: "Last Name",
    },
    {
      key: "email",
      name: "Email",
    },
    {
      key: "mobile_phone",
      name: "Mobile Phone",
    },
    {
      key: "home_phone",
      name: "Home Phone",
    },
    {
      key: "assigned_to__user__name",
      name: "Assigned to",
    },
    {
      key: "created_by",
      name: "Created By",
    },
    {
      key: "id",
      name: "Customer Id",
    },
    {
      key: "address__post_code",
      name: "Postal code",
    },
  ];

  // When searching, we fetch all results from API, so no client-side filtering needed
  // When not searching, show all loaded data
  const filteredData = useMemo(() => {
    // If searching, API already returns filtered results, so just return allData
    // If not searching, return all loaded data (pagination)
    return allData;
  }, [allData]);

  const { Table, table } = useTable({
    setPagination,
    pagination,
    columns,
    data: filteredData, // Show all loaded data
    setData,
    rowSelection,
    setRowSelection,
    columnVisibility,
    setColumnVisibility,
    onRowClick: rowHandler,
    rowCount: filteredData.length,
  });

  useEffect(() => {}, [columnVisibility]);

  const [isFilterOpen, setFilterOpenState] = useState<boolean>(false);

  return (
    <div className="w-full" ref={tableContainerRef} style={{ maxHeight: "70vh", overflowY: "auto" }}>
      <div className="my-5 flex gap-1 items-center justify-between">
        <div className="flex gap-2 items-center">
          <Link href="/customer/customer-manage">
            <Button className="bg-brownish hover:bg-yellowish">
              <p className="mr-2">Add Customer</p> <Plus />
            </Button>
          </Link>
          {!isLoading && totalCount > 0 && (
            <div className="ml-4 text-sm font-medium text-gray-700">
              Total Customers: <span className="font-bold text-brownish">{totalCount}</span>
            </div>
          )}

          <div className="ml-10 w-96 space-y-2">
            <div className="flex items-center border-2 rounded-md">
              <Input
                className="border-none"
                placeholder="search"
                onChange={(e) => setGSearch(e.currentTarget.value)}
              />
              <div
                onClick={() => setFilterOpenState(!isFilterOpen)}
                className="bg-brownish p-2 rounded-md text-white cursor-pointer select-none"
              >
                {!isFilterOpen ? <Filter /> : <FilterX />}
              </div>
            </div>
            {isFilterOpen ? (
              <div className="flex flex-wrap gap-1">
                {filters.map(({ name, key }, i) => (
                  <Chip
                    key={i}
                    name={name ?? ""}
                    onSelectChange={(isSelected) => {
                      if (isSelected) setScope((prev) => [...prev, key]);
                      else setScope((prev) => prev.filter((i) => i !== key));
                    }}
                  />
                ))}
              </div>
            ) : null}
          </div>

          
          
        </div>
        { canImportCustomers && (
          <Button
            onClick={() => setIsImportDialogOpen(true)}
            className="ml-auto bg-brownish hover:bg-yellowish rounded-md text-white text-center p-2 flex items-center gap-2 mx-2"
          >
            <Upload className="w-4 h-4" />
            <p className="mr-2">Import Customers</p>
          </Button>
        )}

        {/* Import Dialog */}
        <ImportCustomersDialog
          open={isImportDialogOpen}
          onClose={() => setIsImportDialogOpen(false)}
          onSuccess={() => {
            fetchAllCustomers(); // Refresh table after successful import
          }}
        />


        {customers && customers.length != 0 ? (
          <InnerCard>
            <p className="text-danger text-xl underline mb-2">Assign to</p>
            <AssignToOption
              customers={customers}
              reset={() => setRowSelection({})}
            />
          </InnerCard>
        ) : null}
      </div>
      <div className="relative">
        {isLoading ? (
          <div className="text-center py-2">
            {debouncedSearchQuery ? "Searching for the customer..." : "Loading..."}
          </div>
        ) : (
            <>
              <Table />
              {/* Sentinel element for Intersection Observer - triggers load more (only when not searching) */}
              {hasMore && !debouncedSearchQuery && (
                <div 
                  ref={loadMoreRef} 
                  className="h-20 flex items-center justify-center"
                  style={{ minHeight: '80px' }}
                />
              )}
              {isLoadingMore && (
                <div className="text-center py-4">
                  <Loader className="animate-spin mx-auto" />
                  <p className="text-sm text-gray-500 mt-2">Loading more...</p>
                </div>
              )}
              {!hasMore && allData.length > 0 && !debouncedSearchQuery && (
                <div className="text-center py-4 text-sm text-gray-500">
                  No more customers to load
                </div>
              )}
              {debouncedSearchQuery && allData.length > 0 && (
                <div className="text-center py-4 text-sm text-gray-500">
                  Showing {allData.length} search result{allData.length !== 1 ? 's' : ''}
                </div>
              )}
            </>
        )}
      </div>
    </div>
  );
}

interface ChipProps {
  name: string;
  onSelectChange: (val: boolean) => void;
}

function Chip({ name, onSelectChange }: ChipProps) {
  const [isSelected, setSelected] = useState<boolean>(false);

  useEffect(() => {
    console.log("::HELLO::", "SOME SELECTION IS CHANGED");
    onSelectChange(isSelected);
  }, [isSelected]);

  function handleSelected(
    event: React.MouseEvent<HTMLDivElement, MouseEvent>
  ): void {
    setSelected(!isSelected);
  }

  return (
    <div
      className={cn(
        "border-brownish border-2 text-brownish text-xs px-2 py-1 rounded-md cursor-pointer select-none focus-visible:bg-white"
      )}
      onClick={handleSelected}
    >
      <div className="flex space-x-1">
        {isSelected ? <Check size={15} /> : null}
        <span>{name}</span>
      </div>
    </div>
  );
}

function AssignToOption({
  customers,
  reset,
}: {
  customers: number[];
  reset: () => void;
}) {
  const { setCustomers } = useCustomerStore();

  const mutationSend = useMutation<
    AxiosResponse<any>,
    AxiosError<RespError>,
    any
  >({
    mutationFn: sendData,
    onSuccess: (data) => {
      toast({
        title: "Success",
        description: "Customer has been saved successfully",
      });
      setCustomers([]);
      reset();
    },
    onError: (error) => {
      const errorObj: Record<any, string[]> = error.response?.data.data!;
      let message = "";
      for (let key in errorObj) {
        if (errorObj.hasOwnProperty(key)) {
          let value = errorObj[key];
          message += key + " " + value[0] + "\n";
        }
      }
      toast({
        variant: "destructive",
        title: "Error",
        description: message,
      });
    },
  });

  function sendData(id?: number) {
    const data = {
      customer_ids: customers,
      assigned_to_id: id,
    };

    return Axios.patch("/customer/management/bulk_assign/", data);
  }

  return (
    <div className="flex items-center gap-2">
      <Combobox<UserListT>
        placeholder={"Assign to"}
        onSelect={(e) => {
          console.log(e);
          if (e === null) {
            return;
          }
          mutationSend.mutate(e.id);
        }}
      >
        <SearchReportTo />
      </Combobox>
      {mutationSend.isPending && (
        <Loader className="text-white animate-spin " />
      )}
    </div>
  );
}