/**
 * @jest-environment node
 */

import {
	createEmptyItem,
	ensureStableIds,
	insertItem,
	updateItemAt,
	removeItemAt,
	reorderItems,
	getCompleteItems,
	getVisibleItems,
} from './items';
import { isValidUuid } from './uuid';
import { getFaqSetupStatus } from './setup-status';
import {
	buildFaqInnerHtml,
	buildFaqClassList,
	escapeHtml,
	sanitizeAnswerHtml,
} from './serialize';
import { migrateToV1 } from './migrate';

describe('FAQ item helpers', () => {
	it('creates items with stable UUID ids', () => {
		const item = createEmptyItem();
		expect(isValidUuid(item.id)).toBe(true);
		expect(item.question).toBe('');
		expect(item.answer).toBe('');
	});

	it('inserts, edits, removes, and reorders while preserving ids', () => {
		let items = [createEmptyItem(), createEmptyItem()];
		const firstId = items[0].id;
		const secondId = items[1].id;

		items = insertItem(items);
		expect(items).toHaveLength(3);
		expect(items[0].id).toBe(firstId);
		expect(items[1].id).toBe(secondId);
		expect(isValidUuid(items[2].id)).toBe(true);

		items = updateItemAt(items, 0, {
			question: 'What is SEOvault?',
			answer: '<p>An SEO toolkit.</p>',
		});
		expect(items[0].id).toBe(firstId);
		expect(items[0].question).toBe('What is SEOvault?');

		items = reorderItems(items, 0, 2);
		expect(items[2].id).toBe(firstId);
		expect(items[0].id).toBe(secondId);

		items = removeItemAt(items, 0);
		expect(items).toHaveLength(2);
		expect(items.find((row) => row.id === firstId)).toBeTruthy();
		expect(items.find((row) => row.id === secondId)).toBeFalsy();
	});

	it('ensureStableIds assigns missing ids and dedupes collisions', () => {
		const shared = '11111111-1111-4111-8111-111111111111';
		const next = ensureStableIds([
			{ id: shared, question: 'A', answer: '1' },
			{ id: shared, question: 'B', answer: '2' },
			{ question: 'C', answer: '3' },
		]);
		expect(next[0].id).toBe(shared);
		expect(next[1].id).not.toBe(shared);
		expect(isValidUuid(next[1].id)).toBe(true);
		expect(isValidUuid(next[2].id)).toBe(true);
		expect(new Set(next.map((row) => row.id)).size).toBe(3);
	});

	it('classifies complete vs visible rows', () => {
		const items = ensureStableIds([
			{ question: 'Q1', answer: '<p>A1</p>' },
			{ question: 'Q2', answer: '' },
			{ question: '', answer: '<p>orphan</p>' },
			{ question: '', answer: '' },
		]);
		expect(getCompleteItems(items)).toHaveLength(1);
		expect(getVisibleItems(items)).toHaveLength(3);
	});
});

describe('FAQ setup status', () => {
	it('does not claim schema is published', () => {
		const empty = getFaqSetupStatus({ items: [] });
		expect(empty.status).toBe('empty');
		expect(empty.message.toLowerCase()).toContain('not published');

		const incomplete = getFaqSetupStatus({
			items: [{ id: '11111111-1111-4111-8111-111111111111', question: 'Only Q', answer: '' }],
		});
		expect(incomplete.status).toBe('incomplete');

		const ready = getFaqSetupStatus({
			items: [
				{
					id: '11111111-1111-4111-8111-111111111111',
					question: 'Q',
					answer: '<p>A</p>',
				},
			],
		});
		expect(ready.status).toBe('ready_for_schema');
		expect(ready.message.toLowerCase()).toContain('separately');
		expect(ready.message.toLowerCase()).not.toContain('published to google');
	});
});

describe('FAQ save serialization', () => {
	it('escapes text and strips script handlers', () => {
		expect(escapeHtml('<b>"x"')).toBe('&lt;b&gt;&quot;x&quot;');
		expect(sanitizeAnswerHtml('<p onclick="alert(1)">Hi</p><script>x</script>')).toBe(
			'<p>Hi</p>'
		);
	});

	it('serializes accordion and static markup with stable item ids', () => {
		const attributes = {
			heading: 'FAQ',
			intro: 'Intro & more',
			displayMode: 'accordion',
			openFirstItem: true,
			showQuestionNumbers: true,
			items: [
				{
					id: 'aaaaaaaa-bbbb-4ccc-8ddd-eeeeeeeeeeee',
					question: 'Q <one>',
					answer: '<p>Answer</p>',
				},
				{
					id: 'bbbbbbbb-bbbb-4ccc-8ddd-eeeeeeeeeeee',
					question: '',
					answer: '',
				},
			],
		};

		const html = buildFaqInnerHtml(attributes);
		expect(html).toContain('<h2 class="seovault-faq-block__heading">FAQ</h2>');
		expect(html).toContain('Intro &amp; more');
		expect(html).toContain('data-faq-item-id="aaaaaaaa-bbbb-4ccc-8ddd-eeeeeeeeeeee"');
		expect(html).toContain('<details');
		expect(html).toContain(' open');
		expect(html).toContain('1. Q &lt;one&gt;');
		expect(html).not.toContain('bbbbbbbb-bbbb-4ccc-8ddd-eeeeeeeeeeee');

		const staticHtml = buildFaqInnerHtml({ ...attributes, displayMode: 'static' });
		expect(staticHtml).toContain('<h3 class="seovault-faq-block__question">');
		expect(staticHtml).not.toContain('<details');

		expect(buildFaqClassList({ displayMode: 'static', sharpCorners: true })).toEqual(
			expect.arrayContaining([
				'seovault-faq-block',
				'seovault-faq-block--static',
				'seovault-faq-block--sharp',
			])
		);
	});
});

describe('FAQ deprecated migration', () => {
	it('migrates title and missing ids to schemaVersion 1', () => {
		const migrated = migrateToV1({
			schemaVersion: 0,
			title: 'Old title',
			intro: 'Hello',
			items: [{ question: 'Q', answer: '<p>A</p>' }],
			displayMode: 'static',
		});

		expect(migrated.schemaVersion).toBe(1);
		expect(migrated.heading).toBe('Old title');
		expect(migrated.intro).toBe('Hello');
		expect(migrated.displayMode).toBe('static');
		expect(migrated.items).toHaveLength(1);
		expect(isValidUuid(migrated.items[0].id)).toBe(true);
		expect(migrated.items[0].question).toBe('Q');
	});
});
