import { useEffect, useRef, useState } from "react";
import { connect } from "react-redux";

import { EmptyState, ErrorToast, MainWrapper, Nav, TableList, Toast } from "@ax/components";
import { appActions } from "@ax/containers/App";
import { usersActions } from "@ax/containers/Users";
import { useBulkSelection, useToast } from "@ax/hooks";
import type { IActivateRole, IGetRoles, IQueryValue, IRole, IRootState, ISite } from "@ax/types";

import BulkHeader from "./BulkHeader";
import { useFilterQuery, useSortedListStatus } from "./hooks";
import RoleItem from "./RoleItem";
import SideModal from "./SideModal";
import { getSortedListStatus } from "./utils";

import * as S from "./style";

const Roles = (props: IRolesProps): JSX.Element => {
	const { currentSiteInfo, roles, getRoles, navItems, currentNavItem, setHistoryPush, activateRoles } = props;

	const itemsPerPage = 50;
	const firstPage = 1;

	const [isBulkLoading, setIsBulkLoading] = useState(false);
	const [page, setPage] = useState(1);
	const [isScrolling, setIsScrolling] = useState(false);
	const [activatedItems, setActivatedItems] = useState<number[]>([]);
	const [undoToastActionValue, setUndoToastActionValue] = useState<boolean>(false);
	const [isOpen, setIsOpen] = useState(false);
	const [selectedRole, setSelectedRole] = useState<IRole | null>(null);

	const { sortedListStatus, setSortedListStatus } = useSortedListStatus();
	const { setFiltersSelection, filterValues } = useFilterQuery();

	const tableRef = useRef<HTMLDivElement>(null);
	const wrapperRef = useRef<HTMLDivElement>(null);
	const isSiteView = !!currentSiteInfo;
	const siteId = isSiteView ? currentSiteInfo.id : "global";
	const { isVisible, toggleToast, setIsVisible } = useToast();

	const rolesIds = roles?.map((role: IRole) => role.id);

	const {
		resetBulkSelection,
		isSelected,
		areItemsSelected,
		checkState,
		addToBulkSelection,
		selectAllItems,
		selectedItems,
		setHoverCheck,
	} = useBulkSelection(rolesIds);

	// biome-ignore lint/correctness/useExhaustiveDependencies: TODO: fix this
	useEffect(() => {
		const { order } = filterValues;
		const handleGetRoles = async () => await getRoles({ siteId, order: order[0]?.value.toString() });
		handleGetRoles();
	}, [filterValues]);

	// biome-ignore lint/correctness/useExhaustiveDependencies: TODO: fix this
	useEffect(() => {
		if (wrapperRef.current) {
			wrapperRef.current.scrollIntoView({ block: "start", behavior: "smooth" });
		}
	}, [roles]);

	const handleMenuClick = (path: string) => setHistoryPush(path);

	const unselectAllItems = () => resetBulkSelection();

	const checkAllEditableSelected = () => pageRoles.filter((role) => role.editable).length === selectedItems.all.length;

	const selectItems = () => (checkAllEditableSelected() ? unselectAllItems() : handleSelectAll());

	const bulkFilter = (bulkSelection: number[]) => {
		const activeRoles = bulkSelection.filter((item) => pageRoles.find((role) => role.id === item)?.editable);
		return { all: activeRoles };
	};

	const handleSelectAll = () => selectAllItems(bulkFilter);

	const onScroll = (e: any) => setIsScrolling(e.target.scrollTop > 0);

	const totalItems = roles?.length;

	const firstPageUser = (page - 1) * itemsPerPage;
	const pageRoles = roles?.slice(firstPageUser, firstPageUser + itemsPerPage);
	const isEmpty = roles && roles?.length === 0;
	const pagination = {
		setPage,
		itemsPerPage,
		totalItems,
		currPage: page,
	};

	const sortItems = async (orderPointer: IQueryValue[], isAscending: boolean) => {
		setPage(firstPage);
		const sortedState = getSortedListStatus(orderPointer[0].value.toString(), isAscending);
		setSortedListStatus(sortedState);
		setFiltersSelection("order", orderPointer, isAscending);
	};

	const activateCurrentRoles = (active: boolean) => {
		const allEditableRoles = roles.filter((role: IRole) => role.editable).map((role: IRole) => role.id);
		const selectedEditableRoles = selectedItems.all.filter((role: number) => allEditableRoles.includes(role));
		handleActivateRoles(selectedEditableRoles, active);
	};

	const handleActivateRoles = async (roleIds: number[], active: boolean) => {
		setIsBulkLoading(true);
		const params = {
			id: roleIds,
			siteId,
			active,
		};
		setUndoToastActionValue(!active);
		const activated = await activateRoles(params);
		if (activated) {
			setActivatedItems(roleIds);
			toggleToast();
		}
		setIsBulkLoading(false);
	};

	const restorePreviousRoleStatus = async () => {
		const params = { id: activatedItems, siteId, active: undoToastActionValue };
		await activateRoles(params);
	};

	const undoAction = () => {
		if (activatedItems) {
			restorePreviousRoleStatus();
		}
		setIsVisible(false);
	};

	const activateText = undoToastActionValue ? "Deactivated" : "Activated";

	const toastProps = {
		action: () => undoAction(),
		setIsVisible,
		message: activatedItems.length > 1 ? `${activatedItems.length} Roles ${activateText}` : `1 Role ${activateText}`,
	};

	const TableHeader = (
		<BulkHeader
			filterValues={filterValues}
			showBulk={areItemsSelected(rolesIds)}
			activateRoles={activateCurrentRoles}
			selectAllItems={handleSelectAll}
			totalItems={totalItems}
			selectItems={selectItems}
			checkState={checkState}
			isScrolling={isScrolling}
			sortItems={sortItems}
			sortedListStatus={sortedListStatus}
			isSiteView={isSiteView}
			roles={roles}
			selectedRoles={selectedItems.all}
			setHoverCheck={setHoverCheck}
			selectedItems={selectedItems}
			isLoading={isBulkLoading}
		/>
	);

	const openSideModal = (role: IRole) => {
		setIsOpen(true);
		setSelectedRole(role);
	};

	const closeSideModal = () => {
		setIsOpen(false);
		setSelectedRole(null);
	};

	return (
		<MainWrapper title="Users & Roles">
			<S.UsersWrapper data-testid="users-wrapper" ref={wrapperRef}>
				<Nav current={currentNavItem} items={navItems} onClick={handleMenuClick} />
				<S.TableListWrapper data-testid="roles-table-list-wrapper">
					<ErrorToast />
					<TableList
						tableHeader={TableHeader}
						pagination={pagination}
						onScroll={onScroll}
						hasFixedHeader={true}
						tableRef={tableRef}
					>
						{isEmpty ? (
							<S.EmptyWrapper data-testid="empty-wrapper">
								<EmptyState message="No roles found" />
							</S.EmptyWrapper>
						) : (
							pageRoles?.map((role: IRole) => {
								const isItemSelected = isSelected(role.id);
								const handleActivateRole = async (value: boolean) => handleActivateRoles([role.id], value);

								return (
									<RoleItem
										key={role.id}
										role={role}
										isSelected={isItemSelected}
										onChange={addToBulkSelection}
										onClick={() => openSideModal(role)}
										siteId={siteId}
										activateRole={handleActivateRole}
										hoverCheck={checkState.hoverCheck}
									/>
								);
							})
						)}
					</TableList>
				</S.TableListWrapper>
			</S.UsersWrapper>
			{isVisible && <Toast {...toastProps} />}
			{selectedRole && (
				<SideModal
					name={selectedRole?.name}
					description={selectedRole?.description}
					permissions={selectedRole?.permissions}
					isOpen={isOpen}
					closeModal={() => closeSideModal()}
				/>
			)}
		</MainWrapper>
	);
};

const mapStateToProps = (state: IRootState) => ({
	roles: state.users.roles,
	users: state.users.users,
	currentSiteInfo: state.sites.currentSiteInfo,
});

const mapDispatchToProps = {
	getRoles: usersActions.getRoles,
	activateRoles: usersActions.activateRoles,
	setHistoryPush: appActions.setHistoryPush,
};

interface IDispatchProps {
	getRoles(params?: IGetRoles): Promise<void>;
	setHistoryPush(route: string): void;
	activateRoles(params: IActivateRole): Promise<boolean>;
}

interface IProps {
	navItems: any[];
	currentNavItem: any;
	roles: IRole[];
	currentSiteInfo: ISite | null;
}

export type IRolesProps = IProps & IDispatchProps;

export default connect(mapStateToProps, mapDispatchToProps)(Roles);
