import React, { useCallback, useEffect, useRef, useState } from "react";
import { connect } from "react-redux";
import { format, subDays } from "date-fns";

import { LogActivityExportRequest, LogActivityPaginationRequest } from "@griddo/api-types";
import { ILogItemsByDay, ILogItemsByUser, IQueryValue, IRootState, IStructuredData } from "@ax/types";
import { EmptyState, ErrorToast, FilterTagsBar, MainWrapper, SearchTagsBar, Select, TableList } from "@ax/components";
import { activityLogActions } from "@ax/containers/ActivityLog";
import { structuredDataActions } from "@ax/containers/StructuredData";
import { useModal } from "@ax/hooks";

import { useFilterQuery } from "./hooks";
import TableHeader from "./TableHeader";
import ItemLog from "./ItemLog";
import ItemLogUser from "./ItemLogUser";
import DownloadModal from "./DownloadModal";

import * as S from "./style";

const ActivityLog = (props: IActivityLogProps) => {
	const {
		activityLog,
		listMode,
		setListMode,
		getActivityLog,
		getActivityLogByUser,
		downloadActivityLog,
		getStructuredData,
		setCurrentData,
	} = props;

	const itemsPerPage = 100;
	const firstPage = 1;
	const [page, setPage] = useState(firstPage);
	const [isScrolling, setIsScrolling] = useState(false);
	const [searchQuery, setSearchQuery] = useState<string>("");
	const [isSortAscending, setIsSortAscending] = useState(false);
	const initialState: IDownloadFormState = {
		dateRange: "7",
		startTime: null,
		maxEvents: 0,
		format: "csv",
		startDate: null,
		endDate: null,
	};
	const [downloadForm, setDownloadForm] = useState(initialState);
	const { setFiltersSelection, resetFilterQuery, filterValues, filterQuery } = useFilterQuery();
	const tableRef = useRef<HTMLDivElement>(null);
	const { isOpen: isDownloadOpen, toggleModal: toggleDownloadModal } = useModal();

	const { totalItems } = activityLog;
	const isEmpty = totalItems === 0;
	const isModeUser = listMode === "user";
	const isSearching = searchQuery.length > 0;

	const getParams = useCallback(() => {
		const params: LogActivityPaginationRequest = {
			page,
			itemsPerPage,
			...(isSortAscending && { order: "ASC" }),
			...(searchQuery.length && { search: searchQuery }),
			...filterQuery,
		};

		return params;
	}, [page, filterQuery, isSortAscending, searchQuery]);

	const handleGetLog = async () => {
		const params = getParams();
		if (isModeUser) {
			await getActivityLogByUser(params);
		} else {
			await getActivityLog(params);
		}
	};

	const handleUpdateStructuredDate = async () => await getStructuredData(null, null, false);

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

	// biome-ignore lint/correctness/useExhaustiveDependencies: TODO: fix this
	useEffect(() => {
		handleUpdateStructuredDate();
		setCurrentData(null);
	}, []);

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

	const handleSelectChange = async (value: string) => {
		const params = getParams();
		if (value === "user") {
			await getActivityLogByUser({ ...params, page: firstPage });
		} else {
			await getActivityLog({ ...params, page: firstPage });
		}
		setListMode(value);
	};

	const sortItems = async (isAscending: boolean) => {
		setPage(firstPage);
		setIsSortAscending(isAscending);
	};

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

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

	const handleDownloadLog = async () => {
		const nowString = format(new Date(), "yyyy/MM/dd");
		let startDate = nowString;
		let endDate = nowString;

		if (downloadForm.dateRange === "7") {
			startDate = format(subDays(new Date(), 7), "yyyy/MM/dd");
		}

		if (downloadForm.dateRange === "30") {
			startDate = format(subDays(new Date(), 30), "yyyy/MM/dd");
		}

		if (downloadForm.dateRange === "custom" && downloadForm.startDate && downloadForm.endDate) {
			startDate = format(new Date(downloadForm.startDate), "yyyy/MM/dd");
			endDate = format(new Date(downloadForm.endDate), "yyyy/MM/dd");
		}

		const data: LogActivityExportRequest = {
			dateRange: `${startDate}-${endDate}`,
			startTime: downloadForm.startTime,
			maxEvents: downloadForm.maxEvents ? downloadForm.maxEvents : null,
			format: [downloadForm.format],
		};

		await downloadActivityLog(data);

		toggleDownloadModal();
		setDownloadForm(initialState);
	};

	const header = (
		<TableHeader
			isScrolling={isScrolling}
			filterItems={filterItems}
			filterValues={filterValues}
			sortItems={sortItems}
			isSortAscending={isSortAscending}
			isModeUser={isModeUser}
		/>
	);

	const pagination = {
		setPage,
		itemsPerPage,
		totalItems,
		currPage: page,
	};

	const rightButtonProps = {
		label: "Refresh",
		action: handleGetLog,
		buttonStyle: "line",
		icon: "refresh",
	};

	const rightLineButtonProps = {
		label: "Download",
		action: toggleDownloadModal,
		buttonStyle: "text",
		icon: "download",
	};

	const mainDownloadAction = { title: "Download", onClick: handleDownloadLog };

	const selectOptions = [
		{ value: "default", label: "Activity timeline" },
		{ value: "user", label: "Grouped by user" },
	];

	const filterLabels = {
		date: "Date",
		users: "User",
		sites: "Site",
		contentTypes: "Content Type",
		eventTypes: "Event",
	};

	const emptyProps = {
		message: (
			<>
				You will start to see the User Activity Log when you
				<br />
				make some changes.
			</>
		),
	};

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

	return (
		<MainWrapper
			title="Logs"
			rightButton={rightButtonProps}
			rightLineButton={rightLineButtonProps}
			searchAction={handleSearch}
			searchValue={searchQuery}
		>
			<S.TableWrapper>
				<ErrorToast />
				<S.Intro>
					<S.IntroContent>
						<S.IntroTitle>User Activity Log</S.IntroTitle>
						<div>
							<strong>Track</strong> and record <strong>all actions performed by users</strong> on the Griddo. This
							enables monitoring, and issue identification,
							<br />
							and ensures the security and integrity of content and data within the system.
							<br />
							For more details on each action, please refer to the Activity Log Glossary.
						</div>
					</S.IntroContent>
					<S.SelectWrapper>
						<Select
							name="visualSelect"
							value={listMode}
							options={selectOptions}
							onChange={handleSelectChange}
							mandatory={true}
						/>
					</S.SelectWrapper>
				</S.Intro>
				<TableList
					tableHeader={header}
					onScroll={onScroll}
					pagination={pagination}
					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>
							{isSearching && <EmptyState {...emptySearchStateProps} />}
							{!isSearching && <EmptyState {...emptyProps} />}
						</S.EmptyWrapper>
					) : (
						<>
							{isModeUser
								? (activityLog as ILogItemsByUser).items.map((item) => (
										<ItemLogUser key={item.date} items={item} getLog={handleGetLog} />
									))
								: (activityLog as ILogItemsByDay).items.map((item) => (
										<ItemLog key={item.date} items={item} getLog={handleGetLog} />
									))}
						</>
					)}
				</TableList>
			</S.TableWrapper>
			<DownloadModal
				isOpen={isDownloadOpen}
				toggleModal={toggleDownloadModal}
				mainModalAction={mainDownloadAction}
				form={downloadForm}
				setForm={setDownloadForm}
			/>
		</MainWrapper>
	);
};

