import { describe, it, expect } from 'vitest';
import { buildAiBotRobotsLines, detectAiBot, AI_TRAINING_BOTS, AI_RETRIEVAL_BOTS, } from '../../seo/ai-bots.js';
function uaSet(lines) {
    return new Set(lines.filter((l) => l.startsWith('User-agent: ')).map((l) => l.replace('User-agent: ', '')));
}
describe('buildAiBotRobotsLines', () => {
    it('emits nothing when no policy and no legacy flag', () => {
        expect(buildAiBotRobotsLines(undefined, undefined)).toEqual([]);
        expect(buildAiBotRobotsLines({}, false)).toEqual([]);
    });
    it('blocks only training bots when training=block, retrieval=allow', () => {
        const lines = buildAiBotRobotsLines({ training: 'block', retrieval: 'allow' }, undefined);
        const uas = uaSet(lines);
        expect(uas.has('GPTBot')).toBe(true);
        expect(uas.has('CCBot')).toBe(true);
        // Retrieval bots stay allowed (absent from the disallow list).
        expect(uas.has('PerplexityBot')).toBe(false);
        expect(uas.has('OAI-SearchBot')).toBe(false);
    });
    it('blocks only retrieval bots when retrieval=block, training=allow', () => {
        const lines = buildAiBotRobotsLines({ training: 'allow', retrieval: 'block' }, undefined);
        const uas = uaSet(lines);
        expect(uas.has('PerplexityBot')).toBe(true);
        expect(uas.has('ChatGPT-User')).toBe(true);
        expect(uas.has('GPTBot')).toBe(false);
    });
    it('blocks both groups when both are set to block', () => {
        const lines = buildAiBotRobotsLines({ training: 'block', retrieval: 'block' }, undefined);
        const uas = uaSet(lines);
        expect(uas.size).toBe(AI_TRAINING_BOTS.length + AI_RETRIEVAL_BOTS.length);
    });
    it('legacy blockAIBots=true blocks both groups (back-compat)', () => {
        const lines = buildAiBotRobotsLines(undefined, true);
        const uas = uaSet(lines);
        expect(uas.has('GPTBot')).toBe(true);
        expect(uas.has('PerplexityBot')).toBe(true);
    });
    it('a set aiPolicy overrides the legacy flag', () => {
        // Operator opted into nuance: training blocked, retrieval allowed — even
        // though the legacy flag is also on, the nuanced policy wins.
        const lines = buildAiBotRobotsLines({ training: 'block', retrieval: 'allow' }, true);
        const uas = uaSet(lines);
        expect(uas.has('GPTBot')).toBe(true);
        expect(uas.has('PerplexityBot')).toBe(false);
    });
    it('every blocked bot gets a Disallow: / line', () => {
        const lines = buildAiBotRobotsLines({ training: 'block' }, undefined);
        const uaCount = lines.filter((l) => l.startsWith('User-agent: ')).length;
        const disallowCount = lines.filter((l) => l === 'Disallow: /').length;
        expect(disallowCount).toBe(uaCount);
    });
});
describe('detectAiBot', () => {
    it('returns null for empty / human user agents', () => {
        expect(detectAiBot(null)).toBeNull();
        expect(detectAiBot(undefined)).toBeNull();
        expect(detectAiBot('')).toBeNull();
        expect(detectAiBot('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/120')).toBeNull();
    });
    it('classifies a training crawler', () => {
        expect(detectAiBot('Mozilla/5.0 (compatible; GPTBot/1.1; +https://openai.com/gptbot)')).toEqual({ token: 'GPTBot', category: 'training' });
        expect(detectAiBot('CCBot/2.0 (https://commoncrawl.org/faq/)')).toEqual({
            token: 'CCBot',
            category: 'training',
        });
    });
    it('classifies a retrieval / answer-engine crawler', () => {
        expect(detectAiBot('Mozilla/5.0 (compatible; PerplexityBot/1.0)')).toEqual({
            token: 'PerplexityBot',
            category: 'retrieval',
        });
        expect(detectAiBot('Mozilla/5.0 ... ChatGPT-User/1.0')).toEqual({
            token: 'ChatGPT-User',
            category: 'retrieval',
        });
    });
    it('prefers the more specific *-Extended training token over its search namesake', () => {
        expect(detectAiBot('Mozilla/5.0 (compatible; Applebot-Extended/0.1)')).toEqual({
            token: 'Applebot-Extended',
            category: 'training',
        });
        // Plain Applebot (search/Siri) is retrieval, not training.
        expect(detectAiBot('Mozilla/5.0 (compatible; Applebot/0.1)')).toEqual({
            token: 'Applebot',
            category: 'retrieval',
        });
    });
    it('is case-insensitive', () => {
        expect(detectAiBot('something gptbot something')?.token).toBe('GPTBot');
    });
});
//# sourceMappingURL=ai-bots.test.js.map