import { useState, useRef, useEffect, createContext, useContext } from "react";
import {
  Cog6ToothIcon,
  InformationCircleIcon,
  MinusIcon,
  DocumentTextIcon,
  KeyIcon,
  CheckIcon,
} from "@heroicons/react/24/outline";
import { motion, AnimatePresence } from "framer-motion";
import { Grid } from "../Grid/Grid";
import { createPortal } from "react-dom";
import { useUserProfileStore } from "../../context/zustand-store/userStore";
import { Tooltip } from "../Tooltip/Tooltip";
import Button from "../Button/Button";
import { useModalStore } from "../../context/zustand-store/appStore";
import Typography from "../Typography/Typography";
import { useToast } from "../../hooks/useToast";
import { ItemWithSubItems } from "../../types/userPermissions";
import { getUserPermissions } from "../../utils/getUserAvalableItems";
import { useApiRequest } from "../../utils/useApiRequest";
import Checkbox from "../CheckBox/CheckBox";
import { useFetchProfile } from "../../hooks/useFetchProfile";
import { useQueryClient } from "@tanstack/react-query";
import api from "../../utils/axios";
import { getFaPermissions } from "../../utils/getFaPermissions";

export const PopOverContext = createContext<boolean>(false);
export const usePopOverContext = () => useContext(PopOverContext);

