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

import { EmptyState, ErrorToast, MainWrapper, SearchTagsBar, TableList, Toast } from "@ax/components";
import { formsActions } from "@ax/containers/Forms";
import { getSchemaFormCategories } from "@ax/helpers";
import { useBulkSelection, useModal, usePermission, useToast } from "@ax/hooks";
import type { FormCategoriesOrderParams, FormCategory, IRootState } from "@ax/types";

import {
	closestCenter,
	DndContext,
	type DragEndEvent,
	type DragStartEvent,
	KeyboardSensor,
	PointerSensor,
	useSensor,
	useSensors,
} from "@dnd-kit/core";
import { SortableContext, sortableKeyboardCoordinates, verticalListSortingStrategy } from "@dnd-kit/sortable";

import FormsMenu from "../FormsMenu";
import { DeleteModal } from "./atoms";
import BulkHeader from "./BulkHeader";
import CategoryItem from "./CategoryItem";
import CategoryPanel from "./CategoryPanel";

import * as S from "./style";

const FormCategoriesList = (props: IProps): JSX.Element => {
	const { categories, currentSiteID, getFormCategories, deleteFormCategory, orderFormCategory } = props;

	const schemaCategories = getSchemaFormCategories();
	const { cat: urlCategory } = useParams<{ cat: string }>();

	const category =
		!urlCategory || !schemaCategories.map((cat) => cat.value).includes(urlCategory)
			? schemaCategories[0].value
			: urlCategory;
	const categoryLabel = schemaCategories.find((cat) => cat.value === category)?.label;
	const isSiteView = !!currentSiteID;

	const [isScrolling, setIsScrolling] = useState(false);
	const [isBulkLoading, setIsBulkLoading] = useState(false);
	const [draggingId, setDraggingId] = useState<number | null>(null);
	const [searchQuery, setSearchQuery] = useState<string>("");
	const { isVisible, toggleToast, setIsVisible, state: toastState } = useToast();
	const { isOpen, toggleModal } = useModal();
	const { isOpen: isDeleteOpen, toggleModal: toggleDeleteModal } = useModal();
	const tableRef = useRef<HTMLDivElement>(null);
	const isSearching = searchQuery.length > 0;

	const createFormCategoryPermission = isSiteView
		? "forms.createFormsCategories"
		: "global.forms.createFormsCategories";
	const deleteFormCategoryPermission = isSiteView
		? "forms.deleteFormsCategories"
		: "global.forms.deleteFormsCategories";
	const isAllowedToCreateFormCategory = usePermission(createFormCategoryPermission);
	const isAllowedToDeleteFormCategory = usePermission(deleteFormCategoryPermission);

	const sensors = useSensors(
		useSensor(PointerSensor, {
			activationConstraint: {
				distance: 5,
			},
		}),
		useSensor(KeyboardSensor, {
			coordinateGetter: sortableKeyboardCoordinates,
		}),
	);

	const catIds = categories.map((category) => category.id);
	const totalItems = categories.length;

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

	// biome-ignore lint/correctness/useExhaustiveDependencies: TODO: fix this
	useEffect(() => {
		const getContents = async () => await getFormCategories(category);
		getContents();
		return () => {
			//resetCurrentData();
		};
	}, [category]);

	const rightButtonProps = isAllowedToCreateFormCategory
		? {
				label: "New",
				action: toggleModal,
			}
		: undefined;

	const bulkDelete = async () => {
		setIsBulkLoading(true);
		const deleted = await deleteFormCategory(selectedItems.all, category);
		if (deleted) {
			resetBulkSelection();
			toggleToast(`${selectedItems.all.length} categor${selectedItems.all.length > 1 ? "ies" : "y"} deleted`);
			toggleDeleteModal();
		}
		setIsBulkLoading(false);
	};

	const selectItems = () => (checkState.isAllSelected ? resetBulkSelection() : selectAllItems());

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

	const toastProps = {
		setIsVisible,
		message: toastState,
	};

	const bulkActions = isAllowedToDeleteFormCategory
		? [
				{
					icon: "delete",
					text: "delete",
					action: toggleDeleteModal,
				},
			]
		: [];

	const TableHeader = (
		<BulkHeader
			showBulk={areItemsSelected(catIds)}
			selectedItems={selectedItems}
			totalItems={totalItems}
			selectItems={selectItems}
			checkState={checkState}
			isScrolling={isScrolling}
			bulkActions={bulkActions}
			setHoverCheck={setHoverCheck}
			isLoading={isBulkLoading}
		/>
	);

	const handleDragStart = (event: DragStartEvent) => {
		const { active } = event;
		setDraggingId(active.id as number);
	};

	const handleOnDragEnd = async (event: DragEndEvent) => {
		const { active, over } = event;

		if (over && active.id !== over.id) {
			const oldIndex = categories.map((e) => e.id).indexOf(active.id as number);
			const newIndex = categories.map((e) => e.id).indexOf(over.id as number);

			const newPosition = newIndex ? categories[newIndex - (newIndex > oldIndex ? 0 : 1)].position + 1 : 1;

			const params: FormCategoriesOrderParams = {
				id: active.id as number,
				categoryType: category,
				position: newPosition,
				relatedSite: currentSiteID,
			};

			await orderFormCategory(params);
		}

		setDraggingId(null);
	};

	const isEmpty = totalItems === 0;
	const emptyProps = {
		message: isAllowedToCreateFormCategory
			? "To start using categories in your forms, create as many categories as you need."
			: "",
		button: isAllowedToCreateFormCategory ? "New Category" : "",
		action: toggleModal,
	};

	const emptySearchStateProps = {
		icon: "search",
		title: "Oh! No Results Found",
		message: "We couldn’t find what you are looking for. Please, try another search.",
	};

	const mainDeleteModalAction = {
		title: isBulkLoading ? "Deleting" : "delete",
		onClick: bulkDelete,
		disabled: isBulkLoading,
	};

	const secondaryDeleteModalAction = { title: "Cancel", onClick: toggleDeleteModal };

	return (
		<MainWrapper title="Forms" rightButton={rightButtonProps} searchAction={setSearchQuery} searchValue={searchQuery}>
			<S.CategoryListWrapper>
				<FormsMenu selected={categoryLabel} />
				<S.TableWrapper>
					<ErrorToast />
					<S.Intro>
						<S.IntroTitle>Create and manage categories</S.IntroTitle>
						<div>
							Define your form categories by creating the elements you need and assigning them to your forms, making it
							easier to quickly find the right form to add to your page.
						</div>
					</S.Intro>
					<TableList tableHeader={TableHeader} onScroll={onScroll} hasFixedHeader={true} tableRef={tableRef}>
						<S.SearchTags>
							<SearchTagsBar query={searchQuery} setQuery={setSearchQuery} />
						</S.SearchTags>
						{isEmpty ? (
							<S.EmptyWrapper>
								{isSearching ? <EmptyState {...emptySearchStateProps} /> : <EmptyState {...emptyProps} />}
							</S.EmptyWrapper>
						) : (
							<>
								<S.Notification>
									Reorder your category list by <strong>drag & drop</strong>.
								</S.Notification>
								<DndContext
									sensors={sensors}
									collisionDetection={closestCenter}
									onDragEnd={handleOnDragEnd}
									onDragStart={handleDragStart}
								>
									<SortableContext items={catIds} strategy={verticalListSortingStrategy}>
										{categories.map((category: FormCategory) => {
											const isItemSelected = isSelected(category.id);
											const isDragging = !!draggingId && draggingId !== category.id;

											return (
												<CategoryItem
													category={category}
													key={category.id}
													isSelected={isItemSelected}
													onChange={addToBulkSelection}
													toggleToast={toggleToast}
													hoverCheck={checkState.hoverCheck}
													isDragging={isDragging}
													isSiteView={isSiteView}
												/>
											);
										})}
									</SortableContext>
								</DndContext>
							</>
						)}
					</TableList>
				</S.TableWrapper>
			</S.CategoryListWrapper>
			<CategoryPanel isOpen={isOpen} toggleModal={toggleModal} toggleToast={toggleToast} type={category} />
			{isDeleteOpen && (
				<DeleteModal
					isOpen={isDeleteOpen}
					toggleModal={toggleDeleteModal}
					mainModalAction={mainDeleteModalAction}
					secondaryModalAction={secondaryDeleteModalAction}
				/>
			)}
			{isVisible && <Toast {...toastProps} />}
		</MainWrapper>
	);
};

const mapStateToProps = (state: IRootState) => ({
	categories: state.forms.currentFormCategories,
	// biome-ignore lint/complexity/useOptionalChain: TODO: fix this
	currentSiteID: state.sites.currentSiteInfo && state.sites.currentSiteInfo.id,
});

interface IDispatchProps {
	getFormCategories(type: string): Promise<void>;
	deleteFormCategory(id: number | number[], categoryType: string): Promise<boolean>;
	orderFormCategory(data: FormCategoriesOrderParams): Promise<boolean>;
}

interface ICategoriesProps {
	categories: FormCategory[];
	currentSiteID: number | null;
}

type IProps = ICategoriesProps & IDispatchProps;

const mapDispatchToProps = {
	getFormCategories: formsActions.getFormCategories,
	deleteFormCategory: formsActions.deleteFormCategory,
	orderFormCategory: formsActions.orderFormCategory,
};

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