import { describe, expect, it } from 'bun:test';
import { applySync } from './config-sync.js';
const NEW_BLOCK = [
    '    // [quickback:options-start]',
    '    // ── new content ──',
    '    // openapi: { generate: true, publish: true },',
    '    // [quickback:options-end]',
].join('\n');
describe('config-sync applySync', () => {
    // User story: As a Quickback user with an existing config containing the marker block, I need
    // the kitchen-sink to be refreshed wholesale every compile so newly added options surface
    // immediately without me having to upgrade my CLI.
    it('replaces the body between markers without touching surrounding code', () => {
        const original = [
            'export default defineConfig({',
            '    name: "demo",',
            '    template: "hono",',
            '    providers: cloudflare({}),',
            '',
            '    // [quickback:options-start]',
            '    // outdated content',
            '    // foo: { bar: true },',
            '    // [quickback:options-end]',
            '});',
            '',
        ].join('\n');
        const { text, inserted, skippedReason } = applySync(original, NEW_BLOCK);
        expect(skippedReason).toBeUndefined();
        expect(inserted).toBe(false);
        expect(text).toContain('name: "demo",');
        expect(text).toContain('// ── new content ──');
        expect(text).not.toContain('outdated content');
        // Surrounding lines are preserved verbatim
        expect(text.startsWith('export default defineConfig({')).toBe(true);
        expect(text.endsWith('});\n')).toBe(true);
    });
    // User story: As a Quickback user with a legacy config that pre-dates the marker convention,
    // I need the first compile to insert the marker block automatically just inside the closing
    // }) of defineConfig so I do not have to hand-edit the file.
    it('inserts marker block before the closing `})` when sentinels are absent', () => {
        const original = [
            'export default defineConfig({',
            '    name: "demo",',
            '    template: "hono",',
            '    providers: cloudflare({}),',
            '});',
            '',
        ].join('\n');
        const { text, inserted, skippedReason } = applySync(original, NEW_BLOCK);
        expect(skippedReason).toBeUndefined();
        expect(inserted).toBe(true);
        expect(text).toContain('// [quickback:options-start]');
        expect(text).toContain('// [quickback:options-end]');
        // The block sits before the closing brace, not after the file ends
        const blockIdx = text.indexOf('// [quickback:options-start]');
        const closeIdx = text.indexOf('});');
        expect(blockIdx).toBeLessThan(closeIdx);
    });
    // User story: As a Quickback user, I need a no-op compile to not rewrite my config so file
    // mtimes stay stable and editors do not flag a phantom change after every compile.
    it('returns identical text when the block is already up to date', () => {
        const original = [
            'export default defineConfig({',
            '    name: "demo",',
            '    template: "hono",',
            '    providers: cloudflare({}),',
            '',
            '    // [quickback:options-start]',
            '    // ── new content ──',
            '    // openapi: { generate: true, publish: true },',
            '    // [quickback:options-end]',
            '});',
            '',
        ].join('\n');
        const { text } = applySync(original, NEW_BLOCK);
        expect(text).toBe(original);
    });
    // User story: As a Quickback user who half-deleted the markers by accident, I need the sync
    // step to refuse to rewrite the file rather than guess where the block ends, so I can fix
    // the file by hand without losing surrounding content.
    it('refuses to overwrite when only one sentinel is present', () => {
        const original = [
            'export default defineConfig({',
            '    name: "demo",',
            '    providers: cloudflare({}),',
            '    // [quickback:options-start]',
            '    // some leftover content with no end sentinel',
            '});',
        ].join('\n');
        const { text, skippedReason } = applySync(original, NEW_BLOCK);
        expect(text).toBe(original);
        expect(skippedReason).toBeDefined();
        expect(skippedReason).toContain('one sentinel');
    });
    // User story: As a Quickback user whose config does not call defineConfig (e.g. a hand-rolled
    // object literal export), I need the sync step to skip rather than corrupt the file.
    it('skips when defineConfig is not present', () => {
        const original = 'export default { name: "demo" };\n';
        const { text, inserted, skippedReason } = applySync(original, NEW_BLOCK);
        expect(text).toBe(original);
        expect(inserted).toBe(false);
        expect(skippedReason).toContain('defineConfig');
    });
    // User story: As a Quickback user whose config has nested parentheses inside provider calls
    // (preset functions, helper expressions, etc.), I need the closing-brace detection to find
    // the *outer* `})` of defineConfig and not stop at the first nested `)`.
    it('matches the outer closing `)` even when defineConfig contains nested calls', () => {
        const original = [
            'export default defineConfig({',
            '    name: "demo",',
            '    providers: cloudflare({ extras: foo({ bar: 1 }) }),',
            '    auth: { roleHierarchy: ["a", "b"] },',
            '});',
        ].join('\n');
        const { text, inserted } = applySync(original, NEW_BLOCK);
        expect(inserted).toBe(true);
        // Block should land before the final }) — there is exactly one
        expect(text.indexOf('// [quickback:options-start]')).toBeGreaterThan(text.indexOf('cloudflare('));
        expect(text.indexOf('// [quickback:options-end]')).toBeLessThan(text.indexOf('});'));
    });
    // User story: As a Quickback user, I need parens that appear inside string literals (e.g.
    // a regex-like default value or a Better Auth callback URL with `?redirect=(...)`) to be
    // ignored by the brace counter so the block lands at the real outer closing.
    it('ignores parens inside string literals when finding the outer closing', () => {
        const original = [
            'export default defineConfig({',
            '    name: "demo",',
            '    auth: { redirect: "/cb?next=(home)" },',
            '});',
        ].join('\n');
        const { text, inserted } = applySync(original, NEW_BLOCK);
        expect(inserted).toBe(true);
        // The string literal should not have been treated as a paren scope
        expect(text).toContain('"/cb?next=(home)"');
    });
    // User story: As a Quickback user, I need parens in line comments (e.g. JSDoc-style notes
    // describing example payloads) to be ignored so the block placement is not thrown off by
    // human-friendly commentary.
    it('ignores parens inside line comments when finding the outer closing', () => {
        const original = [
            'export default defineConfig({',
            '    name: "demo", // example: defineConfig(legacy)',
            '    providers: cloudflare({}),',
            '});',
        ].join('\n');
        const { text, inserted } = applySync(original, NEW_BLOCK);
        expect(inserted).toBe(true);
        expect(text).toContain('example: defineConfig(legacy)');
    });
});
//# sourceMappingURL=config-sync.test.js.map