import React, { useCallback, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { UseQueryResult } from 'react-query';
import { PlusOutlined } from '@ant-design/icons';
import { Button, Flex, Input, Typography } from 'antd';
import type { ColumnsType } from 'antd/es/table/interface';
import logEvent from 'api/common/logEvent';
import { convertToApiError } from 'api/ErrorResponseHandlerForGeneratedAPIs';
import { createRule } from 'api/generated/services/rules';
import type {
	ListRules200,
	RenderErrorResponseDTO,
	RuletypesRuleDTO,
} from 'api/generated/services/sigNoz.schemas';
import type { ErrorType } from 'api/generatedAPIInstance';
import { AxiosError } from 'axios';
import DropDown from 'components/DropDown/DropDown';
import {
	DynamicColumnsKey,
	TableDataSource,
} from 'components/ResizeTable/contants';
import DynamicColumnTable from 'components/ResizeTable/DynamicColumnTable';
import DateComponent from 'components/ResizeTable/TableComponent/DateComponent';
import LabelColumn from 'components/TableRenderer/LabelColumn';
import TextToolTip from 'components/TextToolTip';
import { QueryParams } from 'constants/query';
import ROUTES from 'constants/routes';
import { sanitizeDefaultAlertQuery } from 'container/EditAlertV2/utils';
import useSortableTable from 'hooks/ResizeTable/useSortableTable';
import useComponentPermission from 'hooks/useComponentPermission';
import useDebouncedFn from 'hooks/useDebouncedFunction';
import useInterval from 'hooks/useInterval';
import { useNotifications } from 'hooks/useNotifications';
import { useSafeNavigate } from 'hooks/useSafeNavigate';
import useUrlQuery from 'hooks/useUrlQuery';
import { mapQueryDataFromApi } from 'lib/newQueryBuilder/queryBuilderMappers/mapQueryDataFromApi';
import { useAppContext } from 'providers/App/App';
import { useErrorModal } from 'providers/ErrorModalProvider';
import { toCompositeMetricQuery } from 'types/api/alerts/convert';
import APIError from 'types/api/error';
import { isModifierKeyPressed } from 'utils/app';

import DeleteAlert from './DeleteAlert';
import { ColumnButton, SearchContainer } from './styles';
import Status from './TableComponents/Status';
import ToggleAlertState from './ToggleAlertState';
import { alertActionLogEvent, filterAlerts } from './utils';

const { Search } = Input;

function ListAlert({ allAlertRules, refetch }: ListAlertProps): JSX.Element {
	const { t } = useTranslation('common');
	const { safeNavigate } = useSafeNavigate();
	const { user } = useAppContext();
	const [addNewAlert, action] = useComponentPermission(
		['add_new_alert', 'action'],
		user.role,
	);

	const [editLoader, setEditLoader] = useState<boolean>(false);
	const [cloneLoader, setCloneLoader] = useState<boolean>(false);

	const params = useUrlQuery();
	const orderColumnParam = params.get('columnKey');
	const orderQueryParam = params.get('order');
	const paginationParam = params.get('page');
	const searchParams = params.get('search');
	const [searchString, setSearchString] = useState<string>(searchParams || '');
	const [data, setData] = useState<RuletypesRuleDTO[]>(() => {
		const value = searchString.toLowerCase();
		const filteredData = filterAlerts(allAlertRules, value);
		return filteredData || [];
	});

	// Type asuring
	const sortingOrder: 'ascend' | 'descend' | null =
		orderQueryParam === 'ascend' || orderQueryParam === 'descend'
			? orderQueryParam
			: null;

	const { sortedInfo, handleChange } = useSortableTable<RuletypesRuleDTO>(
		sortingOrder,
		orderColumnParam || '',
		searchString,
	);

	const { notifications: notificationsApi } = useNotifications();

	useInterval(() => {
		(async (): Promise<void> => {
			const { data: refetchData, status } = await refetch();
			if (status === 'success') {
				const value = searchString.toLowerCase();
				const filteredData = filterAlerts(refetchData?.data ?? [], value);
				setData(filteredData || []);
			}
			if (status === 'error') {
				notificationsApi.error({
					message: t('something_went_wrong'),
				});
			}
		})();
	}, 30000);

	const { showErrorModal } = useErrorModal();

	const onClickNewAlertHandler = useCallback(
		(e: React.MouseEvent): void => {
			logEvent('Alert: New alert button clicked', {
				number: allAlertRules?.length,
				layout: 'new',
			});
			safeNavigate(ROUTES.ALERT_TYPE_SELECTION, {
				newTab: isModifierKeyPressed(e),
			});
		},
		// eslint-disable-next-line react-hooks/exhaustive-deps
		[],
	);

	const onEditHandler = (
		record: RuletypesRuleDTO,
		options?: { newTab?: boolean },
	): void => {
		const compositeQuery = sanitizeDefaultAlertQuery(
			mapQueryDataFromApi(toCompositeMetricQuery(record.condition.compositeQuery)),
			record.alertType,
		);
		params.set(
			QueryParams.compositeQuery,
			encodeURIComponent(JSON.stringify(compositeQuery)),
		);

		const panelType = record.condition.compositeQuery.panelType;
		if (panelType) {
			params.set(QueryParams.panelTypes, panelType);
		}

		params.set(QueryParams.ruleId, record.id);

		setEditLoader(false);

		safeNavigate(`${ROUTES.ALERT_OVERVIEW}?${params.toString()}`, {
			newTab: options?.newTab,
		});
	};

	const onCloneHandler =
		(originalAlert: RuletypesRuleDTO) => async (): Promise<void> => {
			const copyAlert: RuletypesRuleDTO = {
				...originalAlert,
				alert: `${originalAlert.alert} - Copy`,
			};

			try {
				setCloneLoader(true);
				await createRule(copyAlert);

				notificationsApi.success({
					message: 'Success',
					description: 'Alert cloned successfully',
				});

				const { data: refetchData, status } = await refetch();
				const rules = refetchData?.data;
				if (status === 'success' && rules) {
					setData(rules);
					setTimeout(() => {
						const clonedAlert = rules[rules.length - 1];
						params.set(QueryParams.ruleId, String(clonedAlert.id));
						safeNavigate(`${ROUTES.EDIT_ALERTS}?${params.toString()}`);
					}, 2000);
				}
				if (status === 'error') {
					notificationsApi.error({
						message: t('something_went_wrong'),
					});
				}
			} catch (error) {
				showErrorModal(
					convertToApiError(error as AxiosError<RenderErrorResponseDTO>) as APIError,
				);
			} finally {
				setCloneLoader(false);
			}
		};

	const handleSearch = useDebouncedFn((e: unknown) => {
		const value = (e as React.BaseSyntheticEvent).target.value.toLowerCase();
		setSearchString(value);
		const filteredData = filterAlerts(allAlertRules, value);
		setData(filteredData);
	});

	const dynamicColumns: ColumnsType<RuletypesRuleDTO> = [
		{
			title: 'Created At',
			dataIndex: 'createdAt',
			width: 80,
			key: DynamicColumnsKey.CreatedAt,
			align: 'center',
			sorter: (a: RuletypesRuleDTO, b: RuletypesRuleDTO): number => {
				const prev = a.createdAt ? new Date(a.createdAt).getTime() : 0;
				const next = b.createdAt ? new Date(b.createdAt).getTime() : 0;

				return prev - next;
			},
			render: DateComponent,
			sortOrder:
				sortedInfo.columnKey === DynamicColumnsKey.CreatedAt
					? sortedInfo.order
					: null,
		},
		{
			title: 'Created By',
			dataIndex: 'createdBy',
			width: 80,
			key: DynamicColumnsKey.CreatedBy,
			align: 'center',
		},
		{
			title: 'Updated At',
			dataIndex: 'updatedAt',
			width: 80,
			key: DynamicColumnsKey.UpdatedAt,
			align: 'center',
			sorter: (a: RuletypesRuleDTO, b: RuletypesRuleDTO): number => {
				const prev = a.updatedAt ? new Date(a.updatedAt).getTime() : 0;
				const next = b.updatedAt ? new Date(b.updatedAt).getTime() : 0;

				return prev - next;
			},
			render: DateComponent,
			sortOrder:
				sortedInfo.columnKey === DynamicColumnsKey.UpdatedAt
					? sortedInfo.order
					: null,
		},
		{
			title: 'Updated By',
			dataIndex: 'updatedBy',
			width: 80,
			key: DynamicColumnsKey.UpdatedBy,
			align: 'center',
		},
	];

	const columns: ColumnsType<RuletypesRuleDTO> = [
		{
			title: 'Status',
			dataIndex: 'state',
			width: 80,
			key: 'state',
			sorter: (a, b): number =>
				(b.state ? b.state.charCodeAt(0) : 1000) -
				(a.state ? a.state.charCodeAt(0) : 1000),
			render: (value): JSX.Element => <Status status={value} />,
			sortOrder: sortedInfo.columnKey === 'state' ? sortedInfo.order : null,
		},
		{
			title: 'Alert Name',
			dataIndex: 'alert',
			width: 100,
			key: 'name',
			sorter: (alertA, alertB): number => {
				if (alertA.alert && alertB.alert) {
					return alertA.alert.localeCompare(alertB.alert);
				}
				return 0;
			},
			render: (value, record): JSX.Element => {
				const onClickHandler = (e: React.MouseEvent<HTMLElement>): void => {
					e.stopPropagation();
					e.preventDefault();
					onEditHandler(record, { newTab: isModifierKeyPressed(e) });
				};

				return <Typography.Link onClick={onClickHandler}>{value}</Typography.Link>;
			},
			sortOrder: sortedInfo.columnKey === 'name' ? sortedInfo.order : null,
		},
		{
			title: 'Severity',
			dataIndex: 'labels',
			width: 80,
			key: 'severity',
			sorter: (a, b): number =>
				(a?.labels?.severity?.length || 0) - (b?.labels?.severity?.length || 0),
			render: (value): JSX.Element => {
				const objectKeys = value ? Object.keys(value) : [];
				const withSeverityKey = objectKeys.find((e) => e === 'severity') || '';
				const severityValue = withSeverityKey ? value[withSeverityKey] : '-';

				return <Typography>{severityValue}</Typography>;
			},
			sortOrder: sortedInfo.columnKey === 'severity' ? sortedInfo.order : null,
		},
		{
			title: 'Labels',
			dataIndex: 'labels',
			key: 'tags',
			align: 'center',
			width: 100,
			render: (value): JSX.Element => {
				const objectKeys = value ? Object.keys(value) : [];
				const withOutSeverityKeys = objectKeys.filter((e) => e !== 'severity');

				if (withOutSeverityKeys.length === 0) {
					return <Typography>-</Typography>;
				}

				return (
					<LabelColumn labels={withOutSeverityKeys} value={value} color="magenta" />
				);
			},
		},
	];

	if (action) {
		columns.push({
			title: 'Action',
			dataIndex: 'id',
			key: 'action',
			width: 10,
			render: (id: RuletypesRuleDTO['id'], record): JSX.Element => (
				<div data-testid="alert-actions">
					<DropDown
						onDropDownItemClick={(item): void =>
							alertActionLogEvent(item.key, record)
						}
						element={[
							<ToggleAlertState
								key="1"
								disabled={record.disabled ?? false}
								setData={setData}
								id={id ?? ''}
							/>,
							<ColumnButton
								key="2"
								onClick={(e: React.MouseEvent): void =>
									onEditHandler(record, { newTab: isModifierKeyPressed(e) })
								}
								type="link"
								loading={editLoader}
							>
								Edit
							</ColumnButton>,
							<ColumnButton
								key="3"
								onClick={(): void => onEditHandler(record, { newTab: true })}
								type="link"
								loading={editLoader}
							>
								Edit in New Tab
							</ColumnButton>,
							<ColumnButton
								key="3"
								onClick={onCloneHandler(record)}
								type="link"
								loading={cloneLoader}
							>
								Clone
							</ColumnButton>,
							<DeleteAlert
								key="4"
								notifications={notificationsApi}
								setData={setData}
								id={id ?? ''}
							/>,
						]}
					/>
				</div>
			),
		});
	}

	const paginationConfig = {
		defaultCurrent: Number(paginationParam) || 1,
	};
	return (
		<div className="alert-rules-list-container">
			<SearchContainer>
				<Search
					placeholder="Search by Alert Name, Severity and Labels"
					onChange={handleSearch}
					defaultValue={searchString}
				/>
				<Flex gap={12}>
					{addNewAlert && (
						<Button
							type="primary"
							onClick={onClickNewAlertHandler}
							icon={<PlusOutlined />}
						>
							New Alert
						</Button>
					)}
					<TextToolTip
						{...{
							text: `More details on how to create alerts`,
							url: 'https://signoz.io/docs/alerts/?utm_source=product&utm_medium=list-alerts',
							urlText: 'Learn More',
						}}
					/>
				</Flex>
			</SearchContainer>
			<DynamicColumnTable
				tablesource={TableDataSource.Alert}
				columns={columns}
				rowKey="id"
				dataSource={data}
				shouldSendAlertsLogEvent
				dynamicColumns={dynamicColumns}
				onChange={handleChange}
				pagination={paginationConfig}
			/>
		</div>
	);
}

interface ListAlertProps {
	allAlertRules: RuletypesRuleDTO[];
	refetch: UseQueryResult<
		ListRules200,
		ErrorType<RenderErrorResponseDTO>
	>['refetch'];
}

export default ListAlert;
