"use client";

import { debounce } from "lodash";
import dynamic from "next/dynamic";
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import toast from "react-hot-toast";
import { TContactAttributeKey } from "@formbricks/types/contact-attribute-key";
import { TEnvironment } from "@formbricks/types/environment";
import { LoadingSpinner } from "@/modules/ui/components/loading-spinner";
import { getContactsAction } from "../actions";
import { TContactTableData, TContactWithAttributes } from "../types/contact";

const ContactsTableDynamic = dynamic(() => import("./contacts-table").then((mod) => mod.ContactsTable), {
  loading: () => <LoadingSpinner />,
  ssr: false,
});

interface ContactDataViewProps {
  environment: TEnvironment;
  contactAttributeKeys: TContactAttributeKey[];
  initialContacts: TContactWithAttributes[];
  itemsPerPage: number;
  isReadOnly: boolean;
  hasMore: boolean;
  isQuotasAllowed: boolean;
}

export const ContactDataView = ({
  environment,
  itemsPerPage,
  contactAttributeKeys,
  isReadOnly,
  hasMore: initialHasMore,
  initialContacts,
  isQuotasAllowed,
}: ContactDataViewProps) => {
  const [contacts, setContacts] = useState<TContactWithAttributes[]>([...initialContacts]);
  const [hasMore, setHasMore] = useState<boolean>(initialHasMore);
  const [loadingNextPage, setLoadingNextPage] = useState<boolean>(false);
  const [searchValue, setSearchValue] = useState<string>("");
  const [isDataLoaded, setIsDataLoaded] = useState(true);

  const isFirstRender = useRef(true);

  const environmentAttributes = useMemo(() => {
    return contactAttributeKeys.filter(
      (attr) => !["userId", "email", "firstName", "lastName"].includes(attr.key)
    );
  }, [contactAttributeKeys]);

  // Fetch contacts from offset 0 with current search value
  const fetchContactsFromStart = useCallback(async () => {
    setIsDataLoaded(false);
    try {
      setHasMore(true);
      const contactsResponse = await getContactsAction({
        environmentId: environment.id,
        offset: 0,
        searchValue,
      });
      if (contactsResponse?.data) {
        setContacts(contactsResponse.data);
      }
      if (contactsResponse?.data && contactsResponse.data.length < itemsPerPage) {
        setHasMore(false);
      }
    } catch (error) {
      console.error("Error fetching contacts:", error);
      toast.error("Error fetching contacts. Please try again.");
    } finally {
      setIsDataLoaded(true);
    }
  }, [environment.id, itemsPerPage, searchValue]);

  useEffect(() => {
    if (!isFirstRender.current) {
      const debouncedFetchData = debounce(fetchContactsFromStart, 300);
      debouncedFetchData();

      return () => {
        debouncedFetchData.cancel();
      };
    }
  }, [fetchContactsFromStart]);

  useEffect(() => {
    if (isFirstRender.current) {
      isFirstRender.current = false;
    }
  }, []);

  // Fetch next page of contacts
  const fetchNextPage = async () => {
    if (hasMore && !loadingNextPage) {
      setLoadingNextPage(true);
      try {
        const contactsResponse = await getContactsAction({
          environmentId: environment.id,
          offset: contacts.length,
          searchValue,
        });
        const contactsData = contactsResponse?.data || [];

        setContacts((prevContacts) => [...prevContacts, ...contactsData]);

        if (contactsData.length < itemsPerPage) {
          setHasMore(false);
        }
      } catch (error) {
        console.error("Error fetching next page of contacts:", error);
      } finally {
        setLoadingNextPage(false);
      }
    }
  };

  // Delete selected contacts
  const updateContactList = (contactIds: string[]) => {
    setContacts((prevContacts) => prevContacts.filter((contact) => !contactIds.includes(contact.id)));
  };

  // Prepare data for the ContactTable component
  const contactsTableData: TContactTableData[] = useMemo(() => {
    return contacts.map((contact) => ({
      id: contact.id,
      userId: contact.attributes.userId ?? "",
      email: contact.attributes.email ?? "",
      firstName: contact.attributes.firstName ?? "",
      lastName: contact.attributes.lastName ?? "",
      attributes: (environmentAttributes ?? []).map((attr) => ({
        key: attr.key,
        name: attr.name,
        value: contact.attributes[attr.key] ?? "",
      })),
    }));
  }, [contacts, environmentAttributes]);

  return (
    <ContactsTableDynamic
      data={contactsTableData}
      fetchNextPage={fetchNextPage}
      hasMore={hasMore}
      isDataLoaded={isFirstRender.current ? true : isDataLoaded}
      updateContactList={updateContactList}
      environmentId={environment.id}
      searchValue={searchValue}
      setSearchValue={setSearchValue}
      isReadOnly={isReadOnly}
      isQuotasAllowed={isQuotasAllowed}
      refreshContacts={fetchContactsFromStart}
    />
  );
};
