import "@mantine/core/styles.css";

import "./App.css";
import { Dropzone } from "./pages/components/Dropzone";

import { ActionIcon, AppShell, Box, Burger, Button, Group, LoadingOverlay, Modal, Progress, ScrollArea, Tabs, Text, Tooltip } from "@mantine/core";
import { useDisclosure, useHotkeys } from "@mantine/hooks";
import { notifications } from "@mantine/notifications";
import {
	IconChevronLeft,
	IconChevronRight,
	IconEdit,
	IconImageInPicture,
	IconPlus,
	IconRefreshDot,
	IconReportAnalytics,
	IconTrash,
} from "@tabler/icons-react";
import { useEffect, useMemo, useRef, useState } from "react";
import { ImageDetect } from "./pages/components/ImageDetect";
import ImageLabel from "./pages/components/ImageLabel";
import { useImagesDetected } from "./stores/use-images-detected";
import { SaveButton } from "./pages/components/SaveButton";
import { generateClientID } from "./ultils";
import ModalLabel from "./pages/components/ModalLabel";

function App() {
	const [mobileOpened, { toggle: toggleMobile }] = useDisclosure();
	const [desktopOpened, { toggle: toggleDesktop }] = useDisclosure(true);

	const [clickData, setClickData] = useState(null);
	const [listLabel, setListLabel] = useState([]);
	const [isLoading, setIsLoading] = useState(false);
	const [opened, { open, close }] = useDisclosure(false);
	const [dataLabel, setDataLabel] = useState({});
	const [openConfirm, setOpenConfirm] = useState(false);

	const { images, clearImagesDetected, appendImageDetect, setImageDetected } = useImagesDetected();

	const [progress, setProgress] = useState({ total: 0, processFiles: 0 });

	const imageLabelRef = useRef();
	const dropzoneRef = useRef();

	const fetchLabels = async () => {
		try {
			const response = await fetch(`${process.env.REACT_APP_API_URL}/labels`);
			// const response = await fetch(`http://127.0.0.1:5000/labels`);
			const result = await response.json();
			setListLabel(result);
		} catch (error) {
			console.log(error);
		}
	};

	useEffect(() => {
		fetchLabels();
	}, []);

	const handleClear = () => {
		// const result = window.confirm('Are you want to clear ?');

		const ID_NOTI = "handle-clear";
		notifications.show({
			id: ID_NOTI,
			title: "Are you want to clear ?",
			message: (
				<Box className="flex items-center gap-2 justify-end">
					<Button
						onClick={() => {
							setClickData(null);
							clearImagesDetected();
							notifications.hide(ID_NOTI);
						}}
						color="red"
						size="xs">
						Ok
					</Button>
					<Button onClick={() => notifications.hide(ID_NOTI)} size="xs">
						Cancel
					</Button>
				</Box>
			),
		});
	};

	const handleDeleteImage = (data, index) => {
		const ID_NOTI = "handle-delete-image";

		const deleteImage = async () => {
			try {
				const response = await fetch(`${process.env.REACT_APP_API_URL}/delete/${data.image_name}`, { method: "DELETE" });

				const result = await response.json();

				setClickData((prevClick) => (prevClick?.image_name === data.image_name ? null : prevClick));

				const newImages = images.filter((image) => image.image_name !== data.image_name);
				appendImageDetect(newImages);

				notifications.hide(ID_NOTI);
			} catch (error) {
				console.log(error);
			}
		};

		notifications.show({
			id: ID_NOTI,
			title: "Are you want to delete ?",
			message: (
				<Box className="flex items-center gap-2 justify-end">
					<Button onClick={deleteImage} color="red" size="xs">
						Ok
					</Button>
					<Button onClick={() => notifications.hide(ID_NOTI)} size="xs">
						Cancel
					</Button>
				</Box>
			),
		});
	};

	const handleAddImages = () => {
		// setClickData(null);

		if (dropzoneRef?.current) {
			dropzoneRef.current();
		}
	};

	const handleClearSelect = () => {
		setClickData(null);
	};

	const handleNext = () => {
		if (!images.length) return;

		if (!clickData) {
			setClickData(images[0]);
			return;
		}

		const findItem = images.find((item) => item?.image_name === clickData?.image_name);

		if (!findItem) return;

		const index = images.indexOf(findItem);

		const nextIndex = index + 1;

		if (index === -1 || nextIndex >= images.length) return;

		console.log(images[nextIndex]);
		setClickData(images[nextIndex]);
	};

	const handleUpload = async (files) => {
		if (!files) return;

		setProgress({
			total: files.length,
			processFiles: 0,
		});

		const worker = new Worker(new URL("./workers/detect-worker.js", import.meta.url));

		worker.onmessage = (event) => {
			if (event.data.status === "success") {
				if (event.data?.result) {
					setImageDetected(event.data.result);
					setProgress({
						total: event.data.total,
						processFiles: event.data.processFiles,
					});

					if (event.data.total === event.data.processFiles) {
						setProgress({
							total: 0,
							processFiles: 0,
						});
					}
				}
			} else {
				console.error("⚠️ Lỗi:", event.data.error);
			}
		};

		worker.postMessage({ action: "processImages", files });
	};

	const handlePrev = () => {
		if (!images.length) return;
		const findItem = images.find((item) => item?.image_name === clickData?.image_name);

		if (!findItem) return;

		const index = images.indexOf(findItem);
		const prevIndex = index - 1;

		if (index <= 0) return;

		setClickData(images[prevIndex]);
	};

	const showNext = useMemo(() => {
		if (!images.length) return false;

		if (clickData?.image_name === images[images.length - 1]?.image_name) return false;

		return true;
	}, [images, clickData]);

	const showPrev = useMemo(() => {
		if (!images.length || !clickData) return false;

		if (clickData?.image_name === images[0]?.image_name) return false;

		return true;
	}, [images, clickData]);

	const handleTraining = async () => {
		try {
			setIsLoading(true);
			setClickData(null);
			clearImagesDetected();
			const response = await fetch(`${process.env.REACT_APP_API_URL}/train`);
			// const response = await fetch(`http://127.0.0.1:5000/train`);
			const result = await response.json();
			if (result?.error) {
				notifications.show({
					title: "Failed",
					message: result?.error,
					color: "red",
				});
			} else
				notifications.show({
					title: "Success",
					message: `Training successfully!`,
					color: "green",
				});
			setIsLoading(false);
		} catch (error) {
			console.log(error);
			setIsLoading(false);
		}
	};

	const handleSave = async (value) => {
		try {
			setIsLoading(true);
			const url = `${process.env.REACT_APP_API_URL}/label/${value?.id ? "update" : "add"}`;
			// const url = `http://127.0.0.1:5000/label/${value?.id ? "update" : "add"}`;
			const response = await fetch(url, {
				method: "POST",
				headers: {
					"Content-Type": "application/json",
				},
				body: JSON.stringify(value),
			});
			const result = await response.json();
			if (!result?.success) {
				notifications.show({
					title: "Failed",
					message: result?.error,
					color: "red",
				});
			} else
				notifications.show({
					title: "Success",
					message: value?.id ? `Update label successfully!` : `Add label successfully!`,
					color: "green",
				});
			fetchLabels();
			setIsLoading(false);
		} catch (error) {
			console.log(error);
			setIsLoading(false);
		}
	};

	useHotkeys([
		["ArrowRight", handleNext],
		["ArrowLeft", handlePrev],
	]);

	return (
		<div style={{ position: "relative" }}>
			<AppShell
				header={{ height: 60 }}
				navbar={{
					width: 300,
					breakpoint: "sm",
					collapsed: { mobile: !mobileOpened, desktop: !desktopOpened },
				}}
				padding="md">
				<Tabs color="teal" defaultValue="detect">
					<AppShell.Header>
						<Box className="flex items-center justify-between h-full">
							<Group h="100%" px="md">
								<Burger opened={mobileOpened} onClick={toggleMobile} hiddenFrom="sm" size="sm" />
								<Burger opened={desktopOpened} onClick={toggleDesktop} visibleFrom="sm" size="sm" />
							</Group>
							<Box className="px-4 flex items-center gap-4 w-fit">
								<Tabs.List>
									<Tabs.Tab value="detect">
										<span style={{ fontSize: 20 }}>Detect</span>
									</Tabs.Tab>
									<Tabs.Tab value="config">
										<span style={{ fontSize: 20 }}>Config label</span>
									</Tabs.Tab>
								</Tabs.List>
							</Box>
							<Box className="px-4 flex items-center gap-4 w-fit">
								<Button disabled={isLoading} onClick={() => setOpenConfirm(true)} leftSection={<IconReportAnalytics size={14} />} color="#caa32c">
									Training
								</Button>
								<Button disabled={!clickData || isLoading} onClick={handleClearSelect} leftSection={<IconRefreshDot size={14} />} color="orange">
									Reset select
								</Button>
								<SaveButton
									disabled={isLoading}
									onSaved={(data) => {
										handleNext();
									}}
									currentData={clickData}
									imageLabelRef={imageLabelRef}
								/>
							</Box>
						</Box>
					</AppShell.Header>
					<Tabs.Panel value="detect">
						<AppShell.Navbar p="md">
							<Box className="flex flex-col justify-between gap-2 w-full h-full">
								<Box className="flex items-center justify-between gap-4 mb-2">
									<Button fullWidth disabled={!images.length || isLoading} onClick={handleClear} leftSection={<IconTrash size={14} />} color="red">
										Clear
									</Button>
									<Button fullWidth disabled={images.length || isLoading} onClick={handleAddImages} leftSection={<IconImageInPicture size={14} />}>
										Add images
									</Button>
								</Box>

								<ScrollArea h={780} className="pb-5 flex-1">
									<Box className="flex flex-col gap-3 w-full">
										{images.length > 0 &&
											images.map((item, index) => {
												return (
													<ImageDetect
														currentData={clickData}
														onClick={(data) => {
															console.log({ data });
															setClickData(data);
														}}
														key={`${item?.name || item?.image_name}_${index}`}
														file={item}
														onDelete={(data) => {
															handleDeleteImage(data, index);
														}}
													/>
												);
											})}
									</Box>

									{images.length <= 0 && (
										<Box className="flex items-center justify-center">
											<span>No images to process</span>
										</Box>
									)}
								</ScrollArea>

								{progress.total > 0 && (
									<Box className="flex flex-col items-center justify-end w-full">
										<Text>
											{progress.processFiles} / {progress.total}
										</Text>
										<Progress className="w-full" value={(progress.processFiles * 100) / progress.total} striped animated />
									</Box>
								)}
							</Box>
						</AppShell.Navbar>
						<AppShell.Main style={{ position: "relative" }}>
							{clickData && <ImageLabel ref={imageLabelRef} data={clickData} />}

							<Box
								style={{
									display: "flex",
									alignItems: "center",
									justifyContent: "center",
									gap: "10px",
									width: "100%",
									flexDirection: "column",
								}}>
								<Dropzone
									openRef={dropzoneRef}
									hidden={!clickData}
									onErorrFiles={(errors) => {
										notifications.show({
											title: "Invalid Images",
											message: `There ${errors.length === 1 ? "is" : "are"} ${errors.length} invalid image${
												errors.length > 1 ? "s" : ""
											}. Please re-check!`,
											color: "red",
										});
									}}
									onFilesChange={handleUpload}
								/>
							</Box>

							<Box className="fixed bottom-5 right-5 flex items-center gap-4">
								<Tooltip label={"Left (<)"}>
									<ActionIcon disabled={!showPrev} onClick={handlePrev} size={"lg"}>
										<IconChevronLeft size={20} />
									</ActionIcon>
								</Tooltip>
								<Tooltip label={"Right (>)"}>
									<ActionIcon disabled={!showNext} onClick={handleNext} size={"lg"}>
										<IconChevronRight size={20} />
									</ActionIcon>
								</Tooltip>
							</Box>
						</AppShell.Main>
					</Tabs.Panel>
					<Tabs.Panel value="config">
						<AppShell.Main style={{ position: "relative", paddingLeft: 0 }}>
							<ScrollArea h={780} className="pb-5 flex-1">
								<Box className="flex justify-end pe-4">
									<Button disabled={isLoading} leftSection={<IconPlus size={14} />} color="#1a9b20" onClick={open}>
										Add
									</Button>
								</Box>
								<div className="flex justify-center items-center">
									<Box w={600} className="mt-4">
										{listLabel.length > 0 &&
											listLabel?.map((item, index) => {
												return (
													<Box w={600} key={index} className="flex items-center justify-between mb-4">
														<Text>{item?.name}</Text>
														<div className="flex items-center justify-between gap-4">
															<Button
																disabled={isLoading}
																leftSection={<IconEdit size={14} />}
																color="#0659a5"
																onClick={() => {
																	open();
																	setDataLabel(item);
																}}>
																Edit
															</Button>
														</div>
													</Box>
												);
											})}
									</Box>
								</div>
							</ScrollArea>
						</AppShell.Main>
					</Tabs.Panel>
				</Tabs>
				<LoadingOverlay
					visible={isLoading}
					zIndex={10}
					overlayProps={{ radius: "sm", blur: 2 }}
					loaderProps={{
						size: "lg",
					}}
				/>
				<ModalLabel
					opened={opened}
					open={open}
					close={() => {
						close();
						setDataLabel({});
					}}
					data={dataLabel}
					onSave={() => {
						close();
						setDataLabel({});
						setIsLoading(true);
						handleSave(dataLabel);
						setTimeout(() => {
							setIsLoading(false);
						}, 2000);
					}}
					setData={setDataLabel}
				/>

				<Modal opened={openConfirm} onClose={() => setOpenConfirm(false)} title={"Confirm"}>
					<div style={{ padding: 20 }} className="flex flex-col gap-4 justify-center items-center">
						<div>Do you want to run training?</div>
						<div>Maybe you need to save some data to train!</div>
					</div>
					<div style={{ padding: 20 }} className="flex justify-center gap-4">
						<Button
							onClick={() => {
								setOpenConfirm(false);
							}}>
							Cancel
						</Button>
						<Button
							onClick={() => {
								setOpenConfirm(false);
								handleTraining();
							}}
							color="#1a9b20">
							Confirm
						</Button>
					</div>
				</Modal>
			</AppShell>
		</div>
	);
}

export default App;
