import { useQuery } from "@tanstack/react-query";
import * as React from "react";
import { useDebounce } from "use-debounce";

import {
  Command,
  CommandInput,
  CommandItem,
  CommandList,
  CommandGroup,
} from "@/components/ui/command";
import Axios from "@/lib/Axios";
import { cn } from "@/lib/utils";
import { PermissionsDataT, PermissionsT } from "@/types/global";
import { Check, Minus } from "lucide-react";

export const searchByPermission = async (query: string) => {
  const resp = await Axios.get<PermissionsT>(
    `users/permissions/?search=${query}`
  ).then((res) => {
    return res.data.data;
  });

  return resp;
};

type SearchPermissionT = {
  onSelectResult: (permission: PermissionsDataT) => void;
  checkList: (string | undefined)[] | undefined;
  customerPermissions: PermissionsDataT[];
  userPermissions: PermissionsDataT[];
  otherPermissions: PermissionsDataT[];
  onSelectGroup?: (ids: string[]) => void;
};

export function SearchPermission({
  onSelectResult,
  checkList,
  customerPermissions,
  userPermissions,
  otherPermissions,
  onSelectGroup,
}: SearchPermissionT) {
  const [query, setQuery] = React.useState("");
  function checkIfChecked(id: any) {
    return checkList!.includes(id + "");
  }

  function getGroupCheckState(perms: PermissionsDataT[]) {
    const checkedCount = perms.filter((perm) => checkIfChecked(perm.id)).length;
    if (checkedCount === perms.length && perms.length > 0) return "checked";
    if (checkedCount > 0) return "indeterminate";
    return "unchecked";
  }

  function handleGroupSelect(perms: PermissionsDataT[]) {
    const allSelected = perms.every((perm) => checkIfChecked(perm.id));
    if (typeof onSelectGroup === 'function') {
      if (allSelected) {
        // Deselect all
        onSelectGroup(perms.filter((perm) => !checkIfChecked(perm.id)).map((perm) => String(perm.id)));
      } else {
        // Select all
        onSelectGroup(perms.map((perm) => String(perm.id)));
      }
    } else {
      perms.forEach((perm) => {
        if (allSelected && checkIfChecked(perm.id)) onSelectResult(perm); // deselect all
        if (!allSelected && !checkIfChecked(perm.id)) onSelectResult(perm); // select all
      });
    }
  }

  // Combine all permissions for search
  const allPermissions = [
    ...customerPermissions,
    ...userPermissions,
    ...(otherPermissions || []),
  ];
  const filteredPermissions = query
    ? allPermissions.filter((perm) =>
        perm.name.toLowerCase().includes(query.toLowerCase()) ||
        perm.codename.toLowerCase().includes(query.toLowerCase())
      )
    : [];

  return (
    <Command shouldFilter={false} className="h-auto rounded-lg border border-b-0 shadow-md w-full">
      <CommandInput
        placeholder="Search permissions..."
        value={query}
        onValueChange={setQuery}
      />
      {query ? (
        <CommandList>
          {filteredPermissions.length === 0 && (
            <div className="p-4 text-sm">No record found</div>
          )}
          {filteredPermissions.map((dt) => (
            <CommandItem
              key={dt.id}
              onSelect={() => onSelectResult(dt)}
              value={dt.id + ""}
            >
              <Check className={cn("mr-2 h-4 w-4", checkIfChecked(dt.id) ? "opacity-100" : "opacity-0")} />
              {dt.name}
            </CommandItem>
          ))}
        </CommandList>
      ) : (
        <CommandList>
          <CommandGroup
            heading={
              <span className="flex items-center gap-2 font-bold text-base select-none">
                <span
                  className="flex items-center justify-center w-5 h-5 border rounded bg-white cursor-pointer"
                  onClick={(e) => {
                    e.stopPropagation();
                    handleGroupSelect(customerPermissions);
                  }}
                >
                  {getGroupCheckState(customerPermissions) === "checked" && <Check className="w-4 h-4" />}
                  {getGroupCheckState(customerPermissions) === "indeterminate" && <Minus className="w-4 h-4" />}
                </span>
                Customer Permissions
              </span>
            }
          >
            {customerPermissions.map((dt) => (
              <CommandItem
                key={dt.id}
                onSelect={() => onSelectResult(dt)}
                value={dt.id + ""}
              >
                <Check className={cn("mr-2 h-4 w-4", checkIfChecked(dt.id) ? "opacity-100" : "opacity-0")} />
                {dt.name}
              </CommandItem>
            ))}
          </CommandGroup>
          <CommandGroup
            heading={
              <span className="flex items-center gap-2 font-bold text-base select-none">
                <span
                  className="flex items-center justify-center w-5 h-5 border rounded bg-white cursor-pointer"
                  onClick={(e) => {
                    e.stopPropagation();
                    handleGroupSelect(userPermissions);
                  }}
                >
                  {getGroupCheckState(userPermissions) === "checked" && <Check className="w-4 h-4" />}
                  {getGroupCheckState(userPermissions) === "indeterminate" && <Minus className="w-4 h-4" />}
                </span>
                User Permissions
              </span>
            }
          >
            {userPermissions.map((dt) => (
              <CommandItem
                key={dt.id}
                onSelect={() => onSelectResult(dt)}
                value={dt.id + ""}
              >
                <Check className={cn("mr-2 h-4 w-4", checkIfChecked(dt.id) ? "opacity-100" : "opacity-0")} />
                {dt.name}
              </CommandItem>
            ))}
          </CommandGroup>
          {/*
          <CommandGroup heading={<span className="font-semibold">Other Permissions</span>}>
            {otherPermissions.map((dt) => (
              <CommandItem
                key={dt.id}
                onSelect={() => onSelectResult(dt)}
                value={dt.id + ""}
              >
                <Check className={cn("mr-2 h-4 w-4", checkIfChecked(dt.id) ? "opacity-100" : "opacity-0")} />
                {dt.name}
              </CommandItem>
            ))}
          </CommandGroup>
          */}
        </CommandList>
      )}
    </Command>
  );
}

