import { fireEvent, render, screen } from '@testing-library/react';
import type { DefaultOptionType } from 'antd/es/select';
import { createMockAlertContextState } from 'container/CreateAlertV2/EvaluationSettings/__tests__/testUtils';
import { getAppContextMockState } from 'container/RoutingPolicies/__tests__/testUtils';
import * as appHooks from 'providers/App/App';
import { Channels } from 'types/api/channels/getAll';

import * as context from '../../context';
import ThresholdItem from '../ThresholdItem';
import { ThresholdItemProps } from '../types';

jest.spyOn(appHooks, 'useAppContext').mockReturnValue(getAppContextMockState());

jest.mock('uplot', () => {
	const paths = {
		spline: jest.fn(),
		bars: jest.fn(),
	};
	const uplotMock: any = jest.fn(() => ({
		paths,
	}));
	uplotMock.paths = paths;
	return uplotMock;
});

const mockSetAlertState = jest.fn();
const mockSetThresholdState = jest.fn();
jest.spyOn(context, 'useCreateAlertState').mockReturnValue(
	createMockAlertContextState({
		setThresholdState: mockSetThresholdState,
		setAlertState: mockSetAlertState,
	}),
);

const TEST_CONSTANTS = {
	THRESHOLD_ID: 'test-threshold-1',
	CRITICAL_LABEL: 'CRITICAL',
	WARNING_LABEL: 'WARNING',
	INFO_LABEL: 'INFO',
	CHANNEL_1: 'channel-1',
	CHANNEL_2: 'channel-2',
	CHANNEL_3: 'channel-3',
	EMAIL_CHANNEL_NAME: 'Email Channel',
	EMAIL_CHANNEL_TRUNCATED: 'Email Chan...',
	ENTER_THRESHOLD_NAME: 'Enter threshold name',
	ENTER_THRESHOLD_VALUE: 'Enter threshold value',
	ENTER_RECOVERY_THRESHOLD_VALUE: 'Enter recovery threshold value',
} as const;

const mockThreshold = {
	id: TEST_CONSTANTS.THRESHOLD_ID,
	label: TEST_CONSTANTS.CRITICAL_LABEL,
	thresholdValue: 100,
	recoveryThresholdValue: 80,
	unit: 'bytes',
	channels: [TEST_CONSTANTS.CHANNEL_1],
	color: '#ff0000',
};

const mockChannels: Channels[] = [
	{
		id: TEST_CONSTANTS.CHANNEL_1,
		name: TEST_CONSTANTS.EMAIL_CHANNEL_NAME,
	} as any,
	{ id: TEST_CONSTANTS.CHANNEL_2, name: 'Slack Channel' } as any,
	{ id: TEST_CONSTANTS.CHANNEL_3, name: 'PagerDuty Channel' } as any,
];

const mockUnits: DefaultOptionType[] = [
	{ label: 'Bytes', value: 'bytes' },
	{ label: 'KB', value: 'kb' },
	{ label: 'MB', value: 'mb' },
];

const defaultProps: ThresholdItemProps = {
	threshold: mockThreshold,
	updateThreshold: jest.fn(),
	removeThreshold: jest.fn(),
	showRemoveButton: false,
	channels: mockChannels,
	isLoadingChannels: false,
	units: mockUnits,
	isErrorChannels: false,
	refreshChannels: jest.fn(),
};

const renderThresholdItem = (
	props: Partial<ThresholdItemProps> = {},
): ReturnType<typeof render> => {
	const mergedProps = { ...defaultProps, ...props };
	return render(<ThresholdItem {...mergedProps} />);
};

const verifySelectorWidth = (
	selectorIndex: number,
	expectedWidth: string,
): void => {
	const selectors = screen.getAllByRole('combobox');
	const selector = selectors[selectorIndex];
	expect(selector.closest('.ant-select')).toHaveStyle(`width: ${expectedWidth}`);
};

// TODO: Unskip this when recovery threshold is implemented
// const showRecoveryThreshold = (): void => {
// 	const recoveryButton = screen.getByRole('button', { name: '' });
// 	fireEvent.click(recoveryButton);
// };

const verifyComponentRendersWithLoading = (): void => {
	expect(
		screen.getByPlaceholderText(TEST_CONSTANTS.ENTER_THRESHOLD_NAME),
	).toBeInTheDocument();
};