const PermissionsContent = ({
  filterProps,
  showToast,
  matchedSubItem,
}: {
  filterProps: Array<{ page: string; access: string; title: string }>;
  showToast: (text: string, type?: "success" | "error" | "default") => void;
  matchedSubItem: any;
}) => {
  const [copiedItem, setCopiedItem] = useState<{
    type: "page" | "access";
    index: number;
  } | null>(null);
  const [expandedPermissions, setExpandedPermissions] = useState<{
    [key: string]: boolean;
  }>({});
  const queryClient = useQueryClient();
  const { getProfile } = useFetchProfile();
  const [selectedRoleIdsByKey, setSelectedRoleIdsByKey] = useState<{
    [key: string]: Set<number>;
  }>({});
  const [submittingKey, setSubmittingKey] = useState<string | null>(null);

  const { data: rolesData, refetch: refetchRoles } = useApiRequest({
    api: "/auth/api/v1/role/",
    method: "get",
    params: { page: 1, page_size: 1000 },
    queryKey: ["roles-permissions"],
  });

  const { data: permissionsData } = useApiRequest({
    api: "/auth/api/v1/permission/",
    method: "get",
    params: { page: 1, page_size: 1000 },
    queryKey: ["all-permissions"],
  });

  const findPermissionId = (page: string, access: string): number | null => {
    if (!permissionsData?.results) return null;
    const permission = permissionsData.results.find(
      (p: any) => p.page === page && p.name === access
    );
    return permission?.id || null;
  };

  const checkRoleHasPermission = (
    role: any,
    page: string,
    access: string
  ): boolean => {
    if (!role?.permissions || !Array.isArray(role.permissions)) {
      return false;
    }
    if (!permissionsData?.results) return false;

    const permissionId = findPermissionId(page, access);
    if (!permissionId) return false;

    const rolePermissionIds = role.permissions.map((p: any) => p.id || p);
    return rolePermissionIds.includes(permissionId);
  };

  const ensureInitialized = (key: string, page: string, access: string) => {
    if (selectedRoleIdsByKey[key]) return;
    if (!rolesData?.results) return;
    const next = new Set<number>();
    rolesData.results.forEach((role: any) => {
      if (checkRoleHasPermission(role, page, access)) {
        next.add(role.id);
      }
    });
    setSelectedRoleIdsByKey((prev) => ({ ...prev, [key]: next }));
  };

  const toggleLocal = (key: string, roleId: number) => {
    setSelectedRoleIdsByKey((prev) => {
      const current = new Set(prev[key] || []);
      if (current.has(roleId)) current.delete(roleId);
      else current.add(roleId);
      return { ...prev, [key]: current };
    });
  };

  const handleCancel = (key: string, page: string, access: string) => {
    if (!rolesData?.results) return;
    const next = new Set<number>();
    rolesData.results.forEach((role: any) => {
      if (checkRoleHasPermission(role, page, access)) {
        next.add(role.id);
      }
    });
    setSelectedRoleIdsByKey((prev) => ({ ...prev, [key]: next }));
  };

  const handleSubmit = async (key: string, page: string, access: string) => {
    try {
      const permissionId = findPermissionId(page, access);
      if (!permissionId) {
        showToast("دسترسی یافت نشد", "error");
        return;
      }
      if (!rolesData?.results) return;
      let selected = selectedRoleIdsByKey[key];
      if (!selected) {
        const init = new Set<number>();
        rolesData.results.forEach((role: any) => {
          if (checkRoleHasPermission(role, page, access)) {
            init.add(role.id);
          }
        });
        setSelectedRoleIdsByKey((prev) => ({ ...prev, [key]: init }));
        selected = init;
      }
      const updates = rolesData.results.flatMap((role: any) => {
        const currentPermissionIds = (role.permissions || []).map(
          (p: any) => p.id || p
        );
        const currentlyHas = currentPermissionIds.includes(permissionId);
        const shouldHave = selected.has(role.id);
        if (currentlyHas === shouldHave) return [];
        const updatedPermissionIds = shouldHave
          ? currentPermissionIds.includes(permissionId)
            ? currentPermissionIds
            : [...currentPermissionIds, permissionId]
          : currentPermissionIds.filter((id: number) => id !== permissionId);
        return [
          api.patch(`/auth/api/v1/role/${role.id}/`, {
            permissions: updatedPermissionIds,
          }),
        ];
      });
      if (updates.length === 0) {
        showToast("تغییری برای ارسال وجود ندارد", "default");
        return;
      }
      setSubmittingKey(key);
      await Promise.all(updates);
      showToast("به‌روزرسانی نقش‌ها با موفقیت انجام شد", "success");
      queryClient.invalidateQueries({ queryKey: ["roles"] });
      queryClient.invalidateQueries({ queryKey: ["roles-permissions"] });
      refetchRoles();
      getProfile();
    } catch (error: any) {
      showToast(
        error?.response?.data?.message || "خطا در به‌روزرسانی نقش‌ها",
        "error"
      );
    } finally {
      setSubmittingKey(null);
    }
  };

  const handleCopy = async (
    text: string,
    type: "page" | "access",
    index: number
  ) => {
    try {
      await navigator.clipboard.writeText(text);
      setCopiedItem({ type, index });
      showToast(
        type === "page" ? `صفحه "${text}" کپی شد` : `دسترسی "${text}" کپی شد`,
        "success"
      );
      setTimeout(() => {
        setCopiedItem(null);
      }, 2000);
    } catch {
      showToast("خطا در کپی کردن", "error");
    }
  };

  return (
    <div className="">
      <Grid
        container
        className="mb-2 gap-1 border-gray-200/60 dark:border-gray-700/40 justify-center items-center"
      >
        {matchedSubItem?.name && (
          <div className="px-3 py-1.5 rounded-lg bg-gradient-to-r from-gray-50 to-gray-100/50 dark:from-gray-800/50 dark:to-gray-800/30 border border-gray-200/50 dark:border-gray-700/30 shadow-sm">
            <Typography
              variant="caption"
              className="text-gray-700 dark:text-gray-300 font-medium text-sm line-clamp-1"
            >
              صفحه فعلی: {matchedSubItem?.name} (
              {getFaPermissions(matchedSubItem?.name)})
            </Typography>
          </div>
        )}
      </Grid>
      <div className="space-y-3">
        {filterProps && filterProps.length > 0 ? (
          filterProps.map(
            (
              item: {
                page: string;
                access: string;
                title: string;
              },
              index: number
            ) => (
              <motion.div
                key={`${item.page}-${index}`}
                initial={{ opacity: 0, y: 5 }}
                animate={{ opacity: 1, y: 0 }}
                transition={{ delay: index * 0.03 }}
                className="relative bg-gradient-to-br from-gray-50 to-gray-100/50 dark:from-dark-700 dark:to-dark-800 rounded-lg p-2.5 border border-gray-200/60 dark:border-gray-600/40 shadow-sm hover:shadow transition-all duration-200 group"
              >
                <div className="flex items-center gap-2.5">
                  <div className="flex-shrink-0 w-7 h-7 rounded-md bg-primary-100 dark:bg-primary-900/30 flex items-center justify-center group-hover:bg-primary-200 dark:group-hover:bg-primary-900/50 transition-colors">
                    <span className="text-xs text-primary-600 dark:text-primary-400 font-bold">
                      {index + 1}
                    </span>
                  </div>
                  <div className="flex-1 min-w-0">
                    {item.title && (
                      <Typography
                        variant="subtitle2"
                        className="text-gray-700 dark:text-gray-300 font-medium text-sm mb-1.5 line-clamp-1"
                      >
                        {item.title}
                      </Typography>
                    )}
                    <div className="flex flex-wrap items-center gap-2">
                      {item.page && (
                        <div
                          onClick={(e) => {
                            e.stopPropagation();
                            handleCopy(item.page, "page", index);
                          }}
                          className="flex items-center gap-1.5 px-2 py-1 rounded-md bg-white/60 dark:bg-dark-600/60 border border-gray-200/50 dark:border-gray-700/50 cursor-pointer hover:bg-white/80 dark:hover:bg-dark-600/80 transition-colors active:scale-95"
                        >
                          {copiedItem?.type === "page" &&
                          copiedItem?.index === index ? (
                            <CheckIcon className="w-3.5 h-3.5 text-green-500 dark:text-green-400 flex-shrink-0" />
                          ) : (
                            <DocumentTextIcon className="w-3.5 h-3.5 text-gray-500 dark:text-gray-400 flex-shrink-0" />
                          )}
                          <Typography
                            variant="caption"
                            className="text-gray-700 dark:text-gray-300 text-xs font-medium truncate max-w-[120px]"
                          >
                            {item.page}
                          </Typography>
                        </div>
                      )}
                      {item.access && (
                        <span
                          onClick={(e) => {
                            e.stopPropagation();
                            handleCopy(item.access, "access", index);
                          }}
                          className="inline-flex items-center gap-1.5 px-2 py-1 rounded-md text-xs font-semibold bg-primary-100 dark:bg-primary-900/40 text-primary-700 dark:text-primary-300 border border-primary-200 dark:border-primary-800 cursor-pointer hover:bg-primary-200 dark:hover:bg-primary-900/60 transition-colors active:scale-95"
                        >
                          {copiedItem?.type === "access" &&
                          copiedItem?.index === index ? (
                            <CheckIcon className="w-3.5 h-3.5 text-green-500 dark:text-green-400" />
                          ) : (
                            <KeyIcon className="w-3.5 h-3.5" />
                          )}
                          {item.access}
                        </span>
                      )}
                    </div>
                    {rolesData?.results && rolesData.results.length > 0 && (
                      <div className="mt-3 pt-3 border-t border-gray-200/60 dark:border-gray-700/40">
                        <button
                          onClick={(e) => {
                            e.stopPropagation();
                            setExpandedPermissions((prev) => ({
                              ...prev,
                              [`${item.page}-${item.access}-${index}`]:
                                !prev[`${item.page}-${item.access}-${index}`],
                            }));
                            const k = `${item.page}-${item.access}-${index}`;
                            ensureInitialized(k, item.page, item.access);
                          }}
                          className="flex items-center gap-2 text-xs text-gray-600 dark:text-gray-400 hover:text-primary-600 dark:hover:text-primary-400 transition-colors mb-2"
                        >
                          <span>
                            {expandedPermissions[
                              `${item.page}-${item.access}-${index}`
                            ]
                              ? "▲"
                              : "▼"}{" "}
                            نقش‌ها (
                            {
                              rolesData.results.filter((role: any) =>
                                checkRoleHasPermission(
                                  role,
                                  item.page,
                                  item.access
                                )
                              ).length
                            }
                            /{rolesData.results.length})
                          </span>
                        </button>
                        {expandedPermissions[
                          `${item.page}-${item.access}-${index}`
                        ] && (
                          <div className="space-y-2 max-h-60 overflow-y-auto">
                            {rolesData.results.map((role: any) => {
                              const k = `${item.page}-${item.access}-${index}`;
                              const selectedSet = selectedRoleIdsByKey[k];
                              const hasPermission =
                                selectedSet?.has(role.id) ??
                                checkRoleHasPermission(
                                  role,
                                  item.page,
                                  item.access
                                );
                              return (
                                <div
                                  key={role.id}
                                  className="flex items-center gap-2 px-2 py-1.5 rounded-md bg-white/40 dark:bg-dark-600/40 border border-gray-200/50 dark:border-gray-700/50 hover:bg-white/60 dark:hover:bg-dark-600/60 transition-colors"
                                >
                                  <Checkbox
                                    checked={hasPermission}
                                    disabled={submittingKey === k}
                                    onChange={(e) => {
                                      e.stopPropagation();
                                      ensureInitialized(
                                        k,
                                        item.page,
                                        item.access
                                      );
                                      toggleLocal(k, role.id);
                                    }}
                                    size="small"
                                  />
                                  <Typography
                                    variant="caption"
                                    className="text-xs text-gray-700 dark:text-gray-300 flex-1"
                                  >
                                    {role.role_name}
                                  </Typography>
                                  {role.type?.name && (
                                    <Typography
                                      variant="caption"
                                      className="text-xs text-gray-500 dark:text-gray-400"
                                    >
                                      ({role.type.name})
                                    </Typography>
                                  )}
                                </div>
                              );
                            })}
                          </div>
                        )}
                        {expandedPermissions[
                          `${item.page}-${item.access}-${index}`
                        ] && (
                          <div className="flex items-center justify-between gap-2 mt-2">
                            <button
                              className="px-3 py-1.5 text-xs rounded-md bg-gray-100 dark:bg-dark-600 text-gray-700 dark:text-gray-200 hover:bg-gray-200/80 dark:hover:bg-dark-500"
                              onClick={(e) => {
                                e.stopPropagation();
                                const k = `${item.page}-${item.access}-${index}`;
                                handleCancel(k, item.page, item.access);
                              }}
                              disabled={
                                submittingKey ===
                                `${item.page}-${item.access}-${index}`
                              }
                            >
                              انصراف
                            </button>
                            <button
                              className="px-3 py-1.5 text-xs rounded-md bg-primary-600 text-white hover:bg-primary-700 disabled:opacity-60"
                              onClick={(e) => {
                                e.stopPropagation();
                                const k = `${item.page}-${item.access}-${index}`;
                                handleSubmit(k, item.page, item.access);
                              }}
                              disabled={
                                submittingKey ===
                                `${item.page}-${item.access}-${index}`
                              }
                            >
                              {submittingKey ===
                              `${item.page}-${item.access}-${index}`
                                ? "در حال ارسال..."
                                : "ثبت تغییرات"}
                            </button>
                          </div>
                        )}
                      </div>
                    )}
                  </div>
                </div>
              </motion.div>
            )
          )
        ) : (
          <div className="text-center py-6 text-gray-500 dark:text-gray-400">
            <Typography variant="body2" className="text-sm">
              دسترسی‌ای یافت نشد
            </Typography>
          </div>
        )}
      </div>
    </div>
  );
};

