import { describe, it, expect } from 'vitest';
import { runSeoAuditAnalysis, buildQuickWins, issueKeyFor, } from '../../seo/audit-engine.js';
const goodPage = {
    entityType: 'page',
    entityId: 'p1',
    title: 'Home',
    url: '/',
    content: '<h1>Home</h1>' + 'word '.repeat(400),
    metaTitle: 'Home — Acme, the modern CMS for teams',
    metaDescription: 'Acme is the modern content platform that helps marketing and engineering teams ship reliable, search-optimised websites together.',
    focusKeyword: 'modern cms',
    canonicalUrl: 'https://acme.com/',
    ogTitle: 'Home',
    ogDescription: 'Welcome',
    ogImage: 'https://acme.com/og.png',
    structuredDataType: 'WebPage',
    noindex: false,
};
function findIssues(issues, type) {
    return issues.filter((i) => i.type === type);
}
describe('runSeoAuditAnalysis', () => {
    it('produces no content issues for a fully-optimised page', () => {
        const result = runSeoAuditAnalysis([goodPage]);
        expect(result.pages).toHaveLength(1);
        expect(result.pages[0].score).toBeGreaterThanOrEqual(95);
        expect(result.counts.total).toBe(0);
    });
    it('detects missing meta description', () => {
        const result = runSeoAuditAnalysis([{ ...goodPage, metaDescription: '' }]);
        const found = findIssues(result.issues, 'missing-meta-description');
        expect(found).toHaveLength(1);
        expect(found[0].severity).toBe('warning');
        expect(found[0].fixActionType).toBe('edit-metadata');
    });
    it('does not flag missing canonical when an auto-resolved URL is present', () => {
        const result = runSeoAuditAnalysis([
            {
                ...goodPage,
                canonicalUrl: 'https://acme.com/about',
                url: '/about',
            },
        ]);
        expect(findIssues(result.issues, 'missing-canonical')).toHaveLength(0);
    });
    it('flags missing canonical only when no URL is available', () => {
        const result = runSeoAuditAnalysis([{ ...goodPage, canonicalUrl: '' }]);
        expect(findIssues(result.issues, 'missing-canonical')).toHaveLength(1);
    });
    it('detects duplicate meta titles across pages', () => {
        const a = { ...goodPage, entityId: 'a', url: '/about', metaTitle: 'Same Title Here For Both' };
        const b = {
            ...goodPage,
            entityId: 'b',
            url: '/services',
            metaTitle: 'Same Title Here For Both',
        };
        const result = runSeoAuditAnalysis([a, b]);
        const dup = findIssues(result.issues, 'duplicate-meta-title');
        expect(dup).toHaveLength(1);
        expect(dup[0].severity).toBe('critical');
        expect(dup[0].relatedEntityIds.sort()).toEqual(['a', 'b']);
    });
    it('does not flag duplicate when titles differ', () => {
        const a = { ...goodPage, entityId: 'a', metaTitle: 'Title A unique enough here' };
        const b = { ...goodPage, entityId: 'b', metaTitle: 'Title B unique enough here' };
        const result = runSeoAuditAnalysis([a, b]);
        expect(findIssues(result.issues, 'duplicate-meta-title')).toHaveLength(0);
    });
    it('detects broken internal links from signals', () => {
        const result = runSeoAuditAnalysis([goodPage], {
            brokenLinks: [
                { url: '/services/enterprise', fromEntityId: 'p1', fromTitle: 'Home', fromUrl: '/' },
            ],
        });
        const broken = findIssues(result.issues, 'broken-internal-link');
        expect(broken).toHaveLength(1);
        expect(broken[0].severity).toBe('critical');
        expect(broken[0].category).toBe('technical');
    });
    it('detects missing H1 only in non-empty content', () => {
        const noH1 = { ...goodPage, content: '<p>no heading here</p>' };
        const result = runSeoAuditAnalysis([noH1]);
        expect(findIssues(result.issues, 'missing-h1')).toHaveLength(1);
    });
    it('detects thin content', () => {
        const thin = { ...goodPage, content: '<h1>x</h1> short body', wordCount: 20 };
        const result = runSeoAuditAnalysis([thin]);
        expect(findIssues(result.issues, 'thin-content')).toHaveLength(1);
    });
    it('detects missing alt text on images', () => {
        const withImg = { ...goodPage, content: '<h1>x</h1>' + 'w '.repeat(400) + '<img src="a.png">' };
        const result = runSeoAuditAnalysis([withImg]);
        expect(findIssues(result.issues, 'missing-alt-text')).toHaveLength(1);
    });
    it('detects duplicate meta descriptions across pages', () => {
        const desc = 'Same description text used on both pages which is long enough to pass validation checks here.';
        const a = { ...goodPage, entityId: 'a', url: '/about', metaDescription: desc };
        const b = { ...goodPage, entityId: 'b', url: '/services', metaDescription: desc };
        const result = runSeoAuditAnalysis([a, b]);
        expect(findIssues(result.issues, 'duplicate-meta-description')).toHaveLength(1);
    });
    it('detects accidental noindex on indexable pages', () => {
        const result = runSeoAuditAnalysis([{ ...goodPage, noindex: true }]);
        expect(findIssues(result.issues, 'accidental-noindex')).toHaveLength(1);
    });
    it('flags meta titles outside the 30–60 character range', () => {
        const short = runSeoAuditAnalysis([{ ...goodPage, metaTitle: 'Hi' }]);
        expect(findIssues(short.issues, 'meta-title-length')).toHaveLength(1);
    });
    it('counts issues by severity', () => {
        const bad = {
            entityType: 'page',
            entityId: 'bad',
            title: 'Bad',
            url: '/bad',
            content: '<p>thin</p>',
            metaTitle: '',
            metaDescription: '',
        };
        const result = runSeoAuditAnalysis([bad]);
        expect(result.counts.total).toBeGreaterThan(0);
        expect(result.counts.warning).toBeGreaterThanOrEqual(2); // missing title + desc
    });
    it('computes a site score that drops with missing metadata', () => {
        const great = runSeoAuditAnalysis([goodPage]).siteScore.score;
        const poor = runSeoAuditAnalysis([
            {
                ...goodPage,
                metaTitle: '',
                metaDescription: '',
                structuredDataType: '',
                ogImage: '',
                canonicalUrl: '',
            },
        ]).siteScore.score;
        expect(great).toBeGreaterThan(poor);
    });
});
describe('issueKeyFor', () => {
    it('builds a stable key', () => {
        expect(issueKeyFor('missing-meta-title', 'p1')).toBe('missing-meta-title:p1');
    });
});
describe('buildQuickWins', () => {
    const mk = (type, impact, id) => ({
        issueKey: `${type}:${id}`,
        entityType: 'page',
        entityId: id,
        entityTitle: id,
        url: `/${id}`,
        severity: 'warning',
        category: 'content',
        type,
        title: type,
        description: '',
        impact,
        recommendation: '',
        fixable: true,
        fixActionType: 'edit-metadata',
        relatedEntityIds: [],
    });
    it('ranks higher-impact wins first', () => {
        const wins = buildQuickWins([
            mk('missing-canonical', 'Low', '1'),
            mk('missing-meta-description', 'High', '2'),
            mk('missing-meta-description', 'High', '3'),
        ]);
        expect(wins[0].issueType).toBe('missing-meta-description');
        expect(wins[0].count).toBe(2);
    });
    it('excludes non-fixable issues', () => {
        const issue = { ...mk('thin-content', 'Low', '1'), fixable: false };
        expect(buildQuickWins([issue])).toHaveLength(0);
    });
    it('caps at 5 wins', () => {
        const issues = Array.from({ length: 10 }, (_, i) => mk(`type-${i}`, 'Medium', String(i)));
        expect(buildQuickWins(issues).length).toBeLessThanOrEqual(5);
    });
});
//# sourceMappingURL=audit-engine.test.js.map