// React, Redux, Router
import { useTheme } from "@emotion/react";
import { useParams } from "react-router-dom";
import { useState, useEffect } from "react";
import { useSelector } from "react-redux";

// Utility and Network
import { infrastructureMonitorValidation } from "../../../Validation/validation";
import { useFetchHardwareMonitorById } from "../../../Hooks/monitorHooks";
import { capitalizeFirstLetter } from "../../../Utils/stringUtils";
import { useTranslation } from "react-i18next";
import { useGetNotificationsByTeamId } from "../../../Hooks/useNotifications";
import NotificationsConfig from "../../../Components/NotificationConfig";
import { useUpdateMonitor, useCreateMonitor } from "../../../Hooks/monitorHooks";

// MUI
import { Box, Stack, Typography, Button, ButtonGroup } from "@mui/material";

//Components
import Breadcrumbs from "../../../Components/Breadcrumbs";
import Link from "../../../Components/Link";
import ConfigBox from "../../../Components/ConfigBox";
import TextInput from "../../../Components/Inputs/TextInput";
import { HttpAdornment } from "../../../Components/Inputs/TextInput/Adornments";
import { createToast } from "../../../Utils/toastUtils";
import Select from "../../../Components/Inputs/Select";
import { CustomThreshold } from "./Components/CustomThreshold";

const SELECT_VALUES = [
	{ _id: 0.25, name: "15 seconds" },
	{ _id: 0.5, name: "30 seconds" },
	{ _id: 1, name: "1 minute" },
	{ _id: 2, name: "2 minutes" },
	{ _id: 5, name: "5 minutes" },
	{ _id: 10, name: "10 minutes" },
];

const METRICS = ["cpu", "memory", "disk", "temperature"];
const METRIC_PREFIX = "usage_";
const MS_PER_MINUTE = 60000;

const hasAlertError = (errors) => {
	return Object.keys(errors).filter((k) => k.startsWith(METRIC_PREFIX)).length > 0;
};

const getAlertError = (errors) => {
	return Object.keys(errors).find((key) => key.startsWith(METRIC_PREFIX))
		? errors[Object.keys(errors).find((key) => key.startsWith(METRIC_PREFIX))]
		: null;
};