const verifyUnitSelectorDisabled = (): void => {
	const unitSelectors = screen.getAllByRole('combobox');
	const unitSelector = unitSelectors[0]; // First combobox is the unit selector
	expect(unitSelector).toBeDisabled();
};

describe('ThresholdItem', () => {
	beforeEach(() => {
		jest.clearAllMocks();
	});

	it('renders threshold indicator with correct color', () => {
		renderThresholdItem();

		// Find the threshold dot by its class
		const thresholdDot = document.querySelector('.threshold-dot');
		expect(thresholdDot).toHaveStyle('background-color: #ff0000');
	});

	it('renders threshold label input with correct value', () => {
		renderThresholdItem();

		const labelInput = screen.getByPlaceholderText(
			TEST_CONSTANTS.ENTER_THRESHOLD_NAME,
		);
		expect(labelInput).toHaveValue(TEST_CONSTANTS.CRITICAL_LABEL);
	});

	it('renders threshold value input with correct value', () => {
		renderThresholdItem();

		const valueInput = screen.getByPlaceholderText(
			TEST_CONSTANTS.ENTER_THRESHOLD_VALUE,
		);
		expect(valueInput).toHaveValue(100);
	});

	it('renders unit selector with correct value', () => {
		renderThresholdItem();

		// Check for the unit selector by looking for the displayed text
		expect(screen.getByText('Bytes')).toBeInTheDocument();
	});

	it('updates threshold label when label input changes', () => {
		const updateThreshold = jest.fn();
		renderThresholdItem({ updateThreshold });

		const labelInput = screen.getByPlaceholderText(
			TEST_CONSTANTS.ENTER_THRESHOLD_NAME,
		);
		fireEvent.change(labelInput, {
			target: { value: TEST_CONSTANTS.WARNING_LABEL },
		});

		expect(updateThreshold).toHaveBeenCalledWith(
			TEST_CONSTANTS.THRESHOLD_ID,
			'label',
			TEST_CONSTANTS.WARNING_LABEL,
		);
	});

	it('updates threshold value when value input changes', () => {
		const updateThreshold = jest.fn();
		renderThresholdItem({ updateThreshold });

		const valueInput = screen.getByPlaceholderText(
			TEST_CONSTANTS.ENTER_THRESHOLD_VALUE,
		);
		fireEvent.change(valueInput, { target: { value: '200' } });

		expect(updateThreshold).toHaveBeenCalledWith(
			TEST_CONSTANTS.THRESHOLD_ID,
			'thresholdValue',
			'200',
		);
	});

	it('updates threshold unit when unit selector changes', () => {
		const updateThreshold = jest.fn();
		renderThresholdItem({ updateThreshold });

		// Find the unit selector by its role and simulate change
		const unitSelectors = screen.getAllByRole('combobox');
		const unitSelector = unitSelectors[0]; // First combobox is the unit selector

		// Simulate clicking to open the dropdown and selecting a value
		fireEvent.click(unitSelector);

		// The actual change event might not work the same way with Ant Design Select
		// So we'll just verify the selector is present and can be interacted with
		expect(unitSelector).toBeInTheDocument();
	});

	it('updates threshold channels when channels selector changes', () => {
		const updateThreshold = jest.fn();
		renderThresholdItem({ updateThreshold });

		// Find the channels selector by its role and simulate change
		const channelSelectors = screen.getAllByRole('combobox');
		const channelSelector = channelSelectors[1]; // Second combobox is the channels selector

		// Simulate clicking to open the dropdown
		fireEvent.click(channelSelector);

		// The actual change event might not work the same way with Ant Design Select
		// So we'll just verify the selector is present and can be interacted with
		expect(channelSelector).toBeInTheDocument();
	});

	it('shows remove button when showRemoveButton is true', () => {
		renderThresholdItem({ showRemoveButton: true });

		// The remove button is the second button (with circle-x icon)
		const buttons = screen.getAllByRole('button');
		expect(buttons).toHaveLength(1); // remove button
	});

	it('does not show remove button when showRemoveButton is false', () => {
		renderThresholdItem({ showRemoveButton: false });

		// No buttons should be present
		const buttons = screen.queryAllByRole('button');
		expect(buttons).toHaveLength(0);
	});

	it('calls removeThreshold when remove button is clicked', () => {
		const removeThreshold = jest.fn();
		renderThresholdItem({ showRemoveButton: true, removeThreshold });

		// The remove button is the first button (with circle-x icon)
		const buttons = screen.getAllByRole('button');
		const removeButton = buttons[0];
		fireEvent.click(removeButton);

		expect(removeThreshold).toHaveBeenCalledWith(TEST_CONSTANTS.THRESHOLD_ID);
	});

	// TODO: Unskip this when recovery threshold is implemented
	it.skip('shows recovery threshold inputs when recovery button is clicked', () => {
		renderThresholdItem();

		// The recovery button is the first button (with chart-line icon)
		const buttons = screen.getAllByRole('button');
		const recoveryButton = buttons[0]; // First button is the recovery button
		fireEvent.click(recoveryButton);

		expect(
			screen.getByPlaceholderText('Enter recovery threshold value'),
		).toBeInTheDocument();
		expect(
			screen.getByPlaceholderText(TEST_CONSTANTS.ENTER_RECOVERY_THRESHOLD_VALUE),
		).toBeInTheDocument();
	});

	// TODO: Unskip this when recovery threshold is implemented
	it.skip('updates recovery threshold value when input changes', () => {
		const updateThreshold = jest.fn();
		renderThresholdItem({ updateThreshold });

		// Show recovery threshold first
		const buttons = screen.getAllByRole('button');
		const recoveryButton = buttons[0]; // First button is the recovery button
		fireEvent.click(recoveryButton);

		const recoveryValueInput = screen.getByPlaceholderText(
			TEST_CONSTANTS.ENTER_RECOVERY_THRESHOLD_VALUE,
		);
		fireEvent.change(recoveryValueInput, { target: { value: '90' } });

		expect(updateThreshold).toHaveBeenCalledWith(
			TEST_CONSTANTS.THRESHOLD_ID,
			'recoveryThresholdValue',
			'90',
		);
	});

	it('disables unit selector when no units are available', () => {
		renderThresholdItem({ units: [] });
		verifyUnitSelectorDisabled();
	});

	it('shows tooltip when no units are available', () => {
		renderThresholdItem({ units: [] });

		// The tooltip should be present when hovering over disabled unit selector
		verifyUnitSelectorDisabled();
	});

	it('handles empty threshold values correctly', () => {
		const emptyThreshold = {
			...mockThreshold,
			label: '',
			thresholdValue: 0,
			unit: '',
			channels: [],
		};

		renderThresholdItem({ threshold: emptyThreshold });

		expect(screen.getByPlaceholderText('Enter threshold name')).toHaveValue('');
		expect(screen.getByPlaceholderText('Enter threshold value')).toHaveValue(0);
	});

	it('renders with correct input widths', () => {
		renderThresholdItem();

		const labelInput = screen.getByPlaceholderText(
			TEST_CONSTANTS.ENTER_THRESHOLD_NAME,
		);
		const valueInput = screen.getByPlaceholderText(
			TEST_CONSTANTS.ENTER_THRESHOLD_VALUE,
		);

		expect(labelInput).toHaveStyle('width: 200px');
		expect(valueInput).toHaveStyle('width: 100px');
	});

	it('renders channels selector with correct width', () => {
		renderThresholdItem();
		verifySelectorWidth(1, '350px');
	});

	it('renders unit selector with correct width', () => {
		renderThresholdItem();
		verifySelectorWidth(0, '150px');
	});

	it('handles loading channels state', () => {
		renderThresholdItem({ isLoadingChannels: true });
		verifyComponentRendersWithLoading();
	});

	it.skip('renders recovery threshold with correct initial value', () => {
		renderThresholdItem();
		// showRecoveryThreshold();

		const recoveryValueInput = screen.getByPlaceholderText(
			TEST_CONSTANTS.ENTER_RECOVERY_THRESHOLD_VALUE,
		);
		expect(recoveryValueInput).toHaveValue(80);
	});

	it('handles threshold without channels', () => {
		const thresholdWithoutChannels = {
			...mockThreshold,
			channels: [],
		};

		renderThresholdItem({ threshold: thresholdWithoutChannels });

		// Should render channels selector without selected values
		const channelSelectors = screen.getAllByRole('combobox');
		expect(channelSelectors).toHaveLength(2); // Should have both unit and channel selectors
	});
});
