import { useEffect, useState } from "react";
import { useApiRequest } from "../../utils/useApiRequest";
import AutoComplete from "../AutoComplete/AutoComplete";
import { getFaPermissions } from "../../utils/getFaPermissions";
import { getNestedValue } from "../../utils/getNestedValue";

type FormEnterLocationsProps = {
  title: string;
  api: string;
  error?: boolean;
  errorMessage?: any;
  multiple?: boolean;
  onChange?: (data: any) => void;
  onChangeValue?: (data: any) => void;
  keyField?: string;
  secondaryKey?: string | string[];
  tertiaryKey?: string | string[];
  valueField?: string | string[];
  valueField2?: string | string[];
  valueField3?: string | string[];
  filterAddress?: string[];
  filterValue?: string[];
  defaultKey?: string | number | any[];
  valueTemplate?: string;
  valueTemplateProps?: Array<{ [key: string]: "string" | "number" }>;
  groupBy?: string | string[];
  groupFunction?: (item: any) => string;
  selectField?: boolean;
};

export const FormApiBasedAutoComplete = ({
  title,
  api,
  error,
  errorMessage,
  onChange,
  onChangeValue,
  keyField = "id",
  secondaryKey,
  tertiaryKey,
  valueField = "name",
  valueField2,
  valueField3,
  defaultKey,
  multiple = false,
  filterValue,
  filterAddress,
  valueTemplate,
  valueTemplateProps,
  groupBy,
  groupFunction,
  selectField = false,
}: FormEnterLocationsProps) => {
  const [data, setData] = useState<any>([]);
  const [selectedKeys, setSelectedKeys] = useState<(string | number)[]>([]);
  const [groupedItemsMap, setGroupedItemsMap] = useState<
    Map<string | number, any[]>
  >(new Map());

  const formatValue = (value: any, fieldKey: string) => {
    if (!valueTemplate || !valueTemplateProps) return value;

    const templateProp = valueTemplateProps.find((prop) => prop[fieldKey]);
    if (!templateProp) return value;

    const fieldType = templateProp[fieldKey];

    if (fieldType === "number") {
      const numValue = typeof value === "number" ? value : Number(value);
      return !isNaN(numValue) ? numValue.toLocaleString() : String(value);
    } else if (fieldType === "string") {
      let result = String(value);
      if (typeof value === "string" && value.includes(",")) {
        result = value.replace(/,/g, "");
      }
      return result;
    }

    return value;
  };

  const { data: apiData } = useApiRequest({
    api: api,
    method: "get",
    params: { page: 1, page_size: 1000 },
    queryKey: [api],
    disableBackdrop: defaultKey ? true : false,
  });

  useEffect(() => {
    if (apiData?.results) {
      let data;

      if (filterAddress && filterValue) {
        data = apiData.results?.filter(
          (item: any) =>
            !filterValue.includes(getNestedValue(item, filterAddress))
        );
      } else {
        data = apiData.results;
      }
      const d = data?.map((option: any) => ({
        key: option[keyField],
        secondaryKey: secondaryKey
          ? typeof secondaryKey === "string"
            ? option[secondaryKey]
            : getNestedValue(option, secondaryKey)
          : undefined,
        tertiaryKey: tertiaryKey
          ? typeof tertiaryKey === "string"
            ? option[tertiaryKey]
            : getNestedValue(option, tertiaryKey)
          : undefined,
        value: valueTemplate
          ? valueTemplate
              .replace(
                /v1/g,
                formatValue(
                  valueField === "page"
                    ? getFaPermissions(option[valueField])
                    : typeof valueField === "string"
                    ? option[valueField]
                    : getNestedValue(option, valueField),
                  "v1"
                )
              )
              .replace(
                /v2/g,
                formatValue(
                  valueField2
                    ? typeof valueField2 === "string"
                      ? option[valueField2]
                      : getNestedValue(option, valueField2)
                    : "",
                  "v2"
                )
              )
              .replace(
                /v3/g,
                formatValue(
                  valueField3
                    ? typeof valueField3 === "string"
                      ? option[valueField3]
                      : getNestedValue(option, valueField3)
                    : "",
                  "v3"
                )
              )
          : `${
              valueField === "page"
                ? getFaPermissions(option[valueField])
                : typeof valueField === "string"
                ? option[valueField]
                : getNestedValue(option, valueField)
            }  ${
              valueField2
                ? " - " +
                  (typeof valueField2 === "string"
                    ? option[valueField2]
                    : getNestedValue(option, valueField2))
                : ""
            }  ${
              valueField3
                ? "(" +
                  (typeof valueField3 === "string"
                    ? option[valueField3]
                    : getNestedValue(option, valueField3)) +
                  ")"
                : ""
            }`,
        groupValue: groupBy
          ? typeof groupBy === "string"
            ? option[groupBy]
            : getNestedValue(option, groupBy)
          : undefined,
      }));

      let finalData = d;

      if (groupBy) {
        const grouped = new Map<string | number, typeof d>();

        d.forEach((item: any) => {
          const groupKey = item.groupValue ?? "";
          if (!grouped.has(groupKey)) {
            grouped.set(groupKey, []);
          }
          grouped.get(groupKey)!.push(item);
        });

        setGroupedItemsMap(grouped);

        finalData = [];
        grouped.forEach((items, groupKey) => {
          finalData.push({
            key: `__group__${groupKey}`,
            value: groupFunction ? groupFunction(groupKey) : String(groupKey),
            disabled: true,
            isGroupHeader: true,
            originalGroupKey: groupKey,
          });
          finalData.push(...items);
        });
      } else {
        setGroupedItemsMap(new Map());
      }

      setData(finalData);

      const actualDataItems = finalData.filter(
        (item: any) => !item.isGroupHeader && !item.disabled
      );

      if (defaultKey !== undefined && defaultKey !== null) {
        if (multiple) {
          if (Array.isArray(defaultKey)) {
            if (defaultKey.length === 0) {
              setSelectedKeys([]);
            } else {
              const defaultIds = defaultKey.map((item: any) =>
                typeof item === "object" ? item[keyField] : item
              );
              const defaultItems = actualDataItems.filter((item: any) =>
                defaultIds.includes(item.key)
              );
              setSelectedKeys(defaultItems.map((item: any) => item.key));
              if (onChange) {
                if (secondaryKey) {
                  onChange({
                    key1: defaultItems.map((item: any) => item.key),
                    key2: defaultItems.map((item: any) => item.secondaryKey),
                    ...(tertiaryKey
                      ? {
                          key3: defaultItems.map(
                            (item: any) => item.tertiaryKey
                          ),
                        }
                      : {}),
                  });
                } else {
                  onChange(defaultItems.map((item: any) => item.key));
                }
              }
            }
          }
        } else {
          if (!Array.isArray(defaultKey)) {
            const keyToFind =
              typeof defaultKey === "object"
                ? defaultKey[keyField]
                : defaultKey;
            const defaultItem = actualDataItems.find(
              (item: any) => item.key === keyToFind
            );
            if (defaultItem) {
              setSelectedKeys([keyToFind]);
              if (onChange) {
                if (secondaryKey) {
                  onChange({
                    key1: defaultItem.key,
                    key2: defaultItem.secondaryKey,
                    ...(tertiaryKey ? { key3: defaultItem.tertiaryKey } : {}),
                  });
                } else {
                  onChange(keyToFind);
                }
              }
              if (onChangeValue) {
                onChangeValue({
                  key1: defaultItem.key,
                  key2: defaultItem.secondaryKey,
                  ...(tertiaryKey ? { key3: defaultItem.tertiaryKey } : {}),
                  value: defaultItem.value.trim(),
                });
              }
            }
          }
        }
      }
    }
  }, [apiData]);

  const handleGroupHeaderClick = (groupKey: string | number) => {
    if (!multiple || !groupBy) return;

    const groupItems = groupedItemsMap.get(groupKey) || [];
    if (groupItems.length === 0) return;

    const groupItemKeys = groupItems.map((item: any) => item.key);
    const allGroupItemsSelected = groupItemKeys.every((key) =>
      selectedKeys.includes(key)
    );

    let newSelectedKeys: (string | number)[];

    if (allGroupItemsSelected) {
      newSelectedKeys = selectedKeys.filter(
        (key) => !groupItemKeys.includes(key)
      );
    } else {
      const newKeys = groupItemKeys.filter(
        (key) => !selectedKeys.includes(key)
      );
      newSelectedKeys = [...selectedKeys, ...newKeys];
    }

    setSelectedKeys(newSelectedKeys);

    if (!onChange) return;

    const selectedItems = data.filter(
      (item: any) =>
        newSelectedKeys.includes(item.key) &&
        !item.isGroupHeader &&
        !item.disabled
    );

    if (secondaryKey) {
      onChange(
        selectedItems.map((item: any) => ({
          key1: item.key,
          key2: item.secondaryKey,
          ...(tertiaryKey ? { key3: item.tertiaryKey } : {}),
        }))
      );
      if (onChangeValue) {
        onChangeValue(selectedItems.map((item: any) => item.value.trim()));
      }
    } else {
      onChange(newSelectedKeys);
    }
  };

  return (
    <>
      <AutoComplete
        multiselect={multiple}
        selectField={selectField}
        data={data}
        selectedKeys={selectedKeys}
        onChange={(newSelectedKeys) => {
          setSelectedKeys(newSelectedKeys);

          if (!onChange) return;

          if (multiple) {
            if (secondaryKey) {
              const selectedItems = data.filter(
                (item: any) =>
                  newSelectedKeys.includes(item.key) &&
                  !item.isGroupHeader &&
                  !item.disabled
              );

              onChange(
                selectedItems.map((item: any) => ({
                  key1: item.key,
                  key2: item.secondaryKey,
                  ...(tertiaryKey ? { key3: item.tertiaryKey } : {}),
                }))
              );
              if (onChangeValue) {
                onChangeValue(
                  selectedItems.map((item: any) => item.value.trim())
                );
              }
            } else {
              const validKeys = newSelectedKeys.filter(
                (key) => !String(key).startsWith("__group__")
              );
              onChange(validKeys);
            }
          } else {
            if (secondaryKey) {
              const selectedItem = data.find(
                (item: any) =>
                  item.key === newSelectedKeys[0] &&
                  !item.isGroupHeader &&
                  !item.disabled
              );
              if (onChangeValue) {
                onChangeValue({
                  value: selectedItem?.value.trim() ?? "",
                  key1: selectedItem?.key ?? "",
                  key2: selectedItem?.secondaryKey ?? "",
                  ...(tertiaryKey
                    ? { key3: selectedItem?.tertiaryKey ?? "" }
                    : {}),
                });
              }

              if (selectedItem) {
                onChange({
                  key1: selectedItem.key,
                  key2: selectedItem.secondaryKey,
                  ...(tertiaryKey ? { key3: selectedItem.tertiaryKey } : {}),
                });
              }
            } else {
              const validKey =
                newSelectedKeys[0] &&
                !String(newSelectedKeys[0]).startsWith("__group__")
                  ? newSelectedKeys[0]
                  : "";
              onChange(validKey);
            }
          }
        }}
        title={title}
        error={error}
        helperText={errorMessage}
        onGroupHeaderClick={handleGroupHeaderClick}
      />
    </>
  );
};
