import { useMemo } from "react";
import { useSelector } from "react-redux";

import type { IRootState } from "@ax/types";

const usePermission = (permission: string | string[] | undefined): boolean => {
	const currentUser = useSelector((state: IRootState) => state.users.currentUser);
	const userPermissions = useSelector((state: IRootState) => state.users.currentPermissions);
	const isSuperAdmin = useSelector((state: IRootState) => state.users.currentUser?.isSuperAdmin);

	const isAllowedTo = (permissions: string[]) =>
		userPermissions && permissions.some((permission: string) => userPermissions.includes(permission));

	if (!permission) {
		return true;
	}

	if (!currentUser) {
		return false;
	}

	if (isSuperAdmin) {
		return true;
	}

	const arrayPermission = Array.isArray(permission) ? permission : [permission];

	return isAllowedTo(arrayPermission);
};

const usePermissions = <T extends Record<string, string | string[]>>(permissions: T): Record<keyof T, boolean> => {
	const currentUser = useSelector((state: IRootState) => state.users.currentUser);
	const userPermissions = useSelector((state: IRootState) => state.users.currentPermissions);
	const isSuperAdmin = useSelector((state: IRootState) => state.users.currentUser?.isSuperAdmin);

	return useMemo(() => {
		if (!currentUser) {
			return Object.keys(permissions).reduce(
				(acc, key) => {
					acc[key as keyof T] = false;
					return acc;
				},
				{} as Record<keyof T, boolean>,
			);
		}

		const isAllowedTo = (permission: string | string[]) => {
			if (isSuperAdmin) return true;
			const arrayPermission = Array.isArray(permission) ? permission : [permission];
			return userPermissions && arrayPermission.some((perm: string) => userPermissions.includes(perm));
		};

		const result: Record<string, boolean> = {};
		for (const key of Object.keys(permissions)) {
			result[key] = isAllowedTo(permissions[key]);
		}
		return result as Record<keyof T, boolean>;
	}, [permissions, userPermissions, isSuperAdmin, currentUser]);
};

const useGlobalPermission = (permission: string | string[] | undefined): boolean => {
	const currentUser = useSelector((state: IRootState) => state.users.currentUser);
	const userPermissions = useSelector((state: IRootState) => state.users.globalPermissions);
	const isSuperAdmin = useSelector((state: IRootState) => state.users.currentUser?.isSuperAdmin);

	const isAllowedTo = (permissions: string[]) =>
		userPermissions && permissions.some((permission: string) => userPermissions.includes(permission));

	if (!permission) {
		return true;
	}

	if (!currentUser) {
		return false;
	}

	if (isSuperAdmin) {
		return true;
	}

	const arrayPermission = Array.isArray(permission) ? permission : [permission];

	return isAllowedTo(arrayPermission);
};

const usePermissionsForSite = <T extends Record<string, string | string[]>>(
	siteId: number | string,
	permissions: T,
): Record<keyof T, boolean> => {
	const currentUser = useSelector((state: IRootState) => state.users.currentUser);
	const roles = useSelector((state: IRootState) => state.users.roles);
	const isSuperAdmin = useSelector((state: IRootState) => state.users.currentUser?.isSuperAdmin);

	return useMemo(() => {
		if (!currentUser) {
			return Object.keys(permissions).reduce(
				(acc, key) => {
					acc[key as keyof T] = false;
					return acc;
				},
				{} as Record<keyof T, boolean>,
			);
		}

		if (isSuperAdmin) {
			return Object.keys(permissions).reduce(
				(acc, key) => {
					acc[key as keyof T] = true;
					return acc;
				},
				{} as Record<keyof T, boolean>,
			);
		}

		const userRoles = currentUser.roles.find(
			(roleSite) => roleSite.siteId === siteId || roleSite.siteId === "all",
		)?.roles;

		if (!userRoles?.length) {
			return Object.keys(permissions).reduce(
				(acc, key) => {
					acc[key as keyof T] = false;
					return acc;
				},
				{} as Record<keyof T, boolean>,
			);
		}

		const sitePermissions: string[] = [];
		userRoles.forEach((roleID: number) => {
			const role = roles?.find((r) => r.id === roleID);
			if (role) {
				const rolePerms = role.permissions.sitePermissions.map((perm) => perm.key);
				sitePermissions.push(...rolePerms);
			}
		});

		const result: Record<string, boolean> = {};
		for (const key of Object.keys(permissions)) {
			const permission = permissions[key as keyof T];
			const arrayPermission = Array.isArray(permission) ? permission : [permission];
			result[key] = arrayPermission.some((perm: string) => sitePermissions.includes(perm));
		}
		return result as Record<keyof T, boolean>;
	}, [siteId, permissions, currentUser, roles, isSuperAdmin]);
};

export { usePermission, usePermissions, useGlobalPermission, usePermissionsForSite };
