/* eslint-disable sonarjs/cognitive-complexity */
import './NewWidget.styles.scss';

import { WarningOutlined } from '@ant-design/icons';
import { Button, Flex, Modal, Space, Tooltip, Typography } from 'antd';
import FacingIssueBtn from 'components/facingIssueBtn/FacingIssueBtn';
import { chartHelpMessage } from 'components/facingIssueBtn/util';
import { FeatureKeys } from 'constants/features';
import { QueryParams } from 'constants/query';
import { initialQueriesMap, PANEL_TYPES } from 'constants/queryBuilder';
import ROUTES from 'constants/routes';
import { DashboardShortcuts } from 'constants/shortcuts/DashboardShortcuts';
import { DEFAULT_BUCKET_COUNT } from 'container/PanelWrapper/constants';
import { useUpdateDashboard } from 'hooks/dashboard/useUpdateDashboard';
import { useKeyboardHotkeys } from 'hooks/hotkeys/useKeyboardHotkeys';
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
import useAxiosError from 'hooks/useAxiosError';
import { useIsDarkMode } from 'hooks/useDarkMode';
import { MESSAGE, useIsFeatureDisabled } from 'hooks/useFeatureFlag';
import useUrlQuery from 'hooks/useUrlQuery';
import { getDashboardVariables } from 'lib/dashbaordVariables/getDashboardVariables';
import { GetQueryResultsProps } from 'lib/dashboard/getQueryResults';
import history from 'lib/history';
import { defaultTo, isUndefined } from 'lodash-es';
import { Check, X } from 'lucide-react';
import { DashboardWidgetPageParams } from 'pages/DashboardWidget';
import { useDashboard } from 'providers/Dashboard/Dashboard';
import {
	getNextWidgets,
	getPreviousWidgets,
	getSelectedWidgetIndex,
} from 'providers/Dashboard/util';
import { useCallback, useEffect, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useSelector } from 'react-redux';
import { generatePath, useParams } from 'react-router-dom';
import { AppState } from 'store/reducers';
import { ColumnUnit, Dashboard, Widgets } from 'types/api/dashboard/getAll';
import { IField } from 'types/api/logs/fields';
import { EQueryType } from 'types/common/dashboard';
import { DataSource } from 'types/common/queryBuilder';
import AppReducer from 'types/reducer/app';
import { GlobalReducer } from 'types/reducer/globalTime';
import { getGraphType, getGraphTypeForFormat } from 'utils/getGraphType';

import LeftContainer from './LeftContainer';
import QueryTypeTag from './LeftContainer/QueryTypeTag';
import RightContainer from './RightContainer';
import { ThresholdProps } from './RightContainer/Threshold/types';
import TimeItems, { timePreferance } from './RightContainer/timeItems';
import {
	Container,
	LeftContainerWrapper,
	PanelContainer,
	RightContainerWrapper,
} from './styles';
import { NewWidgetProps } from './types';
import {
	getDefaultWidgetData,
	getIsQueryModified,
	handleQueryChange,
} from './utils';