export const Popover = ({
  children,
  className,
}: {
  children: React.ReactNode | any;
  className?: string;
}) => {
  const { openModal } = useModalStore();
  const { profile } = useUserProfileStore();

  const menuItems: ItemWithSubItems[] = getUserPermissions(
    profile?.permissions
  );
  const currentPath = window.location.pathname;

  const matchedSubItem = menuItems
    .flatMap((item) => item.subItems)
    .find(
      (sub) =>
        sub.path === currentPath ||
        sub.path.includes(currentPath.split("/")[1] + "/")
    );

  const [isOpen, setIsOpen] = useState(false);
  const [isMobile, setIsMobile] = useState(false);
  const buttonRef = useRef<HTMLButtonElement>(null);
  const popoverRef = useRef<HTMLDivElement>(null);

  useEffect(() => {
    const checkMobile = () => setIsMobile(window.innerWidth < 640);
    checkMobile();
    window.addEventListener("resize", checkMobile);
    return () => window.removeEventListener("resize", checkMobile);
  }, []);

  const buttonRect = buttonRef?.current?.getBoundingClientRect();

  const showToast = useToast();

  const filterProps: Array<{ page: string; access: string; title: string }> =
    !Array.isArray(children)
      ? [
          {
            page:
              children?.props?.page ||
              children?.props?.children?.props?.page ||
              "",
            access:
              children?.props?.access ||
              children?.props?.children?.props?.access ||
              "",
            title: children?.props?.tooltipText || children?.props?.title || "",
          },
        ]
      : children
          ?.filter(
            (item: any) =>
              (item?.props?.page && item?.props?.access) ||
              (item?.props?.children?.props?.access &&
                item?.props?.children?.props?.page)
          )
          ?.map((option: any) => {
            return {
              page:
                option?.props?.page ||
                option?.props?.children?.props?.page ||
                "",
              access:
                option?.props?.access ||
                option?.props?.children?.props?.access ||
                "",
              title: option?.props?.tooltipText || option?.props?.title || "",
            };
          }) || [];

  const ableToSeeAnyButton = (
    filterProps: Array<{ page: string; access: string }>
  ) => {
    if (!filterProps || filterProps.length === 0) {
      return true;
    }

    return filterProps?.some(({ page, access }) => {
      if (!access || !page) {
        return true;
      }

      const foundPermission = profile?.permissions?.find(
        (item: any) => item.page_name === page
      );

      return foundPermission && foundPermission.page_access.includes(access);
    });
  };

  useEffect(() => {
    const handleClickOutside = (e: MouseEvent | TouchEvent) => {
      if (
        !buttonRef.current?.contains(e.target as Node) &&
        !popoverRef.current?.contains(e.target as Node)
      ) {
        setIsOpen(false);
      }
    };

    if (isOpen) {
      document.addEventListener("mousedown", handleClickOutside);
      if (isMobile) document.body.style.overflow = "hidden";
    }

    return () => {
      document.removeEventListener("mousedown", handleClickOutside);
      if (isMobile) document.body.style.overflow = "";
    };
  }, [isOpen, isMobile]);

  const togglePopover = () => setIsOpen(!isOpen);

  const [position, setPosition] = useState({ top: 0, left: 0 });
  useEffect(() => {
    if (!isOpen || isMobile) return;

    const updatePosition = () => {
      const buttonRect = buttonRef.current?.getBoundingClientRect();
      const popoverElement = popoverRef.current;

      if (!buttonRect) return;

      const viewportHeight = window.innerHeight;
      const viewportWidth = window.innerWidth;
      const scrollY = window.scrollY;
      const scrollX = window.scrollX;

      const padding = 16;
      const maxPopoverHeight = viewportHeight - padding * 2;

      let top = buttonRect.top + scrollY;
      let left = buttonRect.right + scrollX + 8;

      if (popoverElement) {
        const popoverRect = popoverElement.getBoundingClientRect();

        const popoverHeight = Math.min(popoverRect.height, maxPopoverHeight);
        const popoverWidth = popoverRect.width;

        const popoverBottomInViewport = buttonRect.top + popoverHeight;

        if (popoverBottomInViewport > viewportHeight - padding) {
          const overflow = popoverBottomInViewport - (viewportHeight - padding);

          top = buttonRect.top + scrollY - overflow;

          if (top < scrollY + padding) {
            top = scrollY + padding;
          }
        }

        const popoverRightInViewport = buttonRect.right + popoverWidth + 8;
        if (popoverRightInViewport > viewportWidth - padding) {
          left = buttonRect.left + scrollX - popoverWidth - 8;

          if (left < scrollX + padding) {
            left = scrollX + padding;
          }
        }
      } else {
        const estimatedHeight = Math.min(
          (Array.isArray(children) ? children.length : 1) * 50 + 100,
          maxPopoverHeight
        );

        if (buttonRect.top + estimatedHeight > viewportHeight - padding) {
          const overflow =
            buttonRect.top + estimatedHeight - (viewportHeight - padding);

          top = buttonRect.top + scrollY - overflow;
          if (top < scrollY + padding) {
            top = scrollY + padding;
          }
        }

        const estimatedWidth = 300;
        if (buttonRect.right + estimatedWidth + 8 > viewportWidth - padding) {
          left = buttonRect.left + scrollX - estimatedWidth - 8;
          if (left < scrollX + padding) {
            left = scrollX + padding;
          }
        }
      }

      setPosition({ top, left });
    };

    updatePosition();

    const timeoutId = setTimeout(updatePosition, 0);

    window.addEventListener("scroll", updatePosition, true);
    window.addEventListener("resize", updatePosition);

    return () => {
      clearTimeout(timeoutId);
      window.removeEventListener("scroll", updatePosition, true);
      window.removeEventListener("resize", updatePosition);
    };
  }, [isOpen, isMobile, children]);

  return (
    <PopOverContext.Provider value={true}>
      <div className={`relative ${className}`}>
        <motion.button
          disabled={!ableToSeeAnyButton(filterProps)}
          ref={buttonRef}
          onClick={togglePopover}
          className={`p-2 rounded-full hover:bg-gray-100/50 dark:hover:bg-gray-800 transition-colors`}
          whileHover={{ scale: 1.05 }}
          whileTap={{ scale: 0.95 }}
        >
          <motion.div animate={{ rotate: isOpen ? 90 : 0 }}>
            {!ableToSeeAnyButton(filterProps) ? (
              <MinusIcon className="h-5 w-5 text-red-600 cursor-not-allowed" />
            ) : (
              <Cog6ToothIcon
                className={`h-5 w-5 ${
                  isOpen
                    ? "text-primary-600"
                    : "text-gray-600 dark:text-gray-300"
                }`}
              />
            )}
          </motion.div>
        </motion.button>

        {isOpen &&
          createPortal(
            <AnimatePresence>
              <>
                {isMobile && (
                  <motion.div
                    initial={{ opacity: 0 }}
                    animate={{ opacity: 0.4 }}
                    exit={{ opacity: 0 }}
                    className="fixed inset-0 z-[9998] bg-black/40 backdrop-blur-sm"
                    onClick={() => setIsOpen(false)}
                  />
                )}

                <motion.div
                  ref={popoverRef}
                  id="popover-content"
                  initial={isMobile ? { y: "100%" } : { opacity: 0, y: -10 }}
                  animate={isMobile ? { y: 0 } : { opacity: 1, y: 0 }}
                  exit={isMobile ? { y: "100%" } : { opacity: 0, y: -10 }}
                  transition={{ type: "spring", damping: 20, stiffness: 300 }}
                  className={`z-[9999] bg-white dark:bg-dark-700 rounded-lg shadow-lg ring-1 ring-black/10 dark:ring-white/10 ${
                    isMobile
                      ? "fixed bottom-0 inset-x-0 rounded-t-3xl pb-[env(safe-area-inset-bottom)]"
                      : "fixed max-h-[calc(100vh-32px)]"
                  }`}
                  style={
                    !isMobile
                      ? {
                          top: `${
                            buttonRect?.bottom && buttonRect?.bottom > 700
                              ? position.top - 100
                              : position.top
                          }px`,
                          left: `${position.left}px`,
                        }
                      : {}
                  }
                >
                  {isMobile && (
                    <div className="flex justify-center py-2">
                      <div className="w-10 h-1 bg-gray-300 dark:bg-gray-600 rounded-full" />
                    </div>
                  )}

                  <PopOverContext.Provider value={true}>
                    <Grid
                      container
                      column
                      className="gap-2 p-2 max-h-[calc(100vh-32px)] overflow-y-auto"
                      onClick={() => setIsOpen(false)}
                    >
                      {children}
                      {profile?.role?.type?.key === "ADM" && (
                        <Tooltip
                          title="نمایش دسترسی های این قسمت"
                          position="right"
                        >
                          <Button
                            icon={
                              <InformationCircleIcon className="w-5 h-5 text-gray-600 dark:text-red-400" />
                            }
                            variant="detail"
                            onClick={() => {
                              openModal({
                                title: "دسترسی های این قسمت",
                                content: (
                                  <PermissionsContent
                                    filterProps={filterProps}
                                    showToast={showToast}
                                    matchedSubItem={matchedSubItem}
                                  />
                                ),
                              });
                            }}
                          />
                        </Tooltip>
                      )}
                    </Grid>
                  </PopOverContext.Provider>
                </motion.div>
              </>
            </AnimatePresence>,
            document.body
          )}
      </div>
    </PopOverContext.Provider>
  );
};
