import { afterEach, beforeEach, describe, it, expect, vi } from 'vitest';
import { cleanup, render } from 'vitest-browser-svelte';
import { page } from 'vitest/browser';
import TagsListPanel from './TagsListPanel.svelte';

vi.mock('$app/state', () => ({
	page: { url: { pathname: '/admin/tags/t1' } }
}));

afterEach(cleanup);

const tree = [
	{
		id: 't1',
		name: 'Familie',
		color: undefined,
		documentCount: 3,
		subtreeDocumentCount: 5,
		parentId: undefined,
		children: [
			{
				id: 't2',
				name: 'Eltern',
				color: undefined,
				documentCount: 2,
				subtreeDocumentCount: 2,
				parentId: 't1',
				children: []
			}
		]
	},
	{
		id: 't3',
		name: 'Urlaub',
		color: 'teal',
		documentCount: 0,
		subtreeDocumentCount: 0,
		parentId: undefined,
		children: []
	}
];

describe('TagsListPanel — header', () => {
	it('renders the panel title', async () => {
		render(TagsListPanel, { tree });
		await expect.element(page.getByText(/Schlagwörter/i)).toBeInTheDocument();
	});
});

describe('TagsListPanel — ARIA tree', () => {
	it('renders a role="tree" container', async () => {
		const { container } = render(TagsListPanel, { tree });
		expect(container.querySelector('[role="tree"]')).toBeTruthy();
	});

	it('renders role="treeitem" on each item', async () => {
		const { container } = render(TagsListPanel, { tree });
		const items = container.querySelectorAll('[role="treeitem"]');
		// Both parent and child treeitem
		expect(items.length).toBeGreaterThanOrEqual(2);
	});

	it('sets aria-expanded on nodes with children', async () => {
		const { container } = render(TagsListPanel, { tree });
		const familieItem = container.querySelector<HTMLElement>('[role="treeitem"]');
		expect(familieItem?.hasAttribute('aria-expanded')).toBe(true);
	});

	it('does NOT set aria-expanded on leaf nodes', async () => {
		const { container } = render(TagsListPanel, { tree });
		const items = container.querySelectorAll<HTMLElement>('[role="treeitem"]');
		const urlaubItem = Array.from(items).find((el) => el.textContent?.includes('Urlaub'));
		expect(urlaubItem?.hasAttribute('aria-expanded')).toBe(false);
	});
});

describe('TagsListPanel — tag items', () => {
	it('renders each root tag name as a link', async () => {
		render(TagsListPanel, { tree });
		await expect.element(page.getByRole('link', { name: /familie/i })).toBeInTheDocument();
		await expect.element(page.getByRole('link', { name: /urlaub/i })).toBeInTheDocument();
	});

	it('each tag links to /admin/tags/[id]', async () => {
		const { container } = render(TagsListPanel, { tree });
		const link = container.querySelector<HTMLAnchorElement>('a[href="/admin/tags/t1"]');
		expect(link).toBeTruthy();
	});

	it('renders document count badge when documentCount > 0', async () => {
		const { container } = render(TagsListPanel, { tree });
		// Familie has count 3 — should show "(3)"
		expect(container.textContent).toContain('(3)');
	});

	it('does not render count badge when documentCount is 0', async () => {
		const { container } = render(TagsListPanel, { tree });
		// Urlaub has count 0 — should NOT show "(0)"
		expect(container.textContent).not.toContain('(0)');
	});
});

describe('TagsListPanel — active state', () => {
	it('marks the active tag link with aria-current=page', async () => {
		render(TagsListPanel, { tree });
		await expect
			.element(page.getByRole('link', { name: /familie/i }))
			.toHaveAttribute('aria-current', 'page');
	});

	it('does not mark inactive tag links with aria-current', async () => {
		render(TagsListPanel, { tree });
		await expect
			.element(page.getByRole('link', { name: /urlaub/i }))
			.not.toHaveAttribute('aria-current');
	});
});

describe('TagsListPanel — empty state', () => {
	it('shows empty state when tree is empty', async () => {
		render(TagsListPanel, { tree: [] });
		await expect.element(page.getByText(/keine schlagworte/i)).toBeInTheDocument();
	});
});

describe('TagsListPanel — color dot', () => {
	it('renders color dot on root tags that have a color', async () => {
		render(TagsListPanel, { tree });
		const dot = page.getByTestId('tag-list-color-dot');
		await expect.element(dot).toBeInTheDocument();
		await expect.element(dot).toHaveAttribute('data-color', 'teal');
	});

	it('does not render color dot on tags without a color', async () => {
		render(TagsListPanel, {
			tree: [
				{
					id: 't1',
					name: 'Familie',
					documentCount: 0,
					subtreeDocumentCount: 0,
					parentId: undefined,
					children: [],
					color: undefined
				}
			]
		});
		await expect.element(page.getByTestId('tag-list-color-dot')).not.toBeInTheDocument();
	});
});

describe('TagsListPanel — collapse toggle', () => {
	beforeEach(() => {
		localStorage.removeItem('admin_tags_list_collapsed');
		localStorage.removeItem('admin_tags_tree_state');
	});

	it('renders a collapse button with aria-label', async () => {
		render(TagsListPanel, { tree });
		await expect
			.element(page.getByRole('button', { name: /Liste einklappen/i }))
			.toBeInTheDocument();
	});

	it('clicking collapse shows the expand handle', async () => {
		render(TagsListPanel, { tree });
		await page.getByRole('button', { name: /Liste einklappen/i }).click();
		await expect
			.element(page.getByRole('button', { name: /Liste ausklappen/i }))
			.toBeInTheDocument();
	});

	it('autocollapse prop starts the panel in collapsed state', async () => {
		render(TagsListPanel, { tree, autocollapse: true });
		await expect
			.element(page.getByRole('button', { name: /Liste ausklappen/i }))
			.toBeInTheDocument();
	});

	it('persists collapse state using the tags-specific localStorage key', async () => {
		render(TagsListPanel, { tree });
		const setSpy = vi.spyOn(Storage.prototype, 'setItem');
		document.querySelector<HTMLButtonElement>('[aria-label="Liste einklappen"]')!.click();
		await vi.waitFor(() =>
			expect(setSpy).toHaveBeenCalledWith('admin_tags_list_collapsed', 'true')
		);
		setSpy.mockRestore();
	});
});

describe('TagsListPanel — chevron collapse', () => {
	beforeEach(() => {
		localStorage.removeItem('admin_tags_tree_state');
		localStorage.removeItem('admin_tags_list_collapsed');
	});

	it('child items are visible by default', async () => {
		render(TagsListPanel, { tree });
		await expect.element(page.getByRole('link', { name: /eltern/i })).toBeInTheDocument();
	});

	it('clicking the chevron collapses children', async () => {
		const { container } = render(TagsListPanel, { tree });
		// Find the chevron button inside the Familie treeitem
		const familieItem = Array.from(container.querySelectorAll('[role="treeitem"]')).find((el) =>
			el.textContent?.includes('Familie')
		);
		const chevron = familieItem?.querySelector<HTMLButtonElement>('button[aria-label]');
		chevron?.click();
		await vi.waitFor(() => {
			const eltern = container.querySelector('a[href="/admin/tags/t2"]');
			expect(eltern).toBeFalsy();
		});
	});
});