function NewWidget({ selectedGraph }: NewWidgetProps): JSX.Element {
	const {
		selectedDashboard,
		setSelectedDashboard,
		setToScrollWidgetId,
	} = useDashboard();

	const { t } = useTranslation(['dashboard']);

	const { registerShortcut, deregisterShortcut } = useKeyboardHotkeys();

	const {
		currentQuery,
		stagedQuery,
		redirectWithQueryBuilderData,
		supersetQuery,
	} = useQueryBuilder();

	const isQueryModified = useMemo(
		() => getIsQueryModified(currentQuery, stagedQuery),
		[currentQuery, stagedQuery],
	);

	const { featureResponse } = useSelector<AppState, AppReducer>(
		(state) => state.app,
	);
	const { selectedTime: globalSelectedInterval } = useSelector<
		AppState,
		GlobalReducer
	>((state) => state.globalTime);

	const { widgets = [] } = selectedDashboard?.data || {};

	const query = useUrlQuery();

	const { dashboardId } = useParams<DashboardWidgetPageParams>();

	const [isNewDashboard, setIsNewDashboard] = useState<boolean>(false);

	useEffect(() => {
		const widgetId = query.get('widgetId');
		const selectedWidget = widgets?.find((e) => e.id === widgetId);
		const isWidgetNotPresent = isUndefined(selectedWidget);
		if (isWidgetNotPresent) {
			setIsNewDashboard(true);
		}
		// eslint-disable-next-line react-hooks/exhaustive-deps
	}, []);

	const getWidget = useCallback(() => {
		const widgetId = query.get('widgetId');
		const selectedWidget = widgets?.find((e) => e.id === widgetId);
		return defaultTo(
			selectedWidget,
			getDefaultWidgetData(widgetId || '', selectedGraph),
		) as Widgets;
	}, [query, selectedGraph, widgets]);

	const [selectedWidget, setSelectedWidget] = useState(getWidget());

	const [title, setTitle] = useState<string>(
		selectedWidget?.title?.toString() || '',
	);
	const [description, setDescription] = useState<string>(
		selectedWidget?.description || '',
	);
	const [yAxisUnit, setYAxisUnit] = useState<string>(
		selectedWidget?.yAxisUnit || 'none',
	);

	const [stacked, setStacked] = useState<boolean>(
		selectedWidget?.isStacked || false,
	);

	const [stackedBarChart, setStackedBarChart] = useState<boolean>(
		selectedWidget?.stackedBarChart || false,
	);
	const [opacity, setOpacity] = useState<string>(selectedWidget?.opacity || '1');
	const [thresholds, setThresholds] = useState<ThresholdProps[]>(
		selectedWidget?.thresholds || [],
	);
	const [selectedNullZeroValue, setSelectedNullZeroValue] = useState<string>(
		selectedWidget?.nullZeroValues || 'zero',
	);
	const [isFillSpans, setIsFillSpans] = useState<boolean>(
		selectedWidget?.fillSpans || false,
	);
	const [saveModal, setSaveModal] = useState(false);
	const [discardModal, setDiscardModal] = useState(false);

	const [bucketWidth, setBucketWidth] = useState<number>(
		selectedWidget?.bucketWidth || 0,
	);

	const [bucketCount, setBucketCount] = useState<number>(
		selectedWidget?.bucketCount || DEFAULT_BUCKET_COUNT,
	);

	const [combineHistogram, setCombineHistogram] = useState<boolean>(
		selectedWidget?.mergeAllActiveQueries || false,
	);

	const [softMin, setSoftMin] = useState<number | null>(
		selectedWidget?.softMin === null || selectedWidget?.softMin === undefined
			? null
			: selectedWidget?.softMin || 0,
	);

	const [selectedLogFields, setSelectedLogFields] = useState<IField[] | null>(
		selectedWidget?.selectedLogFields || null,
	);

	const [selectedTracesFields, setSelectedTracesFields] = useState(
		selectedWidget?.selectedTracesFields || null,
	);

	const [softMax, setSoftMax] = useState<number | null>(
		selectedWidget?.softMax === null || selectedWidget?.softMax === undefined
			? null
			: selectedWidget?.softMax || 0,
	);

	const [columnUnits, setColumnUnits] = useState<ColumnUnit>(
		selectedWidget?.columnUnits || {},
	);

	useEffect(() => {
		setSelectedWidget((prev) => {
			if (!prev) {
				return prev;
			}
			return {
				...prev,
				query: currentQuery,
				title,
				description,
				isStacked: stacked,
				opacity,
				nullZeroValues: selectedNullZeroValue,
				yAxisUnit,
				thresholds,
				softMin,
				softMax,
				fillSpans: isFillSpans,
				columnUnits,
				bucketCount,
				stackedBarChart,
				bucketWidth,
				mergeAllActiveQueries: combineHistogram,
				selectedLogFields,
				selectedTracesFields,
			};
		});
	}, [
		columnUnits,
		currentQuery,
		description,
		isFillSpans,
		opacity,
		selectedLogFields,
		selectedNullZeroValue,
		selectedTracesFields,
		softMax,
		softMin,
		stacked,
		thresholds,
		title,
		yAxisUnit,
		bucketWidth,
		bucketCount,
		combineHistogram,
		stackedBarChart,
	]);

	const closeModal = (): void => {
		setSaveModal(false);
		setDiscardModal(false);
	};

	const [graphType, setGraphType] = useState(selectedGraph);

	const getSelectedTime = useCallback(
		() =>
			TimeItems.find(
				(e) => e.enum === (selectedWidget?.timePreferance || 'GLOBAL_TIME'),
			),
		[selectedWidget],
	);

	const [selectedTime, setSelectedTime] = useState<timePreferance>({
		name: getSelectedTime()?.name || '',
		enum: selectedWidget?.timePreferance || 'GLOBAL_TIME',
	});

	const updateDashboardMutation = useUpdateDashboard();

	const { afterWidgets, preWidgets } = useMemo(() => {
		if (!selectedDashboard) {
			return {
				selectedWidget: {} as Widgets,
				preWidgets: [],
				afterWidgets: [],
			};
		}

		const widgetId = query.get('widgetId');

		const selectedWidgetIndex = getSelectedWidgetIndex(
			selectedDashboard,
			widgetId,
		);

		const preWidgets = getPreviousWidgets(selectedDashboard, selectedWidgetIndex);

		const afterWidgets = getNextWidgets(selectedDashboard, selectedWidgetIndex);

		const selectedWidget = (selectedDashboard.data.widgets || [])[
			selectedWidgetIndex || 0
		];

		return { selectedWidget, preWidgets, afterWidgets };
	}, [selectedDashboard, query]);

	const handleError = useAxiosError();

	// this loading state is to take care of mismatch in the responses for table and other panels
	// hence while changing the query contains the older value and the processing logic fails
	const [isLoadingPanelData, setIsLoadingPanelData] = useState<boolean>(false);

	// request data should be handled by the parent and the child components should consume the same
	// this has been moved here from the left container
	const [requestData, setRequestData] = useState<GetQueryResultsProps>(() => {
		if (selectedWidget && selectedGraph !== PANEL_TYPES.LIST) {
			return {
				selectedTime: selectedWidget?.timePreferance,
				graphType: getGraphType(selectedGraph || selectedWidget.panelTypes),
				query: stagedQuery || initialQueriesMap.metrics,
				globalSelectedInterval,
				formatForWeb:
					getGraphTypeForFormat(selectedGraph || selectedWidget.panelTypes) ===
					PANEL_TYPES.TABLE,
				variables: getDashboardVariables(selectedDashboard?.data.variables),
			};
		}
		const updatedQuery = { ...(stagedQuery || initialQueriesMap.metrics) };
		updatedQuery.builder.queryData[0].pageSize = 10;
		redirectWithQueryBuilderData(updatedQuery);
		return {
			query: updatedQuery,
			graphType: PANEL_TYPES.LIST,
			selectedTime: selectedTime.enum || 'GLOBAL_TIME',
			globalSelectedInterval,
			tableParams: {
				pagination: {
					offset: 0,
					limit: updatedQuery.builder.queryData[0].limit || 0,
				},
			},
		};
	});

	useEffect(() => {
		if (stagedQuery) {
			setIsLoadingPanelData(false);
			setRequestData((prev) => ({
				...prev,
				selectedTime: selectedTime.enum || prev.selectedTime,
				globalSelectedInterval,
				graphType: getGraphType(selectedGraph || selectedWidget.panelTypes),
				query: stagedQuery,
				fillGaps: selectedWidget.fillSpans || false,
				formatForWeb:
					getGraphTypeForFormat(selectedGraph || selectedWidget.panelTypes) ===
					PANEL_TYPES.TABLE,
			}));
		}
		// eslint-disable-next-line react-hooks/exhaustive-deps
	}, [
		stagedQuery,
		selectedTime,
		selectedWidget.fillSpans,
		globalSelectedInterval,
	]);

	const onClickSaveHandler = useCallback(() => {
		if (!selectedDashboard) {
			return;
		}

		const widgetId = query.get('widgetId');
		let updatedLayout = selectedDashboard.data.layout || [];
		if (isNewDashboard) {
			updatedLayout = [
				{
					i: widgetId || '',
					w: 6,
					x: 0,
					h: 6,
					y: 0,
				},
				...updatedLayout,
			];
		}
		const dashboard: Dashboard = {
			...selectedDashboard,
			uuid: selectedDashboard.uuid,
			data: {
				...selectedDashboard.data,
				widgets: isNewDashboard
					? [
							...afterWidgets,
							{
								...(selectedWidget || ({} as Widgets)),
								description: selectedWidget?.description || '',
								timePreferance: selectedTime.enum,
								isStacked: selectedWidget?.isStacked || false,
								opacity: selectedWidget?.opacity || '1',
								nullZeroValues: selectedWidget?.nullZeroValues || 'zero',
								title: selectedWidget?.title,
								stackedBarChart: selectedWidget?.stackedBarChart || false,
								yAxisUnit: selectedWidget?.yAxisUnit,
								panelTypes: graphType,
								query: currentQuery,
								thresholds: selectedWidget?.thresholds,
								columnUnits: selectedWidget?.columnUnits,
								softMin: selectedWidget?.softMin || 0,
								softMax: selectedWidget?.softMax || 0,
								fillSpans: selectedWidget?.fillSpans,
								bucketWidth: selectedWidget?.bucketWidth || 0,
								bucketCount: selectedWidget?.bucketCount || 0,
								mergeAllActiveQueries: selectedWidget?.mergeAllActiveQueries || false,
								selectedLogFields: selectedWidget?.selectedLogFields || [],
								selectedTracesFields: selectedWidget?.selectedTracesFields || [],
							},
					  ]
					: [
							...preWidgets,
							{
								...(selectedWidget || ({} as Widgets)),
								description: selectedWidget?.description || '',
								timePreferance: selectedTime.enum,
								isStacked: selectedWidget?.isStacked || false,
								opacity: selectedWidget?.opacity || '1',
								nullZeroValues: selectedWidget?.nullZeroValues || 'zero',
								title: selectedWidget?.title,
								stackedBarChart: selectedWidget?.stackedBarChart || false,
								yAxisUnit: selectedWidget?.yAxisUnit,
								panelTypes: graphType,
								query: currentQuery,
								thresholds: selectedWidget?.thresholds,
								columnUnits: selectedWidget?.columnUnits,
								softMin: selectedWidget?.softMin || 0,
								softMax: selectedWidget?.softMax || 0,
								fillSpans: selectedWidget?.fillSpans,
								bucketWidth: selectedWidget?.bucketWidth || 0,
								bucketCount: selectedWidget?.bucketCount || 0,
								mergeAllActiveQueries: selectedWidget?.mergeAllActiveQueries || false,
								selectedLogFields: selectedWidget?.selectedLogFields || [],
								selectedTracesFields: selectedWidget?.selectedTracesFields || [],
							},
							...afterWidgets,
					  ],
				layout: [...updatedLayout],
			},
		};

		updateDashboardMutation.mutateAsync(dashboard, {
			onSuccess: () => {
				setSelectedDashboard(dashboard);
				setToScrollWidgetId(selectedWidget?.id || '');
				featureResponse.refetch();
				history.push({
					pathname: generatePath(ROUTES.DASHBOARD, { dashboardId }),
				});
			},
			onError: handleError,
		});
	}, [
		selectedDashboard,
		query,
		isNewDashboard,
		preWidgets,
		selectedWidget,
		selectedTime.enum,
		graphType,
		currentQuery,
		afterWidgets,
		updateDashboardMutation,
		handleError,
		setSelectedDashboard,
		setToScrollWidgetId,
		featureResponse,
		dashboardId,
	]);

	const onClickDiscardHandler = useCallback(() => {
		if (isQueryModified) {
			setDiscardModal(true);
			return;
		}
		history.push(generatePath(ROUTES.DASHBOARD, { dashboardId }));
	}, [dashboardId, isQueryModified]);

	const discardChanges = useCallback(() => {
		history.push(generatePath(ROUTES.DASHBOARD, { dashboardId }));
	}, [dashboardId]);

	const setGraphHandler = (type: PANEL_TYPES): void => {
		setIsLoadingPanelData(true);
		const updatedQuery = handleQueryChange(type as any, supersetQuery);
		setGraphType(type);
		redirectWithQueryBuilderData(
			updatedQuery,
			{ [QueryParams.graphType]: type },
			undefined,
			true,
		);
	};

	const onSaveDashboard = useCallback((): void => {
		setSaveModal(true);
	}, []);

	const isQueryBuilderActive = useIsFeatureDisabled(
		FeatureKeys.QUERY_BUILDER_PANELS,
	);

	const isNewTraceLogsAvailable =
		isQueryBuilderActive &&
		currentQuery.queryType === EQueryType.QUERY_BUILDER &&
		currentQuery.builder.queryData.find(
			(query) => query.dataSource !== DataSource.METRICS,
		) !== undefined;

	const isSaveDisabled = useMemo(() => {
		// new created dashboard
		if (selectedWidget?.id === 'empty') {
			return isNewTraceLogsAvailable;
		}

		const isTraceOrLogsQueryBuilder =
			currentQuery.builder.queryData.find(
				(query) =>
					query.dataSource === DataSource.TRACES ||
					query.dataSource === DataSource.LOGS,
			) !== undefined;

		if (isTraceOrLogsQueryBuilder) {
			return false;
		}

		return isNewTraceLogsAvailable;
	}, [
		currentQuery.builder.queryData,
		selectedWidget?.id,
		isNewTraceLogsAvailable,
	]);

	useEffect(() => {
		registerShortcut(DashboardShortcuts.SaveChanges, onSaveDashboard);
		registerShortcut(DashboardShortcuts.DiscardChanges, onClickDiscardHandler);

		return (): void => {
			deregisterShortcut(DashboardShortcuts.SaveChanges);
			deregisterShortcut(DashboardShortcuts.DiscardChanges);
		};
		// eslint-disable-next-line react-hooks/exhaustive-deps
	}, [onSaveDashboard]);

	return (
		<Container>
			<div className="edit-header">
				<div className="left-header">
					<X size={14} onClick={onClickDiscardHandler} className="discard-icon" />
					<Flex align="center" gap={24}>
						<Typography.Text className="configure-panel">
							Configure panel
						</Typography.Text>
						<FacingIssueBtn
							attributes={{
								uuid: selectedDashboard?.uuid,
								title: selectedDashboard?.data.title,
								screen: 'Dashboard widget',
								panelType: graphType,
								widgetId: query.get('widgetId'),
								queryType: currentQuery.queryType,
							}}
							eventName="Dashboard: Facing Issues in dashboard"
							message={chartHelpMessage(selectedDashboard, graphType)}
							buttonText="Facing issues with dashboards?"
							onHoverText="Click here to get help with dashboard widget"
						/>
					</Flex>
				</div>
				{isSaveDisabled && (
					<Tooltip title={MESSAGE.PANEL}>
						<Button
							type="primary"
							data-testid="new-widget-save"
							loading={updateDashboardMutation.isLoading}
							disabled={isSaveDisabled}
							onClick={onSaveDashboard}
							className="save-btn"
						>
							Save Changes
						</Button>
					</Tooltip>
				)}
				{!isSaveDisabled && (
					<Button
						type="primary"
						data-testid="new-widget-save"
						loading={updateDashboardMutation.isLoading}
						disabled={isSaveDisabled}
						onClick={onSaveDashboard}
						icon={<Check size={14} />}
						className="save-btn"
					>
						Save Changes
					</Button>
				)}
			</div>

			<PanelContainer>
				<LeftContainerWrapper isDarkMode={useIsDarkMode()}>
					{selectedWidget && (
						<LeftContainer
							selectedGraph={graphType}
							selectedLogFields={selectedLogFields}
							setSelectedLogFields={setSelectedLogFields}
							selectedTracesFields={selectedTracesFields}
							setSelectedTracesFields={setSelectedTracesFields}
							selectedWidget={selectedWidget}
							selectedTime={selectedTime}
							requestData={requestData}
							setRequestData={setRequestData}
							isLoadingPanelData={isLoadingPanelData}
						/>
					)}
				</LeftContainerWrapper>

				<RightContainerWrapper>
					<RightContainer
						setGraphHandler={setGraphHandler}
						title={title}
						setTitle={setTitle}
						description={description}
						setDescription={setDescription}
						stacked={stacked}
						setStacked={setStacked}
						stackedBarChart={stackedBarChart}
						setStackedBarChart={setStackedBarChart}
						opacity={opacity}
						yAxisUnit={yAxisUnit}
						columnUnits={columnUnits}
						setColumnUnits={setColumnUnits}
						bucketCount={bucketCount}
						bucketWidth={bucketWidth}
						combineHistogram={combineHistogram}
						setCombineHistogram={setCombineHistogram}
						setBucketWidth={setBucketWidth}
						setBucketCount={setBucketCount}
						setOpacity={setOpacity}
						selectedNullZeroValue={selectedNullZeroValue}
						setSelectedNullZeroValue={setSelectedNullZeroValue}
						selectedGraph={graphType}
						setSelectedTime={setSelectedTime}
						selectedTime={selectedTime}
						setYAxisUnit={setYAxisUnit}
						thresholds={thresholds}
						setThresholds={setThresholds}
						selectedWidget={selectedWidget}
						isFillSpans={isFillSpans}
						setIsFillSpans={setIsFillSpans}
						softMin={softMin}
						setSoftMin={setSoftMin}
						softMax={softMax}
						setSoftMax={setSoftMax}
					/>
				</RightContainerWrapper>
			</PanelContainer>
			<Modal
				title={
					isQueryModified ? (
						<Space>
							<WarningOutlined style={{ fontSize: '16px', color: '#fdd600' }} />
							Unsaved Changes
						</Space>
					) : (
						'Save Widget'
					)
				}
				focusTriggerAfterClose
				forceRender
				destroyOnClose
				closable
				onCancel={closeModal}
				onOk={onClickSaveHandler}
				confirmLoading={updateDashboardMutation.isLoading}
				centered
				open={saveModal}
				width={600}
			>
				{!isQueryModified ? (
					<Typography>
						{t('your_graph_build_with')}{' '}
						<QueryTypeTag queryType={currentQuery.queryType} />{' '}
						{t('dashboard_ok_confirm')}
					</Typography>
				) : (
					<Typography>{t('dashboard_unsave_changes')} </Typography>
				)}
			</Modal>
			<Modal
				title={
					<Space>
						<WarningOutlined style={{ fontSize: '16px', color: '#fdd600' }} />
						Unsaved Changes
					</Space>
				}
				focusTriggerAfterClose
				forceRender
				destroyOnClose
				closable
				onCancel={closeModal}
				onOk={discardChanges}
				centered
				open={discardModal}
				width={600}
			>
				<Typography>{t('dashboard_unsave_changes')}</Typography>
			</Modal>
		</Container>
	);
}

export default NewWidget;
