import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useQueryClient } from 'react-query';
// eslint-disable-next-line no-restricted-imports
import { useSelector } from 'react-redux';
import { useLocation } from 'react-router-dom';
import { ExclamationCircleOutlined, SaveOutlined } from '@ant-design/icons';
import { Button, FormInstance, Modal, SelectProps, Typography } from 'antd';
import logEvent from 'api/common/logEvent';
import { convertToApiError } from 'api/ErrorResponseHandlerForGeneratedAPIs';
import {
	createRule,
	testRule,
	updateRuleByID,
} from 'api/generated/services/rules';
import type { RenderErrorResponseDTO } from 'api/generated/services/sigNoz.schemas';
import { AxiosError } from 'axios';
import { getInvolvedQueriesInTraceOperator } from 'components/QueryBuilderV2/QueryV2/TraceOperator/utils/utils';
import YAxisUnitSelector from 'components/YAxisUnitSelector';
import { YAxisSource } from 'components/YAxisUnitSelector/types';
import { ALERTS_DATA_SOURCE_MAP } from 'constants/alerts';
import { FeatureKeys } from 'constants/features';
import { QueryParams } from 'constants/query';
import { PANEL_TYPES } from 'constants/queryBuilder';
import { REACT_QUERY_KEY } from 'constants/reactQueryKeys';
import ROUTES from 'constants/routes';
import QueryTypeTag from 'container/NewWidget/LeftContainer/QueryTypeTag';
import PlotTag from 'container/NewWidget/LeftContainer/WidgetGraph/PlotTag';
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
import { useShareBuilderUrl } from 'hooks/queryBuilder/useShareBuilderUrl';
import useGetYAxisUnit from 'hooks/useGetYAxisUnit';
import { useNotifications } from 'hooks/useNotifications';
import { useSafeNavigate } from 'hooks/useSafeNavigate';
import useUrlQuery from 'hooks/useUrlQuery';
import { mapQueryDataFromApi } from 'lib/newQueryBuilder/queryBuilderMappers/mapQueryDataFromApi';
import { mapQueryDataToApi } from 'lib/newQueryBuilder/queryBuilderMappers/mapQueryDataToApi';
import { isEmpty, isEqual } from 'lodash-es';
import { BellDot, ExternalLink } from 'lucide-react';
import Tabs2 from 'periscope/components/Tabs2';
import { useAppContext } from 'providers/App/App';
import { useErrorModal } from 'providers/ErrorModalProvider';
import { AppState } from 'store/reducers';
import { AlertTypes } from 'types/api/alerts/alertTypes';
import { toPostableRuleDTOFromAlertDef } from 'types/api/alerts/convert';
import {
	AlertDef,
	defaultEvalWindow,
	defaultMatchType,
} from 'types/api/alerts/def';
import APIError from 'types/api/error';
import { IBuilderQuery, Query } from 'types/api/queryBuilder/queryBuilderData';
import { QueryFunction } from 'types/api/v5/queryRange';
import { EQueryType } from 'types/common/dashboard';
import { DataSource } from 'types/common/queryBuilder';
import { GlobalReducer } from 'types/reducer/globalTime';
import { isModifierKeyPressed } from 'utils/app';
import { compositeQueryToQueryEnvelope } from 'utils/compositeQueryToQueryEnvelope';
import { openInNewTab } from 'utils/navigation';

import BasicInfo from './BasicInfo';
import ChartPreview from './ChartPreview';
import QuerySection from './QuerySection';
import RuleOptions from './RuleOptions';
import {
	ActionButton,
	ButtonContainer,
	MainFormContainer,
	StepContainer,
	StepHeading,
} from './styles';
import { usePrefillAlertConditions } from './usePrefillAlertConditions';
import { getSelectedQueryOptions } from './utils';

import './FormAlertRules.styles.scss';

export enum AlertDetectionTypes {
	THRESHOLD_ALERT = 'threshold_rule',
	ANOMALY_DETECTION_ALERT = 'anomaly_rule',
}

