import { describe, it, expect } from 'vitest';
import { isDense, monthHistogram, DENSE_THRESHOLD } from './timelineDensity';
import type { components } from '$lib/generated/api';

type TimelineEntryDTO = components['schemas']['TimelineEntryDTO'];

function letter(eventDate: string): TimelineEntryDTO {
	return {
		kind: 'LETTER',
		precision: 'DAY',
		derived: false,
		senderName: 'Karl',
		receiverName: 'Elfriede',
		eventDate
	};
}

describe('isDense', () => {
	it('uses a threshold of 12', () => {
		expect(DENSE_THRESHOLD).toBe(12);
	});

	it('is false at exactly 12 letters (still rendered as individual cards)', () => {
		expect(isDense(12)).toBe(false);
	});

	it('is true above 12 letters (collapses to a strip)', () => {
		expect(isDense(13)).toBe(true);
	});

	it('is false for empty and small bands', () => {
		expect(isDense(0)).toBe(false);
		expect(isDense(3)).toBe(false);
	});
});

describe('monthHistogram', () => {
	it('returns exactly 12 buckets for the band year, Jan..Dec', () => {
		const buckets = monthHistogram([letter('1915-03-04')], 1915);
		expect(buckets).toHaveLength(12);
		expect(buckets.map((b) => b.month)).toEqual([
			'1915-01',
			'1915-02',
			'1915-03',
			'1915-04',
			'1915-05',
			'1915-06',
			'1915-07',
			'1915-08',
			'1915-09',
			'1915-10',
			'1915-11',
			'1915-12'
		]);
	});

	it('counts each letter on its eventDate month; counts sum to the total', () => {
		// 30 letters spread one-or-more per month across 1915.
		const dist: Record<string, number> = {
			'01': 1,
			'02': 2,
			'03': 3,
			'04': 4,
			'05': 1,
			'06': 5,
			'07': 2,
			'08': 6,
			'09': 1,
			'10': 2,
			'11': 2,
			'12': 1
		};
		const letters: TimelineEntryDTO[] = [];
		for (const [mm, n] of Object.entries(dist)) {
			for (let i = 0; i < n; i++) letters.push(letter(`1915-${mm}-10`));
		}
		expect(letters).toHaveLength(30);

		const buckets = monthHistogram(letters, 1915);
		expect(buckets.reduce((sum, b) => sum + b.count, 0)).toBe(30);
		for (const b of buckets) {
			expect(b.count).toBe(dist[b.month.slice(5)]);
		}
	});

	it('yields height 0 for the eleven empty months when letters cluster in one', () => {
		const buckets = monthHistogram([letter('1915-03-01'), letter('1915-03-28')], 1915);
		const march = buckets.find((b) => b.month === '1915-03');
		expect(march?.count).toBe(2);
		expect(buckets.filter((b) => b.month !== '1915-03').every((b) => b.count === 0)).toBe(true);
	});

	it('counts coarser-than-month precisions on their eventDate anchor month', () => {
		const seasonLetter: TimelineEntryDTO = { ...letter('1915-07-01'), precision: 'SEASON' };
		const buckets = monthHistogram([seasonLetter], 1915);
		expect(buckets.find((b) => b.month === '1915-07')?.count).toBe(1);
	});

	it('ignores entries without an eventDate', () => {
		const undated: TimelineEntryDTO = {
			kind: 'LETTER',
			precision: 'UNKNOWN',
			derived: false,
			senderName: 'Karl',
			receiverName: 'Elfriede'
		};
		const buckets = monthHistogram([undated, letter('1915-05-01')], 1915);
		expect(buckets.reduce((sum, b) => sum + b.count, 0)).toBe(1);
	});
});
