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

import {
	BackFolder,
	EmptyState,
	ErrorToast,
	FilterTagsBar,
	Icon,
	Loader,
	Notification,
	SearchField,
	SearchTagsBar,
	Tabs,
	Tooltip,
} from "@ax/components";
import { fileDriveActions } from "@ax/containers/FileDrive";
import { usePermission, useResizable } from "@ax/hooks";
// refactor
import Breadcrumb from "@ax/modules/FileDrive/Breadcrumb";
import SortBy from "@ax/modules/FileDrive/FileFilters/SortBy";
import Type from "@ax/modules/FileDrive/FileFilters/Type";
import FolderTree from "@ax/modules/FileDrive/FolderTree";
import { useFilterQuery, useSortedListStatus } from "@ax/modules/FileDrive/hooks";
import { getSortedListStatus } from "@ax/modules/FileDrive/utils";
import type {
	IFile,
	IFilesFolder,
	IFolder,
	IFolderTree,
	IGetFolderParams,
	IQueryValue,
	IRootState,
	ISite,
} from "@ax/types";

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

import * as S from "./style";

const FileGallery = (props: IProps): JSX.Element => {
	const {
		currentFolderContent,
		site,
		currentFolderID,
		customFormats,
		breadcrumb,
		toggleModal,
		getFolderContent,
		getFoldersTree,
		addFile,
		updateCurrentFolder,
	} = props;

	const {
		files: { items },
		folders,
	} = currentFolderContent || { files: { items: [] }, folders: [] };

	const [selectedTab, setSelectedTab] = useState(site ? "local" : "global");
	const [selectedFile, setSelectedFile] = useState<IFile | null>(null);
	const [isPanelOpen, setPanelOpen] = useState(false);
	const [isLoading, setIsLoading] = useState(false);
	const isLocalTab = selectedTab === "local";
	const isGlobalTab = selectedTab === "global";
	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.accessToGlobalFileDriveFromSite");

	const allowedToAddSiteFile = usePermission("mediaGallery.addFiles");
	const allowedToAddGlobalFile = usePermission("global.mediaGallery.addGlobalFiles");
	const allowedToAddGlobalFileFromSite = usePermission("mediaGallery.addGlobalFilesFromSite");
	const allowedToAddFile = !isSiteView
		? allowedToAddGlobalFile
		: isTabGlobal
			? allowedToAddGlobalFileFromSite
			: allowedToAddSiteFile;

	const allowedToEditSiteFile = usePermission("mediaGallery.editFilesss");
	const allowedToEditGlobalFile = usePermission("global.mediaGallery.editGlobalFiles");
	const allowedToEditGlobalFileFromSite = usePermission("mediaGallery.editGlobalFilesInSite");
	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,
		};

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

	// biome-ignore lint/correctness/useExhaustiveDependencies: TODO: fix this
	useLayoutEffect(() => {
		return () => {
			updateCurrentFolder(null);
		};
	}, []);

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

	// biome-ignore lint/correctness/useExhaustiveDependencies: TODO: fix this
	useEffect(() => {
		const handleGetTree = async () => await getFoldersTree(siteID);
		handleGetTree();
	}, [selectedTab]);

	const handleClick = (item: IFile) => {
		if (item.id !== selectedFile?.id) {
			setSelectedFile(item);
		} else {
			setSelectedFile(null);
		}
	};

	const setFile = (fileData: any) => {
		const updatedImage = { ...selectedFile, ...fileData };
		addFile(updatedImage);
		toggleModal();
	};

	const handleSelectedTab = (tab: string) => {
		if (tab !== selectedTab) {
			updateCurrentFolder(null);
			setSelectedFile(null);
			setSelectedTab(tab);
		}
	};

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

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

	const handleUpload = async (file: IFile[]) => {
		setSelectedFile(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 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 documents found in this folder.",
	};

	const filters = (
		<>
			<Type filterItems={filterItems} value={filterValues["filterType"]} />
			<SortBy sortItems={sortItems} sortedState={sortedListStatus} />
		</>
	);

	return (
		<S.Wrapper data-testid="file-gallery-wrapper">
			<S.FolderPanel isOpen={isPanelOpen} ref={ref}>
				<S.FolderPanelContent>
					<FolderTree folderID={currentFolderID || 0} onClick={updateCurrentFolder} 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={setSearchQuery}
						value={searchQuery}
						placeholder="Type file’s name, title, or #tag"
						focus={false}
					/>
				</S.Search>
				<S.GalleryWrapper ref={galleryRef}>
					{isGlobalTab && isSiteView && (
						<S.NotificationWrapper>
							<Notification
								type="info"
								text="This is a global Library. All the changes you make will be applied to all the sites."
							/>
						</S.NotificationWrapper>
					)}
					<ErrorToast size="l" />
					{isLoading ? (
						<S.LoadingWrapper>
							<Loader name="circle" />
						</S.LoadingWrapper>
					) : (
						<>
							<S.SearchTags>
								<SearchTagsBar query={searchQuery} setQuery={setSearchQuery} />
								<FilterTagsBar
									filters={filterValues}
									setFilters={setFiltersSelection}
									labels={{ filterType: "Type" }}
									resetFilters={resetFilterQuery}
								/>
							</S.SearchTags>
							{!isRoot && !isSearching && <Breadcrumb breadcrumb={breadcrumb} onClick={updateCurrentFolder} />}
							{(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={updateCurrentFolder} key={folder.folderName} />
											))}
										</S.FoldersGrid>
									</S.FoldersWrapper>
								</S.SectionWrapper>
							)}
							<S.SectionWrapper>
								<S.SectionHeader>
									<S.SectionTitle>Documents</S.SectionTitle>
								</S.SectionHeader>
								{!items.length ? (
									<S.EmptyWrapper>
										{isSearching ? (
											<EmptyState {...emptySearchStateProps} />
										) : (
											<EmptyState {...emptyFolderStateProps} />
										)}
									</S.EmptyWrapper>
								) : (
									<S.Grid>
										{items?.map((item: IFile) => {
											const isSelected = item.id === selectedFile?.id;
											return <GridItem file={item} onClick={handleClick} key={item.fileName} isSelected={isSelected} />;
										})}
									</S.Grid>
								)}
							</S.SectionWrapper>
						</>
					)}
				</S.GalleryWrapper>
			</S.ContentWrapper>
			<GalleryPanel
				selectedFile={selectedFile}
				customFormats={customFormats}
				setFile={setFile}
				scope={galleryScope}
				currentFolderID={currentFolderID}
				handleUpload={handleUpload}
				isAllowedToAdd={allowedToAddFile}
				isAllowedToEdit={allowedToEditFile}
			/>
		</S.Wrapper>
	);
};

export interface IGalleryProps {
	site: ISite | null;
	currentFolderContent: IFilesFolder | null;
	currentFolderID: number | null;
	isLoading: boolean;
	customFormats?: string[];
	breadcrumb: IFolderTree[];
	toggleModal: () => void;
	addFile: (file: IFile) => void;
}

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

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

const mapDispatchToProps = {
	getFolderContent: fileDriveActions.getFolderContent,
	getFoldersTree: fileDriveActions.getFoldersTree,
	updateCurrentFolder: fileDriveActions.updateCurrentFolder,
};

type IProps = IGalleryProps & IDispatchProps;

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