/**
 * Unit tests for robodocValidator.
 */
import { jest } from '@jest/globals';

// Capture mock references so tests can call .mockReturnValue() on them
const mockGetRobodocConfig = jest.fn();
const mockGetExpectedRobodocHeader = jest.fn(() => ({ kindChar: 'r', kind: 'report', target: 'REPORT/TEST' }));
const mockGetBaseFilename = jest.fn(() => 'TEST');

// Mock robodocUtils BEFORE importing any module that depends on it
await jest.unstable_mockModule('../../../core/src/robodoc/robodocUtils.js', () => ({
    getRobodocConfig: mockGetRobodocConfig,
    getExpectedRobodocHeader: mockGetExpectedRobodocHeader,
    getBaseFilename: mockGetBaseFilename
}));

const { validateRobodoc } = await import("../../../core/src/validators/robodocValidator.js");
const { makeDocument, alwaysWarn, alwaysOff, messageIds } = await import("./helpers.js");

function enabledConfig(overrides = {}) {
    return {
        enabled: true,
        requireDocBlock: true,
        requiredSections: ['DESCRIPTION', 'CHANGE HISTORY'],
        validateHeaderTarget: true,
        ...overrides
    };
}

describe('validateRobodoc', () => {
    beforeEach(() => {
        mockGetRobodocConfig.mockReturnValue(enabledConfig());
    });

    describe('disabled', () => {
        test('returns empty array when robodoc is disabled', () => {
            mockGetRobodocConfig.mockReturnValue({ enabled: false });
            const doc = makeDocument(['SET x = 1']);
            expect(validateRobodoc(doc, alwaysWarn)).toHaveLength(0);
        });
    });

    describe('happy path — no diagnostics', () => {
        test('returns empty array for document with valid docStart and docEnd', () => {
            mockGetRobodocConfig.mockReturnValue(enabledConfig({ requireDocBlock: false }));
            const doc = makeDocument([
                '//@docStart*r* REPORT/TEST',
                '// DESCRIPTION',
                '// Some description',
                '// CHANGE HISTORY',
                '// 2026-03-12 - initial',
                '//@docEnd'
            ]);
            expect(validateRobodoc(doc, alwaysWarn)).toHaveLength(0);
        });
    });

    describe('ACU-RBD-001 — missing docStart', () => {
        test('flags when requireDocBlock is true and no docStart found', () => {
            const doc = makeDocument(['SET x = 1', 'OUTPUT "done"']);
            const diags = validateRobodoc(doc, alwaysWarn);
            expect(messageIds(diags)).toContain('ACU-RBD-001');
        });

        test('does not flag when requireDocBlock is false and no docStart', () => {
            mockGetRobodocConfig.mockReturnValue(enabledConfig({ requireDocBlock: false }));
            const doc = makeDocument(['SET x = 1']);
            const diags = validateRobodoc(doc, alwaysWarn);
            expect(messageIds(diags)).not.toContain('ACU-RBD-001');
        });
    });

    describe('ACU-RBD-002 — missing docEnd', () => {
        test('flags when docStart exists but no docEnd', () => {
            const doc = makeDocument([
                '//@docStart*r* REPORT/TEST',
                '// DESCRIPTION',
                '// text'
                // no @docEnd
            ]);
            const diags = validateRobodoc(doc, alwaysWarn);
            expect(messageIds(diags)).toContain('ACU-RBD-002');
        });
    });

    describe('ACU-RBD-003 — wrong docStart kind', () => {
        test('flags wrong kind character in docStart', () => {
            const doc = makeDocument([
                '//@docStart*s* REPORT/TEST',
                '// DESCRIPTION',
                '// Some description',
                '// CHANGE HISTORY',
                '// 2026-03-12 - initial',
                '//@docEnd'
            ]);
            const diags = validateRobodoc(doc, alwaysWarn);
            expect(messageIds(diags)).toContain('ACU-RBD-003');
        });
    });

    describe('ACU-RBD-005 — missing required section', () => {
        test('flags when a required section is absent from the doc block', () => {
            const doc = makeDocument([
                '//@docStart*r* REPORT/TEST',
                '// DESCRIPTION',
                '// Some description',
                '//@docEnd'
            ]);
            const diags = validateRobodoc(doc, alwaysWarn);
            expect(messageIds(diags)).toContain('ACU-RBD-005');
        });

        test('returns no section diagnostics when requiredSections is empty', () => {
            mockGetRobodocConfig.mockReturnValue(enabledConfig({ requiredSections: [] }));
            const doc = makeDocument([
                '//@docStart*r* REPORT/TEST',
                '//@docEnd'
            ]);
            const diags = validateRobodoc(doc, alwaysWarn);
            expect(messageIds(diags)).not.toContain('ACU-RBD-005');
        });
    });

    describe('severity', () => {
        test('produces no diagnostics when severity is off', () => {
            const doc = makeDocument(['SET x = 1']);
            expect(validateRobodoc(doc, alwaysOff)).toHaveLength(0);
        });
    });
});
