import { describe, it, expect, vi, beforeEach } from 'vitest';
import { generateContentResearch, supportsContentResearch, contentResearchFromMetadata, renderContentResearchMarkdown, RESEARCH_ISSUE_TYPES, } from '../../seo/issue-content-research.js';
const generateTextForFeatureMock = vi.fn();
const fetchBrandVoiceUrlSampleMock = vi.fn();
vi.mock('../../ai/index.js', () => ({
    generateTextForFeature: (...args) => generateTextForFeatureMock(...args),
}));
vi.mock('../../ai/brand-voice-sources.js', () => ({
    fetchBrandVoiceUrlSample: (...args) => fetchBrandVoiceUrlSampleMock(...args),
    BrandVoiceSourceError: class BrandVoiceSourceError extends Error {
    },
}));
vi.mock('../../security/audit.js', () => ({
    logEvent: vi.fn(async () => { }),
}));
const entity = {
    entityType: 'page',
    entityId: 'page-1',
    title: 'AI Models Guide',
    url: '/models',
    content: '<p>Short overview.</p>',
    wordCount: 120,
};
const ctx = { entity, updatedAt: '2024-06-27T10:00:00.000Z' };
const deps = { db: {}, userId: 'user-1', collection: 'pages' };
describe('supportsContentResearch', () => {
    it('is limited to thin-content issues', () => {
        expect(RESEARCH_ISSUE_TYPES.has('thin-content')).toBe(true);
        expect(supportsContentResearch('thin-content')).toBe(true);
        expect(supportsContentResearch('missing-h1')).toBe(false);
    });
});
describe('generateContentResearch', () => {
    beforeEach(() => {
        generateTextForFeatureMock.mockReset();
        fetchBrandVoiceUrlSampleMock.mockReset();
    });
    it('parses structured JSON and attaches competitor insights', async () => {
        fetchBrandVoiceUrlSampleMock.mockResolvedValue({
            title: 'Competitor page',
            text: 'They cover pricing and support tiers in detail.',
        });
        generateTextForFeatureMock.mockResolvedValue({
            ok: true,
            text: JSON.stringify({
                summary: 'Expand with pricing tiers and model comparison tables.',
                focusKeyword: 'AI model pricing',
                suggestedWordCount: 650,
                outline: ['Overview', 'Pricing tiers', 'FAQ'],
                faqCandidates: ['How much does it cost?'],
                entitiesToMention: ['GPT-4', 'Claude'],
                competitorNotes: ['Competitor emphasizes pricing tables'],
            }),
        });
        const result = await generateContentResearch({
            id: 'issue-1',
            type: 'thin-content',
            title: 'Content below 300 words',
            entityId: 'page-1',
        }, ctx, deps, { competitorUrls: ['https://example.com/pricing'] });
        expect(result.ok).toBe(true);
        if (!result.ok)
            return;
        expect(result.research.outline).toHaveLength(3);
        expect(result.research.competitorInsights).toHaveLength(1);
        expect(fetchBrandVoiceUrlSampleMock).toHaveBeenCalledWith('https://example.com/pricing');
    });
    it('rejects unsupported issue types', async () => {
        const result = await generateContentResearch({ id: 'i1', type: 'missing-h1', title: 'Missing H1', entityId: 'page-1' }, ctx, deps);
        expect(result.ok).toBe(false);
        if (result.ok)
            return;
        expect(result.code).toBe('unsupported');
    });
});
describe('contentResearchFromMetadata', () => {
    it('returns null when fingerprint is stale', () => {
        const loaded = contentResearchFromMetadata({
            contentResearch: {
                fingerprint: 'stale',
                generatedAt: '2024-01-01T00:00:00.000Z',
                summary: 'Old research',
                focusKeyword: null,
                suggestedWordCount: null,
                outline: [],
                faqCandidates: [],
                entitiesToMention: [],
                competitorInsights: [],
            },
        }, 'thin-content', 'page-1', ctx.updatedAt);
        expect(loaded).toBeNull();
    });
});
describe('renderContentResearchMarkdown', () => {
    it('formats research for export', () => {
        const md = renderContentResearchMarkdown({
            issueType: 'thin-content',
            entityId: 'page-1',
            fingerprint: 'x',
            generatedAt: '2024-01-01T00:00:00.000Z',
            summary: 'Add pricing and FAQ sections.',
            focusKeyword: 'pricing',
            suggestedWordCount: 500,
            outline: ['Pricing', 'FAQ'],
            faqCandidates: ['What plans exist?'],
            entitiesToMention: ['Pro plan'],
            competitorInsights: [],
        });
        expect(md).toContain('Topic research');
        expect(md).toContain('pricing');
        expect(md).toContain('What plans exist?');
    });
});
//# sourceMappingURL=issue-content-research.test.js.map