const ALERT_SETUP_GUIDE_URLS: Record<AlertTypes, string> = {
	[AlertTypes.METRICS_BASED_ALERT]:
		'https://signoz.io/docs/alerts-management/metrics-based-alerts/?utm_source=product&utm_medium=alert-creation-page',
	[AlertTypes.LOGS_BASED_ALERT]:
		'https://signoz.io/docs/alerts-management/log-based-alerts/?utm_source=product&utm_medium=alert-creation-page',
	[AlertTypes.TRACES_BASED_ALERT]:
		'https://signoz.io/docs/alerts-management/trace-based-alerts/?utm_source=product&utm_medium=alert-creation-page',
	[AlertTypes.EXCEPTIONS_BASED_ALERT]:
		'https://signoz.io/docs/alerts-management/exceptions-based-alerts/?utm_source=product&utm_medium=alert-creation-page',
	[AlertTypes.ANOMALY_BASED_ALERT]:
		'https://signoz.io/docs/alerts-management/anomaly-based-alerts/?utm_source=product&utm_medium=alert-creation-page',
};

// eslint-disable-next-line sonarjs/cognitive-complexity
function FormAlertRules({
	alertType,
	formInstance,
	initialValue,
	ruleId,
}: FormAlertRuleProps): JSX.Element {
	// init namespace for translations
	const { t } = useTranslation('alerts');
	const { featureFlags } = useAppContext();
	const { safeNavigate } = useSafeNavigate();
	const { selectedTime: globalSelectedInterval } = useSelector<
		AppState,
		GlobalReducer
	>((state) => state.globalTime);

	const urlQuery = useUrlQuery();
	const location = useLocation();
	const queryParams = new URLSearchParams(location.search);

	const dataSource = useMemo(
		() => urlQuery.get(QueryParams.alertType) as DataSource,
		[urlQuery],
	);

	// In case of alert the panel types should always be "Graph" only
	const panelType = PANEL_TYPES.TIME_SERIES;

	const {
		currentQuery,
		stagedQuery,
		handleSetQueryData,
		handleRunQuery,
		handleSetConfig,
		redirectWithQueryBuilderData,
	} = useQueryBuilder();
	const { matchType, op, target, targetUnit } =
		usePrefillAlertConditions(stagedQuery);

	useEffect(() => {
		handleSetConfig(panelType || PANEL_TYPES.TIME_SERIES, dataSource);
	}, [handleSetConfig, dataSource, panelType]);

	// use query client
	const ruleCache = useQueryClient();
	const [isChartQueryCancelled, setIsChartQueryCancelled] = useState(false);
	const [isLoadingAlertQuery, setIsLoadingAlertQuery] = useState(false);

	useEffect(() => {
		if (isLoadingAlertQuery) {
			setIsChartQueryCancelled(false);
		}
	}, [isLoadingAlertQuery]);

	const handleCancelAlertQuery = useCallback(() => {
		ruleCache.cancelQueries(REACT_QUERY_KEY.ALERT_RULES_CHART_PREVIEW);
		setIsChartQueryCancelled(true);
	}, [ruleCache]);

	const isNewRule = !ruleId || isEmpty(ruleId);

	const [loading, setLoading] = useState(false);
	const [queryStatus, setQueryStatus] = useState<string>('');

	// alertDef holds the form values to be posted
	const [alertDef, setAlertDef] = useState<AlertDef>(initialValue);
	const [yAxisUnit, setYAxisUnit] = useState<string>(currentQuery.unit || '');

	const alertTypeFromURL = urlQuery.get(QueryParams.ruleType);

	const [detectionMethod, setDetectionMethod] = useState<string | null>(null);

	useEffect(() => {
		if (!isEqual(currentQuery.unit, yAxisUnit)) {
			setYAxisUnit(currentQuery.unit || '');
		}
		// eslint-disable-next-line react-hooks/exhaustive-deps
	}, [currentQuery.unit]);

	// initQuery contains initial query when component was mounted
	const initQuery = useMemo(
		() => initialValue.condition.compositeQuery,
		[initialValue],
	);

	const queryOptions = useMemo(() => {
		const involvedQueriesInTraceOperator = getInvolvedQueriesInTraceOperator(
			currentQuery.builder.queryTraceOperator,
		);
		const queryConfig: Record<EQueryType, () => SelectProps['options']> = {
			[EQueryType.QUERY_BUILDER]: () => [
				...(getSelectedQueryOptions(currentQuery.builder.queryData)?.filter(
					(option) =>
						!involvedQueriesInTraceOperator.includes(option.value as string),
				) || []),
				...(getSelectedQueryOptions(currentQuery.builder.queryFormulas) || []),
				...(getSelectedQueryOptions(currentQuery.builder.queryTraceOperator) || []),
			],
			[EQueryType.PROM]: () => getSelectedQueryOptions(currentQuery.promql),
			[EQueryType.CLICKHOUSE]: () =>
				getSelectedQueryOptions(currentQuery.clickhouse_sql),
		};

		return queryConfig[currentQuery.queryType]?.() || [];
	}, [currentQuery]);

	const sq = useMemo(() => mapQueryDataFromApi(initQuery), [initQuery]);

	useShareBuilderUrl({ defaultValue: sq });

	const handleDetectionMethodChange = (value: string): void => {
		setAlertDef((def) => ({
			...def,
			ruleType: value,
		}));

		logEvent(`Alert: Detection method changed`, {
			detectionMethod: value,
		});

		setDetectionMethod(value);
	};

	const updateFunctions = (data: IBuilderQuery): QueryFunction[] => {
		const anomalyFunction: QueryFunction = {
			name: 'anomaly' as any,
			args: [
				{
					name: 'z_score_threshold',
					value: alertDef.condition.target || 3,
				},
			],
		};

		const functions = data.functions || [];

		if (alertDef.ruleType === AlertDetectionTypes.ANOMALY_DETECTION_ALERT) {
			// Add anomaly if not already present
			if (!functions.some((func) => func.name === 'anomaly')) {
				functions.push(anomalyFunction);
			} else {
				const anomalyFuncIndex = functions.findIndex(
					(func) => func.name === 'anomaly',
				);

				if (anomalyFuncIndex !== -1) {
					const anomalyFunc = {
						...functions[anomalyFuncIndex],
						namedArgs: { z_score_threshold: alertDef.condition.target || 3 },
					};
					functions.splice(anomalyFuncIndex, 1);
					functions.push(anomalyFunc);
				}
			}
		} else {
			// Remove anomaly if present
			const index = functions.findIndex((func) => func.name === 'anomaly');
			if (index !== -1) {
				functions.splice(index, 1);
			}
		}

		return functions;
	};

	useEffect(() => {
		if (detectionMethod) {
			const ruleType =
				detectionMethod === AlertDetectionTypes.ANOMALY_DETECTION_ALERT
					? AlertDetectionTypes.ANOMALY_DETECTION_ALERT
					: AlertDetectionTypes.THRESHOLD_ALERT;

			queryParams.set(QueryParams.ruleType, ruleType);

			const generatedUrl = `${location.pathname}?${queryParams.toString()}`;

			safeNavigate(generatedUrl);
		}
		// eslint-disable-next-line react-hooks/exhaustive-deps
	}, [detectionMethod]);

	const updateFunctionsBasedOnAlertType = (): void => {
		for (let index = 0; index < currentQuery.builder.queryData.length; index++) {
			const queryData = currentQuery.builder.queryData[index];

			const updatedFunctions = updateFunctions(queryData);

			// Only update if functions actually changed to avoid resetting aggregateAttribute
			const currentFunctions = queryData.functions || [];
			const functionsChanged = !isEqual(currentFunctions, updatedFunctions);

			if (functionsChanged) {
				const updatedQueryData = {
					...queryData,
					functions: updatedFunctions,
				};
				handleSetQueryData(index, updatedQueryData);
			}
		}
	};

	useEffect(() => {
		updateFunctionsBasedOnAlertType();
		// eslint-disable-next-line react-hooks/exhaustive-deps
	}, [
		detectionMethod,
		alertDef.condition.target,
		currentQuery.builder.queryData.length,
	]);

	useEffect(() => {
		const broadcastToSpecificChannels =
			(initialValue &&
				initialValue.preferredChannels &&
				initialValue.preferredChannels.length > 0) ||
			isNewRule;

		let ruleType = AlertDetectionTypes.THRESHOLD_ALERT;

		if (initialValue.ruleType) {
			ruleType = initialValue.ruleType as AlertDetectionTypes;
		} else if (alertTypeFromURL === AlertDetectionTypes.ANOMALY_DETECTION_ALERT) {
			ruleType = AlertDetectionTypes.ANOMALY_DETECTION_ALERT;
		}

		setAlertDef({
			...initialValue,
			broadcastToAll: !broadcastToSpecificChannels,
			ruleType,
			condition: {
				...initialValue.condition,
				compositeQuery: compositeQueryToQueryEnvelope(
					initialValue.condition.compositeQuery,
				),
				matchType: initialValue.condition.matchType ?? matchType ?? '',
				op: initialValue.condition.op ?? op ?? '',
				target: initialValue.condition.target ?? target ?? 0,
				targetUnit: initialValue.condition.targetUnit ?? targetUnit ?? '',
			},
		});

		setDetectionMethod(ruleType);
		// eslint-disable-next-line react-hooks/exhaustive-deps
	}, [initialValue, isNewRule]);

	useEffect(() => {
		// Set selectedQueryName based on the length of queryOptions
		const selectedQueryName = alertDef?.condition?.selectedQueryName;
		if (
			!selectedQueryName ||
			!queryOptions.some((option) => option.value === selectedQueryName)
		) {
			setAlertDef((def) => ({
				...def,
				condition: {
					...def.condition,
					selectedQueryName:
						queryOptions.length > 0 ? String(queryOptions[0].value) : undefined,
				},
			}));
		}
	}, [alertDef, currentQuery?.queryType, queryOptions]);

	const onCancelHandler = useCallback(
		(e?: React.MouseEvent) => {
			urlQuery.delete(QueryParams.compositeQuery);
			urlQuery.delete(QueryParams.panelTypes);
			urlQuery.delete(QueryParams.ruleId);
			urlQuery.delete(QueryParams.relativeTime);
			safeNavigate(`${ROUTES.LIST_ALL_ALERT}?${urlQuery.toString()}`, {
				newTab: !!e && isModifierKeyPressed(e),
			});
		},
		[safeNavigate, urlQuery],
	);

	// onQueryCategoryChange handles changes to query category
	// in state as well as sets additional defaults
	const onQueryCategoryChange = (val: EQueryType): void => {
		const element = document.querySelector('#top');
		if (element) {
			element.scrollIntoView({ behavior: 'smooth' });
		}
		if (val === EQueryType.PROM) {
			setAlertDef({
				...alertDef,
				condition: {
					...alertDef.condition,
					matchType: defaultMatchType,
				},
				evalWindow: defaultEvalWindow,
			});
		}
		const query: Query = { ...currentQuery, queryType: val };

		// update step interval is removed from here as if the user enters
		// any value we will use that rather than auto update
		redirectWithQueryBuilderData(query);
	};
	const { notifications } = useNotifications();
	const { showErrorModal } = useErrorModal();

	const validatePromParams = useCallback((): boolean => {
		let retval = true;
		if (currentQuery.queryType !== EQueryType.PROM) {
			return retval;
		}

		if (!currentQuery.promql || currentQuery.promql.length === 0) {
			notifications.error({
				message: 'Error',
				description: t('promql_required'),
			});
			return false;
		}

		currentQuery.promql.forEach((item) => {
			if (item.query === '') {
				notifications.error({
					message: 'Error',
					description: t('promql_required'),
				});
				retval = false;
			}
		});

		return retval;
	}, [t, currentQuery, notifications]);

	const validateChQueryParams = useCallback((): boolean => {
		let retval = true;
		if (currentQuery.queryType !== EQueryType.CLICKHOUSE) {
			return retval;
		}

		if (
			!currentQuery.clickhouse_sql ||
			currentQuery.clickhouse_sql.length === 0
		) {
			notifications.error({
				message: 'Error',
				description: t('chquery_required'),
			});
			return false;
		}

		currentQuery.clickhouse_sql.forEach((item) => {
			if (item.query === '') {
				notifications.error({
					message: 'Error',
					description: t('chquery_required'),
				});
				retval = false;
			}
		});

		return retval;
	}, [t, currentQuery, notifications]);

	const validateQBParams = useCallback((): boolean => {
		if (currentQuery.queryType !== EQueryType.QUERY_BUILDER) {
			return true;
		}

		if (
			!currentQuery.builder.queryData ||
			currentQuery.builder.queryData?.length === 0
		) {
			notifications.error({
				message: 'Error',
				description: t('condition_required'),
			});
			return false;
		}

		if (
			alertDef.ruleType !== AlertDetectionTypes.ANOMALY_DETECTION_ALERT &&
			alertDef.condition?.target !== 0 &&
			!alertDef.condition?.target
		) {
			notifications.error({
				message: 'Error',
				description: t('target_missing'),
			});
			return false;
		}

		return true;
	}, [t, alertDef, currentQuery, notifications]);

	const isFormValid = useCallback((): boolean => {
		if (!alertDef.alert || alertDef.alert === '') {
			return false;
		}

		if (!validatePromParams()) {
			return false;
		}

		if (!validateChQueryParams()) {
			return false;
		}

		return validateQBParams();
	}, [validateQBParams, validateChQueryParams, alertDef, validatePromParams]);

	const preparePostData = (): AlertDef => {
		const postableAlert: AlertDef = {
			...alertDef,
			preferredChannels: alertDef.broadcastToAll ? [] : alertDef.preferredChannels,
			alertType:
				alertType === AlertTypes.ANOMALY_BASED_ALERT
					? AlertTypes.METRICS_BASED_ALERT
					: alertType,
			source: window?.location.toString(),
			ruleType:
				currentQuery.queryType === EQueryType.PROM
					? 'promql_rule'
					: alertDef.ruleType,
			condition: {
				...alertDef.condition,
				compositeQuery: compositeQueryToQueryEnvelope({
					builderQueries: {
						...mapQueryDataToApi(currentQuery.builder.queryData, 'queryName').data,
						...mapQueryDataToApi(currentQuery.builder.queryFormulas, 'queryName')
							.data,
					},
					promQueries: mapQueryDataToApi(currentQuery.promql, 'name').data,
					chQueries: mapQueryDataToApi(currentQuery.clickhouse_sql, 'name').data,
					queryType: currentQuery.queryType,
					panelType: panelType || initQuery.panelType,
					unit: yAxisUnit,
				}),
			},
		};

		if (alertDef.ruleType === AlertDetectionTypes.ANOMALY_DETECTION_ALERT) {
			postableAlert.condition.algorithm = alertDef.condition.algorithm;
			postableAlert.condition.seasonality = alertDef.condition.seasonality;
		}

		return postableAlert;
	};

	const memoizedPreparePostData = useCallback(preparePostData, [
		currentQuery,
		alertDef,
		alertType,
		initQuery,
		panelType,
		yAxisUnit,
	]);

	const saveRule = useCallback(async () => {
		if (!isFormValid()) {
			return;
		}
		const postableAlert = memoizedPreparePostData();
		setLoading(true);

		let logData = {
			status: 'error',
			statusMessage: t('unexpected_error'),
		};

		try {
			if (ruleId && !isEmpty(ruleId)) {
				await updateRuleByID(
					{ id: ruleId },
					toPostableRuleDTOFromAlertDef(postableAlert),
				);
			} else {
				await createRule(toPostableRuleDTOFromAlertDef(postableAlert));
			}

			logData = {
				status: 'success',
				statusMessage: isNewRule ? t('rule_created') : t('rule_edited'),
			};

			notifications.success({
				message: 'Success',
				description: logData.statusMessage,
			});

			// invalidate rule in cache
			ruleCache.invalidateQueries([
				REACT_QUERY_KEY.ALERT_RULE_DETAILS,
				`${ruleId}`,
			]);

			// eslint-disable-next-line sonarjs/no-identical-functions
			setTimeout(() => {
				urlQuery.delete(QueryParams.compositeQuery);
				urlQuery.delete(QueryParams.panelTypes);
				urlQuery.delete(QueryParams.ruleId);
				urlQuery.delete(QueryParams.relativeTime);
				safeNavigate(`${ROUTES.LIST_ALL_ALERT}?${urlQuery.toString()}`);
			}, 2000);
		} catch (e) {
			const apiError = convertToApiError(e as AxiosError<RenderErrorResponseDTO>);
			logData = {
				status: 'error',
				statusMessage: apiError?.getErrorMessage() || t('unexpected_error'),
			};

			showErrorModal(apiError as APIError);
		}

		setLoading(false);

		logEvent('Alert: Save alert', {
			...logData,
			dataSource: ALERTS_DATA_SOURCE_MAP[postableAlert?.alertType as AlertTypes],
			channelNames: postableAlert?.preferredChannels,
			broadcastToAll: postableAlert?.broadcastToAll,
			isNewRule,
			ruleId,
			queryType: currentQuery.queryType,
			alertId: postableAlert?.id,
			alertName: postableAlert?.alert,
			ruleType: postableAlert?.ruleType,
		});
		// eslint-disable-next-line react-hooks/exhaustive-deps
	}, [
		isFormValid,
		memoizedPreparePostData,
		ruleId,
		notifications,
		t,
		ruleCache,
		urlQuery,
	]);

	const onSaveHandler = useCallback(async () => {
		const content = (
			<Typography.Text>
				{' '}
				{t('confirm_save_content_part1')}{' '}
				<QueryTypeTag queryType={currentQuery.queryType} />{' '}
				{t('confirm_save_content_part2')}
			</Typography.Text>
		);
		Modal.confirm({
			icon: <ExclamationCircleOutlined />,
			title: t('confirm_save_title'),
			centered: true,
			content,
			onOk: saveRule,
			className: 'create-alert-modal',
		});
	}, [t, saveRule, currentQuery]);

	const onTestRuleHandler = useCallback(async () => {
		if (!isFormValid()) {
			return;
		}
		const postableAlert = memoizedPreparePostData();

		let statusResponse = { status: 'failed', message: '' };
		setLoading(true);
		try {
			const response = await testRule(
				toPostableRuleDTOFromAlertDef(postableAlert),
			);

			if (response.data?.alertCount === 0) {
				notifications.error({
					message: 'Error',
					description: t('no_alerts_found'),
				});
				statusResponse = { status: 'failed', message: t('no_alerts_found') };
			} else {
				notifications.success({
					message: 'Success',
					description: t('rule_test_fired'),
				});
				statusResponse = { status: 'success', message: t('rule_test_fired') };
			}
		} catch (e) {
			const apiError = convertToApiError(e as AxiosError<RenderErrorResponseDTO>);
			statusResponse = {
				status: 'failed',
				message: apiError?.getErrorMessage() || t('unexpected_error'),
			};
			showErrorModal(apiError as APIError);
		}
		setLoading(false);
		logEvent('Alert: Test notification', {
			dataSource: ALERTS_DATA_SOURCE_MAP[alertDef?.alertType as AlertTypes],
			channelNames: postableAlert?.preferredChannels,
			broadcastToAll: postableAlert?.broadcastToAll,
			isNewRule,
			ruleId,
			queryType: currentQuery.queryType,
			status: statusResponse.status,
			statusMessage: statusResponse.message,
			ruleType: postableAlert.ruleType,
		});
		// eslint-disable-next-line react-hooks/exhaustive-deps
	}, [t, isFormValid, memoizedPreparePostData, notifications]);

	const renderBasicInfo = (): JSX.Element => (
		<BasicInfo
			alertDef={alertDef}
			setAlertDef={setAlertDef}
			isNewRule={isNewRule}
		/>
	);

	const renderQBChartPreview = (): JSX.Element => (
		<ChartPreview
			headline={
				<PlotTag
					queryType={currentQuery.queryType}
					panelType={panelType || PANEL_TYPES.TIME_SERIES}
				/>
			}
			name=""
			query={stagedQuery}
			selectedInterval={globalSelectedInterval}
			alertDef={alertDef}
			yAxisUnit={yAxisUnit || ''}
			graphType={panelType || PANEL_TYPES.TIME_SERIES}
			setQueryStatus={setQueryStatus}
			isCancelled={isChartQueryCancelled}
			onFetchingStateChange={setIsLoadingAlertQuery}
		/>
	);

	const renderPromAndChQueryChartPreview = (): JSX.Element => (
		<ChartPreview
			headline={
				<PlotTag
					queryType={currentQuery.queryType}
					panelType={panelType || PANEL_TYPES.TIME_SERIES}
				/>
			}
			name="Chart Preview"
			query={stagedQuery}
			alertDef={alertDef}
			selectedInterval={globalSelectedInterval}
			yAxisUnit={yAxisUnit || ''}
			graphType={panelType || PANEL_TYPES.TIME_SERIES}
			setQueryStatus={setQueryStatus}
			isCancelled={isChartQueryCancelled}
			onFetchingStateChange={setIsLoadingAlertQuery}
		/>
	);

	const isAlertNameMissing = !formInstance.getFieldValue('alert');

	const onUnitChangeHandler = (value: string): void => {
		setYAxisUnit(value);
		// reset target unit
		setAlertDef((def) => ({
			...def,
			condition: {
				...def.condition,
				targetUnit: undefined,
			},
		}));
	};

	const isChannelConfigurationValid =
		alertDef?.broadcastToAll ||
		(alertDef.preferredChannels && alertDef.preferredChannels.length > 0);

	function handleRedirection(option: AlertTypes): void {
		let url;
		if (
			option === AlertTypes.METRICS_BASED_ALERT &&
			alertTypeFromURL === AlertDetectionTypes.ANOMALY_DETECTION_ALERT
		) {
			url = ALERT_SETUP_GUIDE_URLS[AlertTypes.ANOMALY_BASED_ALERT];
		} else {
			url = ALERT_SETUP_GUIDE_URLS[option];
		}

		if (url) {
			logEvent('Alert: Check example alert clicked', {
				dataSource: ALERTS_DATA_SOURCE_MAP[alertDef?.alertType as AlertTypes],
				isNewRule,
				ruleId,
				queryType: currentQuery.queryType,
				link: url,
			});
			openInNewTab(url);
		}
	}

	useEffect(() => {
		if (!isNewRule) {
			logEvent('Alert: Edit page visited', {
				ruleId,
				dataSource: ALERTS_DATA_SOURCE_MAP[alertType as AlertTypes],
			});
		}
		// eslint-disable-next-line react-hooks/exhaustive-deps
	}, []);

	const tabs = [
		{
			value: AlertDetectionTypes.THRESHOLD_ALERT,
			label: 'Threshold Alert',
		},
		{
			value: AlertDetectionTypes.ANOMALY_DETECTION_ALERT,
			label: 'Anomaly Detection Alert',
			isBeta: true,
		},
	];

	const isAnomalyDetectionEnabled =
		featureFlags?.find((flag) => flag.name === FeatureKeys.ANOMALY_DETECTION)
			?.active || false;

	const source = useMemo(
		() => urlQuery.get(QueryParams.source) as YAxisSource,
		[urlQuery],
	);

	// Only update automatically when creating a new metrics-based alert rule
	const shouldUpdateYAxisUnit = useMemo(() => {
		// Do not update if we are coming to the page from dashboards (we still show warning)
		if (source === YAxisSource.DASHBOARDS) {
			return false;
		}
		return isNewRule && alertType === AlertTypes.METRICS_BASED_ALERT;
	}, [isNewRule, alertType, source]);

	const { yAxisUnit: initialYAxisUnit, isLoading } = useGetYAxisUnit(
		alertDef.condition.selectedQueryName,
	);

	// Every time a new metric is selected, set the y-axis unit to its unit
	// Only for metrics-based alerts in create mode
	useEffect(() => {
		if (shouldUpdateYAxisUnit) {
			setYAxisUnit(initialYAxisUnit || '');
		}
	}, [initialYAxisUnit, shouldUpdateYAxisUnit]);

	return (
		<>
			{Element}

			<div
				id="top"
				className={`form-alert-rules-container ${
					isNewRule ? 'create-mode' : 'edit-mode'
				}`}
			>
				<div className="overview-header">
					<div className="alert-type-container">
						<Typography.Title level={5} className="alert-type-title">
							<BellDot size={14} />

							{alertDef.alertType === AlertTypes.ANOMALY_BASED_ALERT &&
								'Anomaly Detection Alert'}
							{alertDef.alertType === AlertTypes.METRICS_BASED_ALERT &&
								'Metrics Based Alert'}
							{alertDef.alertType === AlertTypes.LOGS_BASED_ALERT &&
								'Logs Based Alert'}
							{alertDef.alertType === AlertTypes.TRACES_BASED_ALERT &&
								'Traces Based Alert'}
							{alertDef.alertType === AlertTypes.EXCEPTIONS_BASED_ALERT &&
								'Exceptions Based Alert'}
						</Typography.Title>
					</div>

					<Button
						className="periscope-btn"
						onClick={(): void => handleRedirection(alertDef.alertType as AlertTypes)}
						icon={<ExternalLink size={14} />}
					>
						Alert Setup Guide
					</Button>
				</div>

				<MainFormContainer
					initialValues={initialValue}
					layout="vertical"
					form={formInstance}
					className="main-container"
				>
					<div className="chart-preview-container">
						{currentQuery.queryType === EQueryType.QUERY_BUILDER &&
							renderQBChartPreview()}
						{currentQuery.queryType === EQueryType.PROM &&
							renderPromAndChQueryChartPreview()}
						{currentQuery.queryType === EQueryType.CLICKHOUSE &&
							renderPromAndChQueryChartPreview()}
					</div>

					<StepContainer>
						<YAxisUnitSelector
							value={yAxisUnit}
							initialValue={initialYAxisUnit}
							onChange={onUnitChangeHandler}
							source={YAxisSource.ALERTS}
							loading={isLoading}
						/>
					</StepContainer>

					<div className="steps-container">
						{alertDef.alertType === AlertTypes.METRICS_BASED_ALERT &&
							isAnomalyDetectionEnabled && (
								<div className="detection-method-container">
									<StepHeading> {t('alert_form_step1')}</StepHeading>

									<Tabs2
										key={detectionMethod}
										tabs={tabs}
										initialSelectedTab={detectionMethod || ''}
										onSelectTab={handleDetectionMethodChange}
									/>

									<div className="detection-method-description">
										{detectionMethod === AlertDetectionTypes.ANOMALY_DETECTION_ALERT
											? t('anomaly_detection_alert_desc')
											: t('threshold_alert_desc')}
									</div>
								</div>
							)}

						<QuerySection
							queryCategory={currentQuery.queryType}
							setQueryCategory={onQueryCategoryChange}
							alertType={alertType || AlertTypes.METRICS_BASED_ALERT}
							runQuery={(): void => {
								setIsChartQueryCancelled(false);
								ruleCache.invalidateQueries([
									REACT_QUERY_KEY.ALERT_RULES_CHART_PREVIEW,
								]);
								handleRunQuery();
							}}
							isLoadingQueries={isLoadingAlertQuery}
							handleCancelQuery={handleCancelAlertQuery}
							alertDef={alertDef}
							panelType={panelType || PANEL_TYPES.TIME_SERIES}
							key={currentQuery.queryType}
							ruleId={ruleId}
							isAnomalyDetection={
								alertDef.ruleType === AlertDetectionTypes.ANOMALY_DETECTION_ALERT
							}
						/>

						<RuleOptions
							queryCategory={currentQuery.queryType}
							alertDef={alertDef}
							setAlertDef={setAlertDef}
							queryOptions={queryOptions}
							yAxisUnit={yAxisUnit || ''}
						/>

						{renderBasicInfo()}
					</div>
					<ButtonContainer>
						<ActionButton
							loading={loading || false}
							type="primary"
							onClick={onSaveHandler}
							icon={<SaveOutlined />}
							disabled={
								isAlertNameMissing ||
								!isChannelConfigurationValid ||
								queryStatus === 'error'
							}
						>
							{isNewRule ? t('button_createrule') : t('button_savechanges')}
						</ActionButton>

						<ActionButton
							loading={loading || false}
							disabled={
								isAlertNameMissing ||
								!isChannelConfigurationValid ||
								queryStatus === 'error'
							}
							type="default"
							onClick={onTestRuleHandler}
						>
							{' '}
							{t('button_testrule')}
						</ActionButton>
						<ActionButton
							disabled={loading || false}
							type="default"
							onClick={onCancelHandler}
						>
							{isNewRule && t('button_cancelchanges')}
							{ruleId && !isEmpty(ruleId) && t('button_discard')}
						</ActionButton>
					</ButtonContainer>
				</MainFormContainer>
			</div>
		</>
	);
}

FormAlertRules.defaultProps = {
	alertType: AlertTypes.METRICS_BASED_ALERT,
};

interface FormAlertRuleProps {
	alertType?: AlertTypes;
	formInstance: FormInstance;
	initialValue: AlertDef;
	ruleId: string;
}

export default FormAlertRules;