const CreateInfrastructureMonitor = () => {
	const theme = useTheme();
	const { user } = useSelector((state) => state.auth);
	const { monitorId } = useParams();
	const { t } = useTranslation();

	// Determine if we are creating or editing
	const isCreate = typeof monitorId === "undefined";

	// Fetch monitor details if editing
	const [monitor, isLoading, networkError] = useFetchHardwareMonitorById({ monitorId });
	const [notifications, notificationsAreLoading, notificationsError] =
		useGetNotificationsByTeamId();
	const [updateMonitor, isUpdating] = useUpdateMonitor();
	const [createMonitor, isCreating] = useCreateMonitor();

	// State
	const [errors, setErrors] = useState({});
	const [https, setHttps] = useState(false);
	const [infrastructureMonitor, setInfrastructureMonitor] = useState({
		url: "",
		name: "",
		notifications: [],
		notify_email: false,
		interval: 0.25,
		cpu: false,
		usage_cpu: "",
		memory: false,
		usage_memory: "",
		disk: false,
		usage_disk: "",
		temperature: false,
		usage_temperature: "",
		secret: "",
	});

	// Populate form fields if editing
	useEffect(() => {
		if (isCreate || !monitor) return;

		setInfrastructureMonitor({
			url: monitor.url.replace(/^https?:\/\//, ""),
			name: monitor.name || "",
			notifications: monitor.notifications,
			interval: monitor.interval / MS_PER_MINUTE,
			cpu: monitor.thresholds?.usage_cpu !== undefined,
			usage_cpu: monitor.thresholds?.usage_cpu ? monitor.thresholds.usage_cpu * 100 : "",

			memory: monitor.thresholds?.usage_memory !== undefined,
			usage_memory: monitor.thresholds?.usage_memory
				? monitor.thresholds.usage_memory * 100
				: "",

			disk: monitor.thresholds?.usage_disk !== undefined,
			usage_disk: monitor.thresholds?.usage_disk
				? monitor.thresholds.usage_disk * 100
				: "",

			temperature: monitor.thresholds?.usage_temperature !== undefined,
			usage_temperature: monitor.thresholds?.usage_temperature
				? monitor.thresholds.usage_temperature * 100
				: "",
			secret: monitor.secret || "",
		});
		setHttps(monitor.url.startsWith("https"));
	}, [isCreate, monitor]);

	// Handlers
	const onSubmit = async (event) => {
		event.preventDefault();

		// Build the form
		let form = {
			url: `http${https ? "s" : ""}://` + infrastructureMonitor.url,
			name:
				infrastructureMonitor.name === ""
					? infrastructureMonitor.url
					: infrastructureMonitor.name,
			interval: infrastructureMonitor.interval * MS_PER_MINUTE,
			cpu: infrastructureMonitor.cpu,
			...(infrastructureMonitor.cpu
				? { usage_cpu: infrastructureMonitor.usage_cpu }
				: {}),
			memory: infrastructureMonitor.memory,
			...(infrastructureMonitor.memory
				? { usage_memory: infrastructureMonitor.usage_memory }
				: {}),
			disk: infrastructureMonitor.disk,
			...(infrastructureMonitor.disk
				? { usage_disk: infrastructureMonitor.usage_disk }
				: {}),
			temperature: infrastructureMonitor.temperature,
			...(infrastructureMonitor.temperature
				? { usage_temperature: infrastructureMonitor.usage_temperature }
				: {}),
			secret: infrastructureMonitor.secret,
		};

		const { error } = infrastructureMonitorValidation.validate(form, {
			abortEarly: false,
		});

		if (error) {
			const newErrors = {};
			error.details.forEach((err) => {
				newErrors[err.path[0]] = err.message;
			});
			console.log(newErrors);
			setErrors(newErrors);
			createToast({ body: "Please check the form for errors." });
			return;
		}

		// Build the thresholds for the form
		const {
			cpu,
			usage_cpu,
			memory,
			usage_memory,
			disk,
			usage_disk,
			temperature,
			usage_temperature,
			...rest
		} = form;

		const thresholds = {
			...(cpu ? { usage_cpu: usage_cpu / 100 } : {}),
			...(memory ? { usage_memory: usage_memory / 100 } : {}),
			...(disk ? { usage_disk: usage_disk / 100 } : {}),
			...(temperature ? { usage_temperature: usage_temperature / 100 } : {}),
		};

		form = {
			...(isCreate ? {} : { _id: monitorId }),
			...rest,
			description: form.name,
			type: "hardware",
			notifications: infrastructureMonitor.notifications,
			thresholds,
		};

		// Handle create or update
		isCreate
			? await createMonitor({ monitor: form, redirect: "/infrastructure" })
			: await updateMonitor({ monitor: form, redirect: "/infrastructure" });
	};

	const onChange = (event) => {
		const { value, name } = event.target;
		setInfrastructureMonitor({
			...infrastructureMonitor,
			[name]: value,
		});

		const { error } = infrastructureMonitorValidation.validate(
			{ [name]: value },
			{ abortEarly: false }
		);
		setErrors((prev) => ({
			...prev,
			...(error ? { [name]: error.details[0].message } : { [name]: undefined }),
		}));
	};

	const handleCheckboxChange = (event) => {
		const { name } = event.target;
		const { checked } = event.target;
		setInfrastructureMonitor({
			...infrastructureMonitor,
			[name]: checked,
		});
	};

	return (
		<Box className="create-infrastructure-monitor">
			<Breadcrumbs
				list={[
					{ name: "Infrastructure monitors", path: "/infrastructure" },
					...(isCreate
						? [{ name: "Create", path: "/infrastructure/create" }]
						: [
								{ name: "Details", path: `/infrastructure/${monitorId}` },
								{ name: "Configure", path: `/infrastructure/configure/${monitorId}` },
							]),
				]}
			/>
			<Stack
				component="form"
				onSubmit={onSubmit}
				noValidate
				spellCheck="false"
				gap={theme.spacing(12)}
				mt={theme.spacing(6)}
			>
				<Typography
					component="h1"
					variant="h1"
				>
					<Typography
						component="span"
						fontSize="inherit"
					>
						{t(isCreate ? "infrastructureCreateYour" : "infrastructureEditYour")}{" "}
					</Typography>
					<Typography
						component="span"
						variant="h2"
						fontSize="inherit"
						fontWeight="inherit"
					>
						{t("monitor")}
					</Typography>
				</Typography>
				<ConfigBox>
					<Stack gap={theme.spacing(6)}>
						<Typography
							component="h2"
							variant="h2"
						>
							{t("settingsGeneralSettings")}
						</Typography>
						<Typography component="p">
							{t("infrastructureCreateGeneralSettingsDescription")}
						</Typography>
						<Typography component="p">
							{t("infrastructureServerRequirement")}{" "}
							<Link
								level="primary"
								url="https://github.com/bluewave-labs/checkmate-agent"
								label={t("common.monitoringAgentName")}
							/>
						</Typography>
					</Stack>
					<Stack gap={theme.spacing(15)}>
						<TextInput
							type="url"
							id="url"
							name="url"
							startAdornment={<HttpAdornment https={https} />}
							placeholder={"localhost:59232/api/v1/metrics"}
							label={t("infrastructureServerUrlLabel")}
							https={https}
							value={infrastructureMonitor.url}
							onChange={onChange}
							error={errors["url"] ? true : false}
							helperText={errors["url"]}
							disabled={!isCreate}
						/>
						{isCreate && (
							<Box>
								<Typography component="p">{t("infrastructureProtocol")}</Typography>
								<ButtonGroup>
									<Button
										variant="group"
										filled={https.toString()}
										onClick={() => setHttps(true)}
									>
										{t("https")}
									</Button>
									<Button
										variant="group"
										filled={(!https).toString()}
										onClick={() => setHttps(false)}
									>
										{t("http")}
									</Button>
								</ButtonGroup>
							</Box>
						)}
						<TextInput
							type="text"
							id="name"
							name="name"
							label={t("infrastructureDisplayNameLabel")}
							placeholder="Google"
							isOptional={true}
							value={infrastructureMonitor.name}
							onChange={onChange}
							error={errors["name"]}
						/>
						<TextInput
							type="text"
							id="secret"
							name="secret"
							label={t("infrastructureAuthorizationSecretLabel")}
							value={infrastructureMonitor.secret}
							onChange={onChange}
							error={errors["secret"] ? true : false}
							helperText={errors["secret"]}
						/>
					</Stack>
				</ConfigBox>
				<ConfigBox>
					<Box>
						<Typography component="h2">{t("notificationConfig.title")}</Typography>
						<Typography component="p">{t("notificationConfig.description")}</Typography>
					</Box>
					<NotificationsConfig
						notifications={notifications}
						setMonitor={setInfrastructureMonitor}
						setNotifications={infrastructureMonitor.notifications}
					/>
				</ConfigBox>
				<ConfigBox>
					<Box>
						<Typography
							component="h2"
							variant="h2"
						>
							{t("infrastructureCustomizeAlerts")}
						</Typography>
						<Typography component="p">
							{t("infrastructureAlertNotificationDescription")}
						</Typography>
					</Box>
					<Stack gap={theme.spacing(6)}>
						{METRICS.map((metric) => {
							return (
								<CustomThreshold
									key={metric}
									infrastructureMonitor={infrastructureMonitor}
									errors={errors}
									checkboxId={metric}
									checkboxName={metric}
									checkboxLabel={
										metric !== "cpu"
											? capitalizeFirstLetter(metric)
											: metric.toUpperCase()
									}
									onCheckboxChange={handleCheckboxChange}
									isChecked={infrastructureMonitor[metric]}
									fieldId={METRIC_PREFIX + metric}
									fieldName={METRIC_PREFIX + metric}
									fieldValue={String(infrastructureMonitor[METRIC_PREFIX + metric])}
									onFieldChange={onChange}
									alertUnit={metric == "temperature" ? "°C" : "%"}
								/>
							);
						})}
						{/* Error text */}
						{hasAlertError(errors) && (
							<Typography
								component="span"
								className="input-error"
								color={theme.palette.error.main}
								mt={theme.spacing(2)}
								sx={{
									opacity: 0.8,
								}}
							>
								{getAlertError(errors)}
							</Typography>
						)}
					</Stack>
				</ConfigBox>
				<ConfigBox>
					<Box>
						<Typography
							component="h2"
							variant="h2"
						>
							{t("distributedUptimeCreateAdvancedSettings")}
						</Typography>
					</Box>
					<Stack gap={theme.spacing(12)}>
						<Select
							id="interval"
							name="interval"
							label="Check frequency"
							value={infrastructureMonitor.interval || 15}
							onChange={onChange}
							items={SELECT_VALUES}
						/>
					</Stack>
				</ConfigBox>
				<Stack
					direction="row"
					justifyContent="flex-end"
				>
					<Button
						type="submit"
						variant="contained"
						color="accent"
						loading={isLoading || isUpdating || isCreating || notificationsAreLoading}
					>
						{t(isCreate ? "infrastructureCreateMonitor" : "infrastructureEditMonitor")}
					</Button>
				</Stack>
			</Stack>
		</Box>
	);
};

export default CreateInfrastructureMonitor;
