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

afterEach(cleanup);

const makeInvite = (overrides: Record<string, unknown> = {}) => ({
	id: 'i-1',
	code: 'XYZ1234567',
	displayCode: 'XYZ-1234',
	label: 'Familie',
	useCount: 0,
	maxUses: 5,
	expiresAt: '2027-01-01T00:00:00Z',
	revoked: false,
	status: 'active' as string,
	createdAt: '2025-01-01T00:00:00Z',
	shareableUrl: 'http://example.com/i/i-1',
	...overrides
});

const baseData = (
	overrides: Partial<{
		invites: ReturnType<typeof makeInvite>[];
		status: string;
		loadError: string | null;
		groups: { id: string; name: string; permissions: string[] }[];
		groupsLoadError: string | null;
	}> = {}
) => ({
	invites: [],
	status: 'active',
	loadError: null,
	groups: [],
	groupsLoadError: null,
	...overrides
});

describe('admin/invites page', () => {
	it('renders the page heading and the new-invite button', async () => {
		render(AdminInvitesPage, { props: { data: baseData() } });

		await expect.element(page.getByRole('heading', { name: /einladungen/i })).toBeVisible();
		await expect.element(page.getByRole('button', { name: /neue einladung/i })).toBeVisible();
	});

	it('renders the empty placeholder when the invite list is empty', async () => {
		render(AdminInvitesPage, { props: { data: baseData() } });

		await expect.element(page.getByText('Keine aktiven Einladungen vorhanden.')).toBeVisible();
	});

	it('marks the active filter chip as selected when status is "active"', async () => {
		render(AdminInvitesPage, { props: { data: baseData({ status: 'active' }) } });

		const activeChip = (await page
			.getByRole('link', { name: /^aktiv$/i })
			.element()) as HTMLAnchorElement;
		expect(activeChip.classList.contains('bg-primary')).toBe(true);
	});

	it('marks the show-all filter chip as selected when status is "all"', async () => {
		render(AdminInvitesPage, { props: { data: baseData({ status: 'all' }) } });

		const showAllChip = (await page
			.getByRole('link', { name: /alle anzeigen/i })
			.element()) as HTMLAnchorElement;
		expect(showAllChip.classList.contains('bg-primary')).toBe(true);
	});

	it('renders the load-error banner when data.loadError is set', async () => {
		render(AdminInvitesPage, {
			props: { data: baseData({ loadError: 'INVITE_LOAD_FAILED' }) }
		});

		const banner = document.querySelector('.bg-red-50');
		expect(banner).not.toBeNull();
	});

	it('shows the new-invite form when the new-invite button is clicked', async () => {
		render(AdminInvitesPage, { props: { data: baseData() } });

		await page
			.getByRole('button', { name: /neue einladung/i })
			.first()
			.click();

		await expect.element(page.getByLabelText(/bezeichnung|label/i)).toBeVisible();
	});

	it('shows the createError message inside the form when form.createError is set and the form is open', async () => {
		render(AdminInvitesPage, {
			props: { data: baseData(), form: { createError: 'INVALID_INVITE' } }
		});

		await page
			.getByRole('button', { name: /neue einladung/i })
			.first()
			.click();

		const banners = document.querySelectorAll('.text-red-600');
		expect(banners.length).toBeGreaterThan(0);
	});

	it('shows the created-invite success card with the shareable URL when form.created is set', async () => {
		render(AdminInvitesPage, {
			props: {
				data: baseData(),
				form: { created: makeInvite({ id: 'new', shareableUrl: 'http://example.com/i/new' }) }
			}
		});

		await expect.element(page.getByText('Einladung erstellt')).toBeVisible();
		await expect.element(page.getByText('http://example.com/i/new')).toBeVisible();
	});

	it('renders one row per invite in the table', async () => {
		render(AdminInvitesPage, {
			props: {
				data: baseData({
					invites: [
						makeInvite({ id: 'a', displayCode: 'AAA-1111', label: 'Eltern' }),
						makeInvite({ id: 'b', displayCode: 'BBB-2222', label: 'Geschwister' })
					]
				})
			}
		});

		await expect.element(page.getByText('AAA-1111')).toBeVisible();
		await expect.element(page.getByText('BBB-2222')).toBeVisible();
	});

	it('renders "Aktiv" status with the active visual treatment', async () => {
		render(AdminInvitesPage, {
			props: { data: baseData({ invites: [makeInvite({ status: 'active' })] }) }
		});

		const statusBadge = document.querySelector('tbody [aria-label="Aktiv"]') as HTMLElement | null;
		expect(statusBadge?.classList.contains('bg-green-50')).toBe(true);
	});

	it('renders "Widerrufen" status with the revoked visual treatment', async () => {
		render(AdminInvitesPage, {
			props: { data: baseData({ invites: [makeInvite({ status: 'revoked' })] }) }
		});

		const statusBadge = document.querySelector(
			'tbody [aria-label="Widerrufen"]'
		) as HTMLElement | null;
		expect(statusBadge?.classList.contains('bg-red-50')).toBe(true);
	});

	it('renders "Erschöpft" status with the exhausted visual treatment', async () => {
		render(AdminInvitesPage, {
			props: { data: baseData({ invites: [makeInvite({ status: 'exhausted' })] }) }
		});

		const statusBadge = document.querySelector(
			'tbody [aria-label="Erschöpft"]'
		) as HTMLElement | null;
		expect(statusBadge?.classList.contains('bg-gray-100')).toBe(true);
	});

	it('renders "Abgelaufen" status with the expired visual treatment', async () => {
		render(AdminInvitesPage, {
			props: { data: baseData({ invites: [makeInvite({ status: 'expired' })] }) }
		});

		const statusBadge = document.querySelector(
			'tbody [aria-label="Abgelaufen"]'
		) as HTMLElement | null;
		expect(statusBadge?.classList.contains('bg-amber-50')).toBe(true);
	});

	it('renders the revoke button only for active invites', async () => {
		render(AdminInvitesPage, {
			props: {
				data: baseData({
					invites: [
						makeInvite({ id: 'a', status: 'active' }),
						makeInvite({ id: 'b', status: 'revoked' })
					]
				})
			}
		});

		const revokeButtons = document.querySelectorAll('button[type="submit"]');
		// The new-invite form is hidden by default, so all submit buttons are revoke buttons.
		expect(revokeButtons.length).toBe(1);
	});

	it('renders the unlimited symbol when an invite has no maxUses', async () => {
		render(AdminInvitesPage, {
			props: { data: baseData({ invites: [makeInvite({ maxUses: null, useCount: 7 })] }) }
		});

		await expect.element(page.getByText(/7\s*\/\s*∞/)).toBeVisible();
	});

	it('renders "Kein Ablauf" when an invite has no expiresAt', async () => {
		render(AdminInvitesPage, {
			props: { data: baseData({ invites: [makeInvite({ expiresAt: null })] }) }
		});

		await expect.element(page.getByText('Kein Ablauf')).toBeVisible();
	});

	it('renders the exhausted status with the correct color class', async () => {
		render(AdminInvitesPage, {
			props: { data: baseData({ invites: [makeInvite({ status: 'exhausted' })] }) }
		});

		// gray color for exhausted
		const pill = Array.from(document.querySelectorAll('.bg-gray-100'));
		expect(pill.length).toBeGreaterThan(0);
	});

	it('renders the expired status with the correct color class', async () => {
		render(AdminInvitesPage, {
			props: { data: baseData({ invites: [makeInvite({ status: 'expired' })] }) }
		});

		// amber color for expired
		const pill = Array.from(document.querySelectorAll('.bg-amber-50'));
		expect(pill.length).toBeGreaterThan(0);
	});

	it('renders the revoked status with the correct color class', async () => {
		render(AdminInvitesPage, {
			props: { data: baseData({ invites: [makeInvite({ status: 'revoked' })] }) }
		});

		const pill = Array.from(document.querySelectorAll('.bg-red-50'));
		// May have other red elements (like loadError) — at least one
		expect(pill.length).toBeGreaterThan(0);
	});

	it('toggles the new-invite form when the button is clicked', async () => {
		render(AdminInvitesPage, { props: { data: baseData(), form: undefined } });

		const formBefore = document.querySelector('form[action="?/create"]');
		expect(formBefore).toBeNull();

		const newBtn = Array.from(document.querySelectorAll('button')).find((b) =>
			/neue|invite|einladung/i.test(b.textContent ?? '')
		) as HTMLButtonElement | undefined;
		newBtn?.click();

		await vi.waitFor(() => {
			expect(document.querySelector('form[action="?/create"]')).not.toBeNull();
		});
	});

	it('shows the load error banner when data.loadError is set', async () => {
		render(AdminInvitesPage, {
			props: { data: baseData({ loadError: 'INTERNAL_ERROR' }), form: undefined }
		});

		const banner = document.querySelector('.bg-red-50');
		expect(banner).not.toBeNull();
	});

	// ─── groups section ───────────────────────────────────────────────────────

	it('shows a groups-load warning banner when data.groupsLoadError is set', async () => {
		render(AdminInvitesPage, {
			props: { data: { ...baseData(), groups: [], groupsLoadError: 'INTERNAL_ERROR' } }
		});

		await page
			.getByRole('button', { name: /neue einladung/i })
			.first()
			.click();

		const banner = document.querySelector('.bg-amber-50');
		expect(banner).not.toBeNull();
	});

	it('renders group checkboxes inside the new-invite form when groups are provided', async () => {
		render(AdminInvitesPage, {
			props: {
				data: {
					...baseData(),
					groups: [
						{ id: 'g-1', name: 'Administratoren', permissions: ['ADMIN'] },
						{ id: 'g-2', name: 'Familie', permissions: ['READ_ALL'] }
					],
					groupsLoadError: null
				}
			}
		});

		await page
			.getByRole('button', { name: /neue einladung/i })
			.first()
			.click();

		await expect.element(page.getByRole('checkbox', { name: 'Administratoren' })).toBeVisible();
		await expect.element(page.getByRole('checkbox', { name: 'Familie' })).toBeVisible();
	});

	it('group checkbox stays checked after being clicked', async () => {
		render(AdminInvitesPage, {
			props: {
				data: {
					...baseData(),
					groups: [{ id: 'g-1', name: 'Familie', permissions: ['READ_ALL'] }],
					groupsLoadError: null
				}
			}
		});

		await page
			.getByRole('button', { name: /neue einladung/i })
			.first()
			.click();

		const checkbox = page.getByRole('checkbox', { name: 'Familie' });
		await checkbox.click();
		await expect.element(checkbox).toBeChecked();
	});

	it('amber warning banner has role="alert"', async () => {
		render(AdminInvitesPage, {
			props: { data: { ...baseData(), groups: [], groupsLoadError: 'INTERNAL_ERROR' } }
		});

		await page
			.getByRole('button', { name: /neue einladung/i })
			.first()
			.click();

		const alert = document.querySelector('[role="alert"]');
		expect(alert).not.toBeNull();
	});

	it('checkbox group fieldset has accessible name from i18n key (not hardcoded German)', async () => {
		render(AdminInvitesPage, {
			props: {
				data: {
					...baseData(),
					groups: [{ id: 'g-1', name: 'Familie', permissions: ['READ_ALL'] }],
					groupsLoadError: null
				}
			}
		});

		await page
			.getByRole('button', { name: /neue einladung/i })
			.first()
			.click();

		// m.admin_new_invite_groups() returns "Gruppen (optional)" in de locale
		// The hardcoded legend "Gruppen" would not match this accessible name
		await expect.element(page.getByRole('group', { name: 'Gruppen (optional)' })).toBeVisible();
	});

	it('shows no checkboxes and no warning when groups list is empty and no error', async () => {
		render(AdminInvitesPage, {
			props: { data: { ...baseData(), groups: [], groupsLoadError: null } }
		});

		await page
			.getByRole('button', { name: /neue einladung/i })
			.first()
			.click();

		expect(document.querySelectorAll('input[name="groupIds"]')).toHaveLength(0);
		expect(document.querySelector('.bg-amber-50')).toBeNull();
		// empty-state message visible — "Keine Gruppen vorhanden." in de locale
		await expect.element(page.getByText(/keine gruppen/i)).toBeVisible();
	});
});