type ExtendedPermissionsDataT = PermissionsDataT & {
  title: string;
};

interface SearchResultsProps {
  query: string;
  onSelectResult: (data: ExtendedPermissionsDataT) => void;
  checkList: SearchPermissionT["checkList"];
}

function SearchResults({
  query,
  onSelectResult,
  checkList,
}: SearchResultsProps) {
  const [debouncedSearchQuery] = useDebounce(query, 500);

  const enabled = !!debouncedSearchQuery;

  const {
    data,
    isLoading: isLoadingOrig,
    isError,
  } = useQuery<PermissionsDataT[]>({
    queryKey: ["permission_search", debouncedSearchQuery],
    queryFn: () => searchByPermission(debouncedSearchQuery),
    // enabled,
  });

  // To get around this https://github.com/TanStack/query/issues/3584
  const isLoading = enabled && isLoadingOrig;

  //   if (!!enabled) return <></>;

  function checkIfChecked(id: any) {
    return checkList!.includes(id + "");
  }

  return (
    <>
      <CommandList className="">
        {/* TODO: these should have proper loading aria */}
        {isLoading && <div className="p-4 text-sm">Searching...</div>}
        {!isError && !isLoading && !data?.length && (
          <div className="p-4 text-sm">No record found</div>
        )}
        {isError && <div className="p-4 text-sm">Something went wrong</div>}
        {(data || []).map((dt) => {
          return (
            <CommandItem
              key={dt.id}
              onSelect={() => onSelectResult({ ...dt, title: dt.name })}
              value={dt.id + ""}
            >
              <Check
                className={cn(
                  "mr-2 h-4 w-4",
                  checkIfChecked(dt.id) ? "opacity-100" : "opacity-0"
                )}
              />
              {dt.name}
            </CommandItem>
          );
        })}
      </CommandList>
    </>
  );
}
