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

import {
	EmptyState,
	ErrorToast,
	FilterTagsBar,
	MainWrapper,
	Modal,
	Nav,
	SearchTagsBar,
	TableList,
	Toast,
} from "@ax/components";
import { appActions } from "@ax/containers/App";
import { sitesActions } from "@ax/containers/Sites";
import { usersActions } from "@ax/containers/Users";
import { useBulkSelection, useModal, usePermission, useToast } from "@ax/hooks";
import type { IGetRoles, IGetSitesParams, IQueryValue, IRole, IRootState, ISite, IUser } from "@ax/types";

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

import * as S from "./style";

const UserList = (props: IUserListProps): JSX.Element => {
	const {
		currentSiteInfo,
		users,
		getUsers,
		navItems,
		currentNavItem,
		setHistoryPush,
		getUser,
		sites,
		deleteUser,
		removeUsersBulk,
		getRoles,
		roles,
		getSites,
	} = props;

	const itemsPerPage = 50;
	const firstPage = 1;

	const [isBulkLoading, setIsBulkLoading] = useState(false);
	const [page, setPage] = useState(1);
	const [isScrolling, setIsScrolling] = useState(false);
	const [searchQuery, setSearchQuery] = useState<string>("");
	const [usersDeleted, setUSersDeleted] = useState(1);

	const { sortedListStatus, setSortedListStatus } = useSortedListStatus();
	const { setFiltersSelection, resetFilterQuery, filterValues, filterQuery } = useFilterQuery();
	const { isVisible, toggleToast, setIsVisible } = useToast();

	const tableRef = useRef<HTMLDivElement>(null);
	const wrapperRef = useRef<HTMLDivElement>(null);
	const isSiteView = !!currentSiteInfo;

	const { isOpen, toggleModal } = useModal();

	const allowedToCreateUsers = usePermission("usersRoles.createUsers");

	const usersIds = users.map((user: IUser) => user.id);

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

	const handleGetUsers = async () => {
		const query = searchQuery ? (filterQuery ? `&query=${searchQuery}` : `?query=${searchQuery}`) : "";
		const currentFilterQuerySite =
			isSiteView && filterQuery ? `${filterQuery}&site=${currentSiteInfo.id}` : filterQuery;
		await getUsers({ filterQuery: currentFilterQuerySite, query }, currentSiteInfo?.id);
	};

	// biome-ignore lint/correctness/useExhaustiveDependencies: TODO: fix this
	useEffect(() => {
		handleGetUsers();
	}, [filterQuery, searchQuery]);

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

	// biome-ignore lint/correctness/useExhaustiveDependencies: TODO: fix this
	useEffect(() => {
		const handleRolesSites = async () => {
			const siteId = isSiteView ? currentSiteInfo.id : "global";
			await getRoles({ siteId });
			await getSites({ pagination: false, recentSitesNumber: 0 });
		};
		handleRolesSites();
	}, []);

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

	const unselectAllItems = () => resetBulkSelection();

	const checkAllEditableSelected = () =>
		isSiteView
			? pageUsers.filter((user) => !user.isSuperAdmin).length === selectedItems.all.length
			: checkState.isAllSelected;

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

	const bulkFilter = (bulkSelection: number[]) => {
		const activeUsers = isSiteView
			? bulkSelection.filter((item) => pageUsers.find((user) => user.id === item)?.isSuperAdmin === false)
			: bulkSelection;
		return { all: activeUsers };
	};

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

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

	const totalItems = users.length;

	const firstPageUser = (page - 1) * itemsPerPage;
	const pageUsers = users.slice(firstPageUser, firstPageUser + itemsPerPage);
	const isEmpty = !users || users.length === 0;
	const BASE_URL = isSiteView ? "/sites/users" : "/users";
	const pagination = {
		setPage,
		itemsPerPage,
		totalItems,
		currPage: page,
	};

	const bulkDelete = async () => {
		setIsBulkLoading(true);
		if (isSiteView) {
			const siteId = currentSiteInfo.id;
			await removeUsersBulk(siteId, selectedItems.all);
		} else {
			await deleteUser(selectedItems.all);
		}
		setUSersDeleted(selectedItems.all.length);
		toggleModal();
		toggleToast();
		resetBulkSelection();
		setIsBulkLoading(false);
	};

	const rightButtonProps = allowedToCreateUsers
		? {
				label: "New",
				action: () => setHistoryPush(`${BASE_URL}/new`),
			}
		: undefined;

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

	const filterItems = async (filterPointer: string, filtersSelected: IQueryValue[]) => {
		setPage(firstPage);
		setFiltersSelection(filterPointer, filtersSelected);
	};

	const handleSearch = (query: string) => {
		setSearchQuery(query);
		setPage(firstPage);
	};

	const handleClick = (id: number | null) => async () => {
		if (id) {
			await getUser(id);
			setHistoryPush(`${BASE_URL}/edit`);
		}
	};

	const TableHeader = (
		<BulkHeader
			isSiteView={isSiteView}
			filterValues={filterValues}
			showBulk={areItemsSelected(usersIds)}
			bulkDelete={toggleModal}
			selectAllItems={handleSelectAll}
			totalItems={totalItems}
			selectItems={selectItems}
			checkState={checkState}
			isScrolling={isScrolling}
			sortItems={sortItems}
			filterItems={filterItems}
			sortedListStatus={sortedListStatus}
			roles={roles}
			setHoverCheck={setHoverCheck}
			selectedItems={selectedItems}
			isLoading={isBulkLoading}
		/>
	);

	const suffix = usersDeleted > 1 ? "s" : "";

	const toastProps = {
		setIsVisible,
		message: isSiteView ? `${usersDeleted} User${suffix} removed from site` : `${usersDeleted} User${suffix} deleted`,
	};

	const handleToggleToast = () => {
		setUSersDeleted(1);
		toggleToast();
	};

	const mainDeleteAction = {
		title: isSiteView ? (isBulkLoading ? "Removing" : "Remove") : isBulkLoading ? "Deleting" : "Delete",
		onClick: bulkDelete,
		disabled: isBulkLoading,
	};
	const secondaryDeleteAction = { title: "Cancel", onClick: toggleModal };

	const filterLabels = {
		filterRoles: "Role",
		filterSites: "Site",
	};

	return (
		<MainWrapper
			title="Users & Roles"
			rightButton={rightButtonProps}
			searchAction={handleSearch}
			searchValue={searchQuery}
		>
			<S.UsersWrapper ref={wrapperRef} data-testid="users-wrapper">
				<Nav current={currentNavItem} items={navItems} onClick={handleMenuClick} />
				<S.TableListWrapper>
					<ErrorToast />
					<TableList
						tableHeader={TableHeader}
						pagination={pagination}
						onScroll={onScroll}
						hasFixedHeader={true}
						tableRef={tableRef}
					>
						<>
							<S.SearchTags>
								<SearchTagsBar query={searchQuery} setQuery={handleSearch} />
								<FilterTagsBar
									filters={filterValues}
									setFilters={setFiltersSelection}
									resetFilters={resetFilterQuery}
									labels={filterLabels}
								/>
							</S.SearchTags>
							{isEmpty ? (
								<S.EmptyWrapper data-testid="empty-wrapper">
									<EmptyState message="No users found" />
								</S.EmptyWrapper>
							) : (
								pageUsers?.map((user) => {
									const isItemSelected = isSelected(user.id);
									return (
										<UserItem
											siteId={currentSiteInfo?.id}
											isSiteView={isSiteView}
											key={user.id}
											user={user}
											sites={sites}
											isSelected={isItemSelected}
											onChange={addToBulkSelection}
											onClick={handleClick(user.id)}
											roles={roles}
											toggleDeleteToast={handleToggleToast}
											hoverCheck={checkState.hoverCheck}
											getUsers={handleGetUsers}
										/>
									);
								})
							)}
						</>
					</TableList>
				</S.TableListWrapper>
			</S.UsersWrapper>
			<Modal
				isOpen={isOpen}
				hide={toggleModal}
				title={isSiteView ? "Remove users from this site?" : "Delete Users?"}
				secondaryAction={secondaryDeleteAction}
				mainAction={mainDeleteAction}
			>
				{isOpen ? (
					<S.ModalContent data-testid="user-delete-bulk-modal">
						<p>
							{isSiteView
								? "Are you sure you want to remove these users from this site? If you remove them, these users will no longer have access to this site but they will still be able to log in. This action cannot be undone."
								: "Are you sure you want to delete these users? If you delete them, they no longer be able to log in."}
						</p>

						<p>
							This action <strong>cannot be undone</strong>.
						</p>
					</S.ModalContent>
				) : null}
			</Modal>
			{isVisible && <Toast {...toastProps} />}
		</MainWrapper>
	);
};

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

const mapDispatchToProps = {
	getUsers: usersActions.getUsers,
	getUser: usersActions.getUser,
	setHistoryPush: appActions.setHistoryPush,
	deleteUser: usersActions.deleteUser,
	removeUsersBulk: sitesActions.removeUsersBulk,
	getRoles: usersActions.getRoles,
	getSites: sitesActions.getSites,
};

interface IDispatchProps {
	getUsers(params: any, siteID?: number | null): Promise<void>;
	getUser(id: number): Promise<void>;
	setHistoryPush(route: string): void;
	deleteUser(id: number[]): Promise<boolean>;
	removeUsersBulk(siteId: number, users: number[]): Promise<void>;
	getRoles(params: IGetRoles, token?: string, hasLoading?: boolean): Promise<void>;
	getSites(params: IGetSitesParams): Promise<void>;
}

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

export type IUserListProps = IProps & IDispatchProps;

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