export interface IDownloadFormState {
	dateRange: string;
	startTime: string | null;
	maxEvents: number | null;
	format: string;
	startDate: string | null;
	endDate: string | null;
}

interface IActivityLogProps {
	activityLog: ILogItemsByDay | ILogItemsByUser;
	listMode: string;
	getActivityLog(params: LogActivityPaginationRequest): Promise<void>;
	getActivityLogByUser(params: LogActivityPaginationRequest): Promise<void>;
	setListMode(listMode: string): void;
	downloadActivityLog(data: LogActivityExportRequest): Promise<void>;
	getStructuredData(token: string | null, siteID?: number | null, hasLoading?: boolean): Promise<void>;
	setCurrentData(currentStructuredData: IStructuredData | null): void;
}

const mapStateToProps = (state: IRootState) => ({
	activityLog: state.activityLog.activityLog,
	listMode: state.activityLog.listMode,
});

const mapDispatchToProps = {
	getActivityLog: activityLogActions.getActivityLog,
	getActivityLogByUser: activityLogActions.getActivityLogByUser,
	setListMode: activityLogActions.setListMode,
	downloadActivityLog: activityLogActions.downloadActivityLog,
	getStructuredData: structuredDataActions.getStructuredData,
	setCurrentData: structuredDataActions.setCurrentData,
};

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