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

import {
	BackFolder,
	EmptyState,
	ErrorToast,
	FilterTagsBar,
	Icon,
	Loader,
	SearchField,
	SearchTagsBar,
	Tabs,
	Tooltip,
} from "@ax/components";
import { galleryActions } from "@ax/containers/Gallery";
import { usePermission, useResizable } from "@ax/hooks";
// refactor
import Breadcrumb from "@ax/modules/MediaGallery/Breadcrumb";
import FolderTree from "@ax/modules/MediaGallery/FolderTree";
import { useFilterQuery, useSortedListStatus } from "@ax/modules/MediaGallery/hooks";
import Orientation from "@ax/modules/MediaGallery/ImageFilters/Orientation";
import SortBy from "@ax/modules/MediaGallery/ImageFilters/SortBy";
import Type from "@ax/modules/MediaGallery/ImageFilters/Type";
import { getSortedListStatus } from "@ax/modules/MediaGallery/utils";
import type {
	IFolder,
	IFolderTree,
	IGetFolderParams,
	IImage,
	IImageFolder,
	IQueryValue,
	IRootState,
	ISite,
} from "@ax/types";

import FolderItem from "./FolderItem";
import GalleryPanel from "./GalleryPanel";

import * as S from "./style";

const Gallery = (props: IProps): JSX.Element => {
	const { currentFolderContent, site, breadcrumb, toggleModal, getFolderContent, getFoldersTree, getImageSelected } =
		props;

	const { images, folders } = currentFolderContent || { images: { items: [], totalItems: 0 }, folders: [] };
	const { items, totalItems } = images;

	const itemsPerPage = 20;
	const firstPage = 1;
	const lastPage = Math.ceil(totalItems / itemsPerPage);
	const [page, setPage] = useState(firstPage);
	const [selectedTab, setSelectedTab] = useState(site ? "local" : "global");
	const [selectedImage, setSelectedImage] = useState<IImage | null>(null);
	const [isPanelOpen, setPanelOpen] = useState(false);
	const [isLoading, setIsLoading] = useState(false);
	const [isLoadingMore, setIsLoadingMore] = useState(false);
	const [currentFolderID, setCurrentFolderID] = useState<number | null>(null);
	const isLocalTab = selectedTab === "local";
	const galleryScope = isLocalTab && site ? site.id : "global";
	const hasFolders = !!folders?.length;
	const isRoot = !breadcrumb?.length;

	const galleryRef = useRef<HTMLDivElement>(null);

	const [ref] = useResizable();

	const { setFiltersSelection, resetFilterQuery, filterValues, filterQuery } = useFilterQuery();
	const { sortedListStatus, setSortedListStatus } = useSortedListStatus();
	const [searchQuery, setSearchQuery] = useState<string>("");
	const isSearching = searchQuery.length > 0;

	const isSiteView = !!site;
	const isTabGlobal = selectedTab === "global";
	const siteID: number | "global" = !isSiteView || isTabGlobal ? "global" : site.id;

	const allowedToAccessGlobalFromSite = usePermission("mediaGallery.accessToGlobalGalleryFromSite");

	const allowedToAddSiteFile = usePermission("mediaGallery.addImages");
	const allowedToAddGlobalFile = usePermission("global.mediaGallery.addGlobalImages");
	const allowedToAddGlobalFileFromSite = false;
	const allowedToAddFile = !isSiteView
		? allowedToAddGlobalFile
		: isTabGlobal
			? allowedToAddGlobalFileFromSite
			: allowedToAddSiteFile;

	const allowedToEditSiteFile = usePermission("mediaGallery.editImages");
	const allowedToEditGlobalFile = usePermission("global.mediaGallery.editGlobalImages");
	const allowedToEditGlobalFileFromSite = false;

	const allowedToEditFile = !isSiteView
		? allowedToEditGlobalFile
		: isTabGlobal
			? allowedToEditGlobalFileFromSite
			: allowedToEditSiteFile;

	const tabs: string[] = [];
	if (isSiteView && allowedToAccessGlobalFromSite) {
		tabs.unshift(...["local", "global"]);
	}

	const getParams = useCallback(() => {
		const params = {
			siteID,
			folderID: currentFolderID,
			search: searchQuery,
			loading: false,
			query: filterQuery,
			thumbHeight: 116,
			pagination: true,
			page,
			itemsPerPage,
			infinite: page > 1,
		};

		return params;
	}, [currentFolderID, searchQuery, filterQuery, siteID, page]);

	useLayoutEffect(() => {
		return () => {
			setCurrentFolderID(null);
			setSelectedTab("site");
			setPage(firstPage);
		};
	}, []);

	// biome-ignore lint/correctness/useExhaustiveDependencies: TODO: fix this
	useEffect(() => {
		const handleGetContent = async () => {
			page === 1 && setIsLoading(true);
			const params = getParams();
			await getFolderContent(params);
			setIsLoading(false);
			setIsLoadingMore(false);
		};
		const handleGetTree = async () => await getFoldersTree(siteID);
		handleGetContent();
		handleGetTree();
	}, [getParams, selectedTab]);

	const onScroll = () => {
		if (galleryRef.current) {
			const { scrollTop, scrollHeight, clientHeight } = galleryRef.current;
			if (
				scrollTop + clientHeight + 100 >= scrollHeight &&
				items.length < totalItems &&
				page < lastPage &&
				!isLoadingMore
			) {
				setIsLoadingMore(true);
				setPage((currentPage) => currentPage + 1);
			}
		}
	};

	const handleClick = (item: IImage) => {
		if (item.id !== selectedImage?.id) {
			setSelectedImage(item);
		} else {
			setSelectedImage(null);
		}
	};

	const setImage = (imageData: any) => {
		const updatedImage = { ...selectedImage, ...imageData };
		getImageSelected(updatedImage);
		toggleModal();
	};

	const handleSelectedTab = (tab: string) => {
		if (tab !== selectedTab) {
			setSearchQuery("");
			setCurrentFolderID(null);
			setSelectedImage(null);
			setSelectedTab(tab);
			setPage(firstPage);
		}
	};

	const handleUpdateCurrentFolder = (folderID: number | null) => {
		setSearchQuery("");
		setPage(firstPage);
		setCurrentFolderID(folderID);
	};

	const togglePanel = () => setPanelOpen(!isPanelOpen);

	const handleBackClick = () => {
		const parentID = breadcrumb.length >= 2 ? breadcrumb[breadcrumb.length - 2].id : null;
		setPage(firstPage);
		setCurrentFolderID(parentID);
	};

	const handleUpload = async (file: IImage[]) => {
		setSelectedImage(file[0]);
		const params = getParams();
		await getFolderContent(params);
	};

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

		setFiltersSelection("order", orderPointer, isAscending);
	};

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

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

	const foldersIcon = isPanelOpen ? <Icon name="closePanel" size="24" /> : <Icon name="openPanel" size="24" />;

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

	const emptyFolderStateProps = {
		title: "Oh! This looks so empty",
		message: "No images found in this folder.",
	};

	const filters = (
		<>
			<Orientation filterItems={filterItems} />
			<Type filterItems={filterItems} />
			<SortBy sortItems={sortItems} sortedState={sortedListStatus} />
		</>
	);

	return (
		<S.Wrapper data-testid="image-gallery-wrapper">
			<S.FolderPanel isOpen={isPanelOpen} ref={ref}>
				<S.FolderPanelContent>
					<FolderTree folderID={currentFolderID || 0} onClick={handleUpdateCurrentFolder} title="Folders" />
				</S.FolderPanelContent>
				<S.ResizeHandle className="resizer" />
			</S.FolderPanel>
			<S.ContentWrapper>
				{!!tabs.length && (
					<S.Header>
						{!!tabs.length && (
							<S.TabsWrapper>
								<Tabs tabs={tabs} active={selectedTab} setSelectedTab={handleSelectedTab} noMargins />
							</S.TabsWrapper>
						)}
						<S.Filters>{filters}</S.Filters>
					</S.Header>
				)}
				<S.Search>
					{!isSiteView && <S.FiltersGlobal>{filters}</S.FiltersGlobal>}
					<SearchField
						onChange={handleSearch}
						value={searchQuery}
						placeholder="Type an image’s name, title, or #tag"
						focus={false}
					/>
				</S.Search>
				<S.GalleryWrapper ref={galleryRef} onScroll={onScroll}>
					<ErrorToast size="l" />
					{isLoading ? (
						<S.LoadingWrapper>
							<Loader name="circle" />
						</S.LoadingWrapper>
					) : (
						<>
							<S.SearchTags>
								<SearchTagsBar query={searchQuery} setQuery={handleSearch} />
								<FilterTagsBar
									filters={filterValues}
									setFilters={setFiltersSelection}
									labels={{ orientation: "Orientation", format: "Media type", usage: "Usage" }}
									resetFilters={resetFilterQuery}
								/>
							</S.SearchTags>
							{!isRoot && !isSearching && <Breadcrumb breadcrumb={breadcrumb} onClick={handleUpdateCurrentFolder} />}
							{(hasFolders || (!isRoot && !isSearching)) && (
								<S.SectionWrapper>
									<S.SectionHeader>
										<S.SectionTitle>
											<div>Folders</div>
											<S.FoldersIconWrapper onClick={togglePanel}>
												<Tooltip content="Open folder panel">{foldersIcon}</Tooltip>
											</S.FoldersIconWrapper>
										</S.SectionTitle>
									</S.SectionHeader>
									<S.FoldersWrapper>
										{!isRoot && !isSearching && <BackFolder onClick={handleBackClick} size="S" />}
										<S.FoldersGrid>
											{folders.map((folder: IFolder) => (
												<FolderItem folder={folder} onClick={handleUpdateCurrentFolder} key={folder.folderName} />
											))}
										</S.FoldersGrid>
									</S.FoldersWrapper>
								</S.SectionWrapper>
							)}
							<S.SectionWrapper>
								{!items.length ? (
									<S.EmptyWrapper>
										{isSearching ? (
											<EmptyState {...emptySearchStateProps} />
										) : isRoot ? (
											<EmptyState {...emptyFolderStateProps} />
										) : (
											<></>
										)}
									</S.EmptyWrapper>
								) : (
									<>
										<S.SectionHeader>
											<S.SectionTitle>Media</S.SectionTitle>
										</S.SectionHeader>
										<S.Grid>
											{images &&
												items.map((item: IImage) => {
													const isSelected = item.id === selectedImage?.id;
													return (
														<S.ImageWrapper
															key={item.id}
															data-testid="image-item"
															onClick={() => handleClick(item)}
															selected={isSelected}
														>
															<img src={item.thumb} alt={item.alt} />
															<S.IconWrapper>
																<Icon name={isSelected ? "successSolid" : "emptyCheck"} size="24" />
															</S.IconWrapper>
														</S.ImageWrapper>
													);
												})}
										</S.Grid>
									</>
								)}
							</S.SectionWrapper>
						</>
					)}
				</S.GalleryWrapper>
			</S.ContentWrapper>
			<GalleryPanel
				selectedImage={selectedImage}
				setImage={setImage}
				scope={galleryScope}
				currentFolderID={currentFolderID}
				handleUpload={handleUpload}
				isAllowedToAdd={allowedToAddFile}
				isAllowedToEdit={allowedToEditFile}
				getParams={getParams}
			/>
		</S.Wrapper>
	);
};

export interface IGalleryProps {
	site: ISite | null;
	currentFolderContent: IImageFolder | null;
	isLoading: boolean;
	breadcrumb: IFolderTree[];
	toggleModal: () => void;
	getImageSelected: (img: IImage | null) => void;
}

const mapStateToProps = (state: IRootState) => ({
	isLoading: state.app.isLoading,
	currentFolderContent: state.gallery.currentFolderContent,
	breadcrumb: state.gallery.breadcrumb,
});

export interface IDispatchProps {
	getFolderContent(params: IGetFolderParams): Promise<void>;
	getFoldersTree(siteID: number | "global"): Promise<void>;
}

const mapDispatchToProps = {
	getFolderContent: galleryActions.getFolderContent,
	getFoldersTree: galleryActions.getFoldersTree,
};

type IProps = IGalleryProps & IDispatchProps;

export default connect(mapStateToProps, mapDispatchToProps)(memo(Gallery));
