import { Query } from 'types/api/queryBuilder/queryBuilderData';
import { EQueryType } from 'types/common/dashboard';
import { DataSource } from 'types/common/queryBuilder';

import { getStepIntervalPoints, updateStepInterval } from '../utils';

describe('GridCardLayout Utils', () => {
	describe('getStepIntervalPoints', () => {
		it('should return 60 points for duration <= 1 hour', () => {
			// 30 minutes in milliseconds
			const start = Date.now();
			const end = start + 30 * 60 * 1000;

			expect(getStepIntervalPoints(start, end)).toBe(60);
		});

		it('should return 60 points for exactly 1 hour', () => {
			// 1 hour in milliseconds
			const start = Date.now();
			const end = start + 60 * 60 * 1000;

			expect(getStepIntervalPoints(start, end)).toBe(60);
		});

		it('should return 120 points for duration <= 3 hours', () => {
			// 2 hours in milliseconds
			const start = Date.now();
			const end = start + 2 * 60 * 60 * 1000;

			expect(getStepIntervalPoints(start, end)).toBe(120);
		});

		it('should return 120 points for exactly 3 hours', () => {
			// 3 hours in milliseconds
			const start = Date.now();
			const end = start + 3 * 60 * 60 * 1000;

			expect(getStepIntervalPoints(start, end)).toBe(120);
		});

		it('should return 180 points for duration <= 5 hours', () => {
			// 4 hours in milliseconds
			const start = Date.now();
			const end = start + 4 * 60 * 60 * 1000;

			expect(getStepIntervalPoints(start, end)).toBe(180);
		});

		it('should return 180 points for exactly 5 hours', () => {
			// 5 hours in milliseconds
			const start = Date.now();
			const end = start + 5 * 60 * 60 * 1000;

			expect(getStepIntervalPoints(start, end)).toBe(180);
		});

		it('should calculate dynamic interval for duration > 5 hours', () => {
			// 10 hours in milliseconds
			const start = Date.now();
			const end = start + 10 * 60 * 60 * 1000;

			const result = getStepIntervalPoints(start, end);

			// For 10 hours (600 minutes), interval should be ceil(600/80) = 8, rounded to 10, then * 60 = 600
			expect(result).toBe(600);
		});

		it('should handle very long durations correctly', () => {
			// 7 days in milliseconds
			const start = Date.now();
			const end = start + 7 * 24 * 60 * 60 * 1000;

			const result = getStepIntervalPoints(start, end);

			// For 7 days (10080 minutes), interval should be ceil(10080/80) = 126, rounded to 130, then * 60 = 7800
			expect(result).toBe(7800);
		});

		it('should round up to nearest multiple of 5 minutes', () => {
			// 12 hours in milliseconds
			const start = Date.now();
			const end = start + 12 * 60 * 60 * 1000;

			const result = getStepIntervalPoints(start, end);

			// For 12 hours (720 minutes), interval should be ceil(720/80) = 9, rounded to 10, then * 60 = 600
			expect(result).toBe(600);
		});

		it('should handle edge case with very small duration', () => {
			// 1 minute in milliseconds
			const start = Date.now();
			const end = start + 1 * 60 * 1000;

			expect(getStepIntervalPoints(start, end)).toBe(60);
		});

		it('should handle zero duration', () => {
			const start = Date.now();
			const end = start;

			expect(getStepIntervalPoints(start, end)).toBe(60);
		});
	});

	describe('updateStepInterval', () => {
		const mockQuery: Query = {
			queryType: EQueryType.QUERY_BUILDER,
			builder: {
				queryData: [
					{
						stepInterval: 30,
						aggregateOperator: 'avg',
						dataSource: DataSource.METRICS,
						queryName: 'A',
						aggregateAttribute: { key: 'cpu_usage', type: 'Gauge' },
						timeAggregation: 'avg',
						spaceAggregation: 'avg',
						functions: [],
						filters: { items: [], op: 'AND' },
						expression: 'A',
						disabled: false,
						having: [],
						groupBy: [],
						orderBy: [],
						limit: null,
						offset: 0,
						pageSize: 0,
						reduceTo: 'avg',
						legend: '',
					},
				],
				queryFormulas: [],
			},
			clickhouse_sql: [],
			promql: [],
			id: 'test-query',
		};

		it('should update stepInterval based on time range', () => {
			// 2 hours duration
			const minTime = Date.now();
			const maxTime = minTime + 2 * 60 * 60 * 1000;

			const result = updateStepInterval(mockQuery, minTime, maxTime);

			expect(result.builder.queryData[0].stepInterval).toBe(120);
		});

		it('should preserve other query properties', () => {
			const minTime = Date.now();
			const maxTime = minTime + 1 * 60 * 60 * 1000;

			const result = updateStepInterval(mockQuery, minTime, maxTime);

			expect(result.builder.queryData[0].aggregateOperator).toBe('avg');
			expect(result.builder.queryData[0].queryName).toBe('A');
			expect(result.builder.queryData[0].dataSource).toBe('metrics');
		});

		it('should handle multiple queryData items', () => {
			const multiQueryMock: Query = {
				...mockQuery,
				builder: {
					queryData: [
						...mockQuery.builder.queryData,
						{
							...mockQuery.builder.queryData[0],
							queryName: 'B',
							stepInterval: 45,
						},
					],
					queryFormulas: [],
				},
			};

			const minTime = Date.now();
			const maxTime = minTime + 4 * 60 * 60 * 1000;

			const result = updateStepInterval(multiQueryMock, minTime, maxTime);

			expect(result.builder.queryData).toHaveLength(2);
			expect(result.builder.queryData[0].stepInterval).toBe(180);
			expect(result.builder.queryData[1].stepInterval).toBe(180);
		});

		it('should use calculated stepInterval when original is undefined', () => {
			const queryWithUndefinedStep: Query = {
				...mockQuery,
				builder: {
					queryData: [
						{
							...mockQuery.builder.queryData[0],
							stepInterval: undefined as any,
						},
					],
					queryFormulas: [],
				},
			};

			const minTime = Date.now();
			const maxTime = minTime + 1 * 60 * 60 * 1000;

			const result = updateStepInterval(queryWithUndefinedStep, minTime, maxTime);

			expect(result.builder.queryData[0].stepInterval).toBe(60);
		});

		it('should fallback to 60 when calculated stepInterval is 0', () => {
			const minTime = Date.now();
			const maxTime = minTime; // Same time = 0 duration

			const result = updateStepInterval(mockQuery, minTime, maxTime);

			expect(result.builder.queryData[0].stepInterval).toBe(60);
		});

		it('should handle very large time ranges', () => {
			const minTime = Date.now();
			const maxTime = minTime + 30 * 24 * 60 * 60 * 1000; // 30 days

			const result = updateStepInterval(mockQuery, minTime, maxTime);

			// Should calculate appropriate interval for 30 days
			expect(result.builder.queryData[0].stepInterval).toBeGreaterThan(180);
		});
	});
});
