import { describe, it, expect, vi } from 'vitest';
import { BrowserResolver } from '../resolver.js';
import { VirtualFileSystem } from '../virtual-fs.js';

describe('BrowserResolver', () => {
  describe('resolve', () => {
    it('should resolve a simple file', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "test" syntax: "1.0.0" }`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('project.prs');

      expect(result.ast).not.toBeNull();
      expect(result.errors).toEqual([]);
      expect(result.sources).toContain('project.prs');
    });

    it('should normalize paths with backslashes', async () => {
      const fs = new VirtualFileSystem({
        'dir/project.prs': `@meta { id: "test" syntax: "1.0.0" }`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('dir\\project.prs');

      expect(result.ast).not.toBeNull();
      expect(result.sources).toContain('dir/project.prs');
    });

    it('should add .prs extension if missing', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "test" syntax: "1.0.0" }`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('project');

      expect(result.ast).not.toBeNull();
    });

    it('should remove leading slash from path', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "test" syntax: "1.0.0" }`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('/project.prs');

      expect(result.ast).not.toBeNull();
    });

    it('should return error for missing file', async () => {
      const fs = new VirtualFileSystem({});
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('missing.prs');

      expect(result.ast).toBeNull();
      expect(result.errors.length).toBeGreaterThan(0);
      expect(result.errors[0].message).toContain('not found');
    });

    it('should return errors for invalid syntax', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "broken`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('project.prs');

      expect(result.ast).toBeNull();
      expect(result.errors.length).toBeGreaterThan(0);
    });

    it('should use cache when enabled', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "test" syntax: "1.0.0" }`,
      });
      const resolver = new BrowserResolver({ fs, cache: true });

      const result1 = await resolver.resolve('project.prs');
      const result2 = await resolver.resolve('project.prs');

      expect(result1).toBe(result2);
    });

    it('should not use cache when disabled', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "test" syntax: "1.0.0" }`,
      });
      const resolver = new BrowserResolver({ fs, cache: false });

      const result1 = await resolver.resolve('project.prs');
      const result2 = await resolver.resolve('project.prs');

      expect(result1).not.toBe(result2);
      expect(result1).toEqual(result2);
    });

    it('should detect circular dependencies', async () => {
      const fs = new VirtualFileSystem({
        'a.prs': `@meta { id: "a" syntax: "1.0.0" }
@inherit ./b`,
        'b.prs': `@meta { id: "b" syntax: "1.0.0" }
@inherit ./a`,
      });
      const resolver = new BrowserResolver({ fs });

      await expect(resolver.resolve('a.prs')).rejects.toThrow('Circular');
    });

    it('should log debug messages with custom logger', async () => {
      const logger = {
        debug: vi.fn(),
        verbose: vi.fn(),
        info: vi.fn(),
        warn: vi.fn(),
        error: vi.fn(),
      };
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "test" syntax: "1.0.0" }`,
      });
      const resolver = new BrowserResolver({ fs, logger, cache: true });

      await resolver.resolve('project.prs');
      await resolver.resolve('project.prs'); // trigger cache hit

      expect(logger.verbose).toHaveBeenCalled();
      expect(logger.debug).toHaveBeenCalledWith(expect.stringContaining('Cache'));
    });
  });

  describe('clearCache', () => {
    it('should clear the resolution cache', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "test" syntax: "1.0.0" }`,
      });
      const resolver = new BrowserResolver({ fs, cache: true });

      const result1 = await resolver.resolve('project.prs');
      resolver.clearCache();
      const result2 = await resolver.resolve('project.prs');

      expect(result1).not.toBe(result2);
    });
  });

  describe('inheritance resolution', () => {
    it('should resolve @inherit with relative path', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "child" syntax: "1.0.0" }
@inherit ./base
@identity { """Child identity""" }`,
        'base.prs': `@meta { id: "parent" syntax: "1.0.0" }
@identity { """Base identity""" }`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('project.prs');

      expect(result.ast).not.toBeNull();
      expect(result.sources).toContain('project.prs');
      expect(result.sources).toContain('base.prs');
    });

    it('should resolve @inherit from nested directory', async () => {
      const fs = new VirtualFileSystem({
        'sub/project.prs': `@meta { id: "child" syntax: "1.0.0" }
@inherit ../base
@identity { """Child""" }`,
        'base.prs': `@meta { id: "parent" syntax: "1.0.0" }
@identity { """Base""" }`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('sub/project.prs');

      expect(result.ast).not.toBeNull();
      expect(result.sources).toContain('base.prs');
    });

    it('should resolve @inherit with registry path', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "test" syntax: "1.0.0" }
@inherit @core/base`,
        '@core/base.prs': `@meta { id: "core-base" syntax: "1.0.0" }
@identity { """Core base""" }`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('project.prs');

      expect(result.ast).not.toBeNull();
      expect(result.sources).toContain('@core/base.prs');
    });

    it('should merge @meta fields during inheritance', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "child" syntax: "1.0.0" description: "Child" }
@inherit ./base`,
        'base.prs': `@meta { id: "parent" syntax: "1.0.0" version: "2.0" }`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('project.prs');

      expect(result.ast?.meta?.fields).toMatchObject({
        id: 'child',
        description: 'Child',
        version: '2.0',
      });
    });

    it('should merge blocks during inheritance', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "child" syntax: "1.0.0" }
@inherit ./base
@context { environment: "production" }`,
        'base.prs': `@meta { id: "parent" syntax: "1.0.0" }
@context { environment: "development" }
@identity { """Base identity""" }`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('project.prs');

      expect(result.ast).not.toBeNull();
      const contextBlock = result.ast?.blocks.find((b) => b.name === 'context');
      expect(contextBlock).toBeDefined();
    });

    it('should handle inheritance error gracefully', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "child" syntax: "1.0.0" }
@inherit ./missing`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('project.prs');

      expect(result.errors.some((e) => e.message.includes('not found'))).toBe(true);
    });
  });

  describe('import resolution (@use)', () => {
    it('should resolve @use imports', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "main" syntax: "1.0.0" }
@use ./utils`,
        'utils.prs': `@meta { id: "utils" syntax: "1.0.0" }
@standards { code: ["TypeScript"] }`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('project.prs');

      expect(result.ast).not.toBeNull();
      expect(result.sources).toContain('utils.prs');
    });

    it('should resolve @use with alias', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "main" syntax: "1.0.0" }
@use ./utils as myUtils
@extend myUtils.standards { extra: "value" }`,
        'utils.prs': `@meta { id: "utils" syntax: "1.0.0" }
@standards { code: ["TypeScript"] }`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('project.prs');

      expect(result.ast).not.toBeNull();
      expect(result.sources).toContain('utils.prs');
      // Import markers are stripped after applying extends, but content should be merged
    });

    it('should merge blocks from imports', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "main" syntax: "1.0.0" }
@use ./standards
@standards { languages: ["JavaScript"] }`,
        'standards.prs': `@meta { id: "standards" syntax: "1.0.0" }
@standards { languages: ["TypeScript"] }`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('project.prs');

      expect(result.ast).not.toBeNull();
    });

    it('should handle multiple @use imports', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "main" syntax: "1.0.0" }
@use ./utils
@use ./standards`,
        'utils.prs': `@meta { id: "utils" syntax: "1.0.0" }
@tools { lint: { description: "Lint code" } }`,
        'standards.prs': `@meta { id: "standards" syntax: "1.0.0" }
@standards { code: ["Clean"] }`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('project.prs');

      expect(result.ast).not.toBeNull();
      expect(result.sources).toContain('utils.prs');
      expect(result.sources).toContain('standards.prs');
    });

    it('should handle import errors gracefully', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "main" syntax: "1.0.0" }
@use ./missing`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('project.prs');

      expect(result.errors.some((e) => e.message.includes('not found'))).toBe(true);
    });
  });

  describe('extension resolution (@extend)', () => {
    it('should apply @extend to existing block', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "test" syntax: "1.0.0" }
@standards { code: ["TypeScript"] }
@extend standards { testing: ["Vitest"] }`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('project.prs');

      expect(result.ast).not.toBeNull();
      const standardsBlock = result.ast?.blocks.find((b) => b.name === 'standards');
      expect(standardsBlock).toBeDefined();
    });

    it('should apply @extend to nested path', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "test" syntax: "1.0.0" }
@context { project: { name: "Test" } }
@extend context.project { version: "1.0" }`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('project.prs');

      expect(result.ast).not.toBeNull();
    });

    it('should extend text content by appending', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "test" syntax: "1.0.0" }
@identity { """Base identity.""" }
@extend identity { """Extended identity.""" }`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('project.prs');

      expect(result.ast).not.toBeNull();
      const identityBlock = result.ast?.blocks.find((b) => b.name === 'identity');
      if (identityBlock?.content.type === 'TextContent') {
        expect(identityBlock.content.value).toContain('Base identity');
        expect(identityBlock.content.value).toContain('Extended identity');
      }
    });

    it('should extend array content by concatenating', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "test" syntax: "1.0.0" }
@restrictions { - "Rule 1" }
@extend restrictions { - "Rule 2" }`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('project.prs');

      expect(result.ast).not.toBeNull();
    });

    it('should handle @extend for non-existent target gracefully', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "test" syntax: "1.0.0" }
@extend missing { content: "value" }`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('project.prs');

      // Should not throw, just skip the extension
      expect(result.ast).not.toBeNull();
    });

    it('should extend imported aliased blocks', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "main" syntax: "1.0.0" }
@use ./utils as tools
@extend tools.standards { extra: "value" }`,
        'utils.prs': `@meta { id: "utils" syntax: "1.0.0" }
@standards { code: ["TypeScript"] }`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('project.prs');

      expect(result.ast).not.toBeNull();
      // The aliased @extend must mutate the surviving (un-aliased) block,
      // not the `__import__tools.standards` copy that gets stripped at the
      // end of applyExtends. Otherwise the override silently disappears.
      const standardsBlock = result.ast?.blocks.find((b) => b.name === 'standards');
      expect(standardsBlock).toBeDefined();
      expect(result.ast?.blocks.some((b) => b.name.startsWith('__import__'))).toBe(false);
      if (standardsBlock?.content.type === 'ObjectContent') {
        expect(standardsBlock.content.properties).toMatchObject({ extra: 'value' });
      } else {
        throw new Error('expected ObjectContent for standards block');
      }
    });

    it('should overlay an aliased skill via @extend alias.skills.<name>', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "banking-review" syntax: "1.2.0" }
@use ./base-skill as base
@extend base.skills.code-review {
  description: "Banking-grade code review"
  references: ["./policies/pci-dss.md"]
  content: """Banking review steps"""
}`,
        'base-skill.prs': `@meta { id: "base-skill" syntax: "1.2.0" }
@skills {
  code-review: {
    description: "Generic code review"
    references: ["./standards/clean-code.md"]
    content: """Generic review steps"""
  }
}`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('project.prs');

      expect(result.ast).not.toBeNull();
      const skillsBlock = result.ast?.blocks.find((b) => b.name === 'skills');
      expect(skillsBlock).toBeDefined();
      if (skillsBlock?.content.type !== 'ObjectContent') {
        throw new Error('expected ObjectContent for skills block');
      }

      const codeReview = skillsBlock.content.properties['code-review'] as Record<string, unknown>;
      expect(codeReview).toBeDefined();

      // Replace strategy on description (primitive).
      expect(codeReview['description']).toBe('Banking-grade code review');

      // Append strategy on references — both base and overlay entries present.
      const refs = codeReview['references'];
      const refList = Array.isArray(refs)
        ? refs
        : ((refs as { type?: string; elements?: unknown[] })?.elements ?? []);
      const refStrings = (refList as unknown[]).map((r) => String(r));
      expect(refStrings).toContain('./policies/pci-dss.md');
      expect(refStrings).toContain('./standards/clean-code.md');

      // Replace strategy on TextContent content — banking wins, generic gone.
      const content = codeReview['content'];
      const contentValue =
        typeof content === 'string' ? content : ((content as { value?: string })?.value ?? '');
      expect(contentValue).toContain('Banking review steps');
      expect(contentValue).not.toContain('Generic review steps');
    });

    it('should preserve composedFrom and merge params/inputs via skill-aware merge', async () => {
      // Hits SKILL_PRESERVE_PROPERTIES (composedFrom skipped) and
      // SKILL_MERGE_PROPERTIES (params shallow-merged, overlay key wins).
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "p" syntax: "1.2.0" }
@skills {
  ops: {
    description: "base ops"
    params: { mode: "fast", retries: 3 }
    composedFrom: ["base.prs"]
  }
}
@extend skills.ops {
  description: "ops overlay"
  params: { mode: "safe", verbose: true }
  composedFrom: ["overlay-attempt.prs"]
}`,
      });
      const resolver = new BrowserResolver({ fs });
      const result = await resolver.resolve('project.prs');

      const skillsBlock = result.ast?.blocks.find((b) => b.name === 'skills');
      if (skillsBlock?.content.type !== 'ObjectContent') {
        throw new Error('expected ObjectContent for skills block');
      }
      const ops = skillsBlock.content.properties['ops'] as Record<string, unknown>;

      // Replace strategy.
      expect(ops['description']).toBe('ops overlay');

      // Shallow-merge strategy: overlay key wins, base-only key survives.
      expect(ops['params']).toMatchObject({ mode: 'safe', retries: 3, verbose: true });

      // Preserve strategy: composedFrom is never overwritten by @extend.
      const composed = ops['composedFrom'] as unknown[];
      expect(composed).toEqual(['base.prs']);
    });

    it('should support negation in append-strategy references with !-prefix', async () => {
      // Exercises processSkillAppend's negation path: `!entry` removes a base
      // reference, remaining entries append with deduplication.
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "p" syntax: "1.2.0" }
@skills {
  audit: {
    description: "audit"
    references: ["./standards/owasp-2017.md", "./standards/clean-code.md"]
  }
}
@extend skills.audit {
  references: ["!./standards/owasp-2017.md", "./standards/owasp-2024.md"]
}`,
      });
      const resolver = new BrowserResolver({ fs });
      const result = await resolver.resolve('project.prs');

      const skillsBlock = result.ast?.blocks.find((b) => b.name === 'skills');
      if (skillsBlock?.content.type !== 'ObjectContent') {
        throw new Error('expected ObjectContent for skills block');
      }
      const audit = skillsBlock.content.properties['audit'] as Record<string, unknown>;
      const refs = audit['references'] as unknown[];
      const refStrings = refs.map(String);

      expect(refStrings).not.toContain('./standards/owasp-2017.md');
      expect(refStrings).toContain('./standards/clean-code.md');
      expect(refStrings).toContain('./standards/owasp-2024.md');
    });

    it('should let overlay introduce params/inputs when the base skill omits them', async () => {
      // Hits the SKILL_MERGE_PROPERTIES deepClone fallback: base has no
      // `params`, overlay introduces it. Without the fallback the first-time
      // introduction would be lost.
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "p" syntax: "1.2.0" }
@skills {
  ops: { description: "ops" }
}
@extend skills.ops {
  params: { mode: "safe" }
}`,
      });
      const resolver = new BrowserResolver({ fs });
      const result = await resolver.resolve('project.prs');

      const skillsBlock = result.ast?.blocks.find((b) => b.name === 'skills');
      if (skillsBlock?.content.type !== 'ObjectContent') {
        throw new Error('expected ObjectContent for skills block');
      }
      const ops = skillsBlock.content.properties['ops'] as Record<string, unknown>;
      expect(ops['params']).toEqual({ mode: 'safe' });
    });

    it('should accept overlay-only references when the base skill omits them', async () => {
      // base has no `references` key → extractSkillElements(undefined) is null,
      // extElems is an array → mergeSkillValue takes the "else if extElems !== null"
      // branch (overlay wins, negations stripped).
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "p" syntax: "1.2.0" }
@skills {
  audit: { description: "audit" }
}
@extend skills.audit {
  references: ["./policies/pci-dss.md", "!./removed.md"]
}`,
      });
      const resolver = new BrowserResolver({ fs });
      const result = await resolver.resolve('project.prs');

      const skillsBlock = result.ast?.blocks.find((b) => b.name === 'skills');
      if (skillsBlock?.content.type !== 'ObjectContent') {
        throw new Error('expected ObjectContent for skills block');
      }
      const audit = skillsBlock.content.properties['audit'] as Record<string, unknown>;
      const refs = audit['references'] as unknown[];
      expect(refs).toEqual(['./policies/pci-dss.md']);
    });

    it('should fall back to deepClone for unknown skill properties whose base value is non-object', async () => {
      // metadata is unknown → unknown branch. Base value is a string (not an
      // object), so the deepMerge branch is skipped and the overlay wins
      // outright via deepClone.
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "p" syntax: "1.2.0" }
@skills {
  custom: {
    description: "base"
    metadata: "old-string"
  }
}
@extend skills.custom {
  metadata: { kind: "structured" }
}`,
      });
      const resolver = new BrowserResolver({ fs });
      const result = await resolver.resolve('project.prs');

      const skillsBlock = result.ast?.blocks.find((b) => b.name === 'skills');
      if (skillsBlock?.content.type !== 'ObjectContent') {
        throw new Error('expected ObjectContent for skills block');
      }
      const custom = skillsBlock.content.properties['custom'] as Record<string, unknown>;
      expect(custom['metadata']).toEqual({ kind: 'structured' });
    });

    it('should fall back to deepMerge for unknown skill properties', async () => {
      // Exercises the "unknown property" branch — properties not in any of
      // the REPLACE/APPEND/MERGE/PRESERVE sets fall through to deepMerge.
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "p" syntax: "1.2.0" }
@skills {
  custom: {
    description: "base"
    metadata: { kind: "old", owner: "team-a" }
  }
}
@extend skills.custom {
  metadata: { kind: "new", priority: 1 }
}`,
      });
      const resolver = new BrowserResolver({ fs });
      const result = await resolver.resolve('project.prs');

      const skillsBlock = result.ast?.blocks.find((b) => b.name === 'skills');
      if (skillsBlock?.content.type !== 'ObjectContent') {
        throw new Error('expected ObjectContent for skills block');
      }
      const custom = skillsBlock.content.properties['custom'] as Record<string, unknown>;

      // metadata isn't a known skill property → deepMerge: overlay wins per
      // key, base-only keys survive.
      expect(custom['metadata']).toMatchObject({ kind: 'new', owner: 'team-a', priority: 1 });
    });

    it('should apply skill-aware replace strategy on un-aliased @extend skills.<name>', async () => {
      // Lock in the parser's plain-Record shape for nested skill objects:
      // before this fix, mergeExtendValue routed everything through generic
      // deepMerge and concatenated TextContent properties (`content`).
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "p" syntax: "1.2.0" }
@skills {
  code-review: {
    description: "Generic review"
    references: ["./standards/clean-code.md"]
    content: """Generic body"""
  }
}
@extend skills.code-review {
  description: "Banking review"
  references: ["./policies/pci-dss.md"]
  content: """Banking body"""
}`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('project.prs');
      const skillsBlock = result.ast?.blocks.find((b) => b.name === 'skills');
      if (skillsBlock?.content.type !== 'ObjectContent') {
        throw new Error('expected ObjectContent for skills block');
      }
      const codeReview = skillsBlock.content.properties['code-review'] as Record<string, unknown>;

      expect(codeReview['description']).toBe('Banking review');

      const refs = codeReview['references'] as unknown[];
      const refStrings = refs.map((r) => (typeof r === 'string' ? r : String(r)));
      expect(refStrings).toContain('./standards/clean-code.md');
      expect(refStrings).toContain('./policies/pci-dss.md');

      const content = codeReview['content'];
      const contentValue =
        typeof content === 'string' ? content : ((content as { value?: string })?.value ?? '');
      expect(contentValue).toBe('Banking body');
      expect(contentValue).not.toContain('Generic body');
    });
  });

  describe('content merging', () => {
    it('should merge TextContent by appending when different', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "child" syntax: "1.0.0" }
@inherit ./base
@identity { """Child text""" }`,
        'base.prs': `@meta { id: "parent" syntax: "1.0.0" }
@identity { """Parent text""" }`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('project.prs');

      const identityBlock = result.ast?.blocks.find((b) => b.name === 'identity');
      if (identityBlock?.content.type === 'TextContent') {
        expect(identityBlock.content.value).toContain('Parent text');
        expect(identityBlock.content.value).toContain('Child text');
      }
    });

    it('should not duplicate identical TextContent', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "child" syntax: "1.0.0" }
@inherit ./base
@identity { """Same text""" }`,
        'base.prs': `@meta { id: "parent" syntax: "1.0.0" }
@identity { """Same text""" }`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('project.prs');

      const identityBlock = result.ast?.blocks.find((b) => b.name === 'identity');
      if (identityBlock?.content.type === 'TextContent') {
        // Should only appear once, not duplicated
        const matches = identityBlock.content.value.match(/Same text/g);
        expect(matches?.length).toBe(1);
      }
    });

    it('should use child text if it includes parent text', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "child" syntax: "1.0.0" }
@inherit ./base
@identity { """Parent text plus additional""" }`,
        'base.prs': `@meta { id: "parent" syntax: "1.0.0" }
@identity { """Parent text""" }`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('project.prs');

      const identityBlock = result.ast?.blocks.find((b) => b.name === 'identity');
      if (identityBlock?.content.type === 'TextContent') {
        expect(identityBlock.content.value).toBe('Parent text plus additional');
      }
    });

    it('should merge ObjectContent by deep merging properties', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "child" syntax: "1.0.0" }
@inherit ./base
@context { childKey: "childValue" }`,
        'base.prs': `@meta { id: "parent" syntax: "1.0.0" }
@context { parentKey: "parentValue" }`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('project.prs');

      const contextBlock = result.ast?.blocks.find((b) => b.name === 'context');
      if (contextBlock?.content.type === 'ObjectContent') {
        expect(contextBlock.content.properties).toHaveProperty('parentKey');
        expect(contextBlock.content.properties).toHaveProperty('childKey');
      }
    });

    it('should merge ArrayContent with unique values', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "child" syntax: "1.0.0" }
@inherit ./base
@restrictions { - "Rule B" - "Rule A" }`,
        'base.prs': `@meta { id: "parent" syntax: "1.0.0" }
@restrictions { - "Rule A" }`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('project.prs');

      const restrictionsBlock = result.ast?.blocks.find((b) => b.name === 'restrictions');
      if (restrictionsBlock?.content.type === 'ArrayContent') {
        // Should have unique elements only
        const elements = restrictionsBlock.content.elements;
        expect(elements.length).toBeLessThanOrEqual(2);
      }
    });

    it('should merge MixedContent combining text and properties', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "child" syntax: "1.0.0" }
@inherit ./base
@context {
  """Child context text"""
  childProp: "childValue"
}`,
        'base.prs': `@meta { id: "parent" syntax: "1.0.0" }
@context {
  """Parent context text"""
  parentProp: "parentValue"
}`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('project.prs');

      expect(result.ast).not.toBeNull();
    });

    it('should handle MixedContent merged with TextContent', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "child" syntax: "1.0.0" }
@inherit ./base
@context { """Just text""" }`,
        'base.prs': `@meta { id: "parent" syntax: "1.0.0" }
@context {
  """Mixed text"""
  key: "value"
}`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('project.prs');

      expect(result.ast).not.toBeNull();
    });

    it('should handle TextContent merged with MixedContent', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "child" syntax: "1.0.0" }
@inherit ./base
@context {
  """Mixed text"""
  key: "value"
}`,
        'base.prs': `@meta { id: "parent" syntax: "1.0.0" }
@context { """Just text""" }`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('project.prs');

      expect(result.ast).not.toBeNull();
    });

    it('should handle MixedContent merged with ObjectContent', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "child" syntax: "1.0.0" }
@inherit ./base
@context { childKey: "childValue" }`,
        'base.prs': `@meta { id: "parent" syntax: "1.0.0" }
@context {
  """Mixed text"""
  parentKey: "parentValue"
}`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('project.prs');

      expect(result.ast).not.toBeNull();
    });

    it('should handle ObjectContent merged with MixedContent', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "child" syntax: "1.0.0" }
@inherit ./base
@context {
  """Child text"""
  childKey: "childValue"
}`,
        'base.prs': `@meta { id: "parent" syntax: "1.0.0" }
@context { parentKey: "parentValue" }`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('project.prs');

      expect(result.ast).not.toBeNull();
    });
  });

  describe('path utilities', () => {
    it('should handle simple parent directory path', async () => {
      const fs = new VirtualFileSystem({
        'dir/project.prs': `@meta { id: "test" syntax: "1.0.0" }
@inherit ../base`,
        'base.prs': `@meta { id: "base" syntax: "1.0.0" }`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('dir/project.prs');

      expect(result.sources).toContain('base.prs');
    });

    it('should handle paths with multiple .. segments', async () => {
      const fs = new VirtualFileSystem({
        'a/b/project.prs': `@meta { id: "test" syntax: "1.0.0" }
@inherit ../base`,
        'a/base.prs': `@meta { id: "base" syntax: "1.0.0" }`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('a/b/project.prs');

      expect(result.sources).toContain('a/base.prs');
    });

    it('should handle registry paths with version', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "test" syntax: "1.0.0" }
@inherit @core/base@1.0.0`,
        '@core/base.prs': `@meta { id: "core-base" syntax: "1.0.0" }`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('project.prs');

      expect(result.ast).not.toBeNull();
    });

    it('should handle registry paths with nested segments', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "test" syntax: "1.0.0" }
@inherit @myorg/deep/nested/file`,
        '@myorg/deep/nested/file.prs': `@meta { id: "nested" syntax: "1.0.0" }`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('project.prs');

      expect(result.ast).not.toBeNull();
    });
  });

  describe('edge cases', () => {
    it('should handle file with only @meta', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "minimal" syntax: "1.0.0" }`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('project.prs');

      expect(result.ast).not.toBeNull();
      expect(result.ast?.blocks.length).toBe(0);
    });

    it('should handle inheritance without child meta', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "child" syntax: "1.0.0" }
@inherit ./base`,
        'base.prs': `@meta { id: "parent" syntax: "1.0.0" }
@identity { """Base""" }`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('project.prs');

      expect(result.ast).not.toBeNull();
      expect(result.ast?.inherit).toBeUndefined(); // inherit should be cleared
    });

    it('should handle imports with overlapping block names', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "main" syntax: "1.0.0" }
@use ./a
@use ./b
@standards { main: "value" }`,
        'a.prs': `@meta { id: "a" syntax: "1.0.0" }
@standards { a: "value" }`,
        'b.prs': `@meta { id: "b" syntax: "1.0.0" }
@standards { b: "value" }`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('project.prs');

      expect(result.ast).not.toBeNull();
    });

    it('should handle deep property merge in extensions', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "test" syntax: "1.0.0" }
@context {
  level1: {
    level2: {
      original: "value"
    }
  }
}
@extend context.level1.level2 { added: "newValue" }`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('project.prs');

      expect(result.ast).not.toBeNull();
    });

    it('should strip import markers from final output', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "main" syntax: "1.0.0" }
@use ./utils as myUtils`,
        'utils.prs': `@meta { id: "utils" syntax: "1.0.0" }
@tools { test: { description: "Test" } }`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('project.prs');

      // Import markers should not be in final blocks
      const hasImportMarker = result.ast?.blocks.some((b) => b.name.startsWith('__import__'));
      expect(hasImportMarker).toBe(false);
    });
  });

  describe('extension content merging', () => {
    it('should extend ObjectContent with TextContent to create MixedContent', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "test" syntax: "1.0.0" }
@context { key: "value" }
@extend context { """Added text""" }`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('project.prs');

      expect(result.ast).not.toBeNull();
      const contextBlock = result.ast?.blocks.find((b) => b.name === 'context');
      expect(contextBlock?.content.type).toBe('MixedContent');
    });

    it('should extend TextContent with ObjectContent to create MixedContent', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "test" syntax: "1.0.0" }
@identity { """Base text""" }
@extend identity { key: "value" }`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('project.prs');

      expect(result.ast).not.toBeNull();
      const identityBlock = result.ast?.blocks.find((b) => b.name === 'identity');
      expect(identityBlock?.content.type).toBe('MixedContent');
    });

    it('should extend MixedContent with TextContent', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "test" syntax: "1.0.0" }
@context {
  """Initial text"""
  key: "value"
}
@extend context { """More text""" }`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('project.prs');

      expect(result.ast).not.toBeNull();
    });

    it('should extend MixedContent with ObjectContent', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "test" syntax: "1.0.0" }
@context {
  """Some text"""
  existingKey: "existingValue"
}
@extend context { newKey: "newValue" }`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('project.prs');

      expect(result.ast).not.toBeNull();
      const contextBlock = result.ast?.blocks.find((b) => b.name === 'context');
      if (contextBlock?.content.type === 'MixedContent') {
        expect(contextBlock.content.properties).toHaveProperty('existingKey');
        expect(contextBlock.content.properties).toHaveProperty('newKey');
      }
    });

    it('should handle extension with incompatible types by using extension content', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "test" syntax: "1.0.0" }
@restrictions { - "Rule 1" }
@extend restrictions { """This replaces array with text""" }`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('project.prs');

      expect(result.ast).not.toBeNull();
    });

    it('should extend array value with ArrayContent', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "test" syntax: "1.0.0" }
@standards {
  languages: ["TypeScript", "JavaScript"]
}
@extend standards.languages { - "Python" }`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('project.prs');

      expect(result.ast).not.toBeNull();
    });

    it('should extend object value with ObjectContent', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "test" syntax: "1.0.0" }
@context {
  settings: {
    debug: true
  }
}
@extend context.settings { verbose: true }`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('project.prs');

      expect(result.ast).not.toBeNull();
    });

    it('should extend TextContent value with TextContent', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "test" syntax: "1.0.0" }
@context {
  description: {
    type: "TextContent"
    value: "Initial description"
  }
}`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('project.prs');

      expect(result.ast).not.toBeNull();
    });

    it('should create path when extending into non-existent nested path', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "test" syntax: "1.0.0" }
@context { existing: "value" }
@extend context.deep.nested.path { content: "new" }`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('project.prs');

      expect(result.ast).not.toBeNull();
    });

    it('should handle buildPathValue with empty path', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "test" syntax: "1.0.0" }
@context { key: "value" }
@extend context { anotherKey: "anotherValue" }`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('project.prs');

      expect(result.ast).not.toBeNull();
    });

    it('should handle MixedContent extension with text', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "test" syntax: "1.0.0" }
@inherit ./base
@context { childKey: "childValue" }`,
        'base.prs': `@meta { id: "parent" syntax: "1.0.0" }
@context {
  """Base context text"""
  parentKey: "parentValue"
}`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('project.prs');

      expect(result.ast).not.toBeNull();
    });
  });

  describe('value cloning', () => {
    it('should deep clone arrays recursively', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "test" syntax: "1.0.0" }
@standards {
  rules: [
    ["nested", "array"],
    { name: "object in array" }
  ]
}`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('project.prs');

      expect(result.ast).not.toBeNull();
    });

    it('should deep clone objects recursively', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "test" syntax: "1.0.0" }
@context {
  level1: {
    level2: {
      level3: "deep value"
    }
  }
}`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('project.prs');

      expect(result.ast).not.toBeNull();
    });

    it('should handle null values in cloning', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "test" syntax: "1.0.0" }
@context {
  value: null
}`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('project.prs');

      expect(result.ast).not.toBeNull();
    });
  });

  describe('properties merging', () => {
    it('should merge nested object properties', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "child" syntax: "1.0.0" }
@inherit ./base
@context {
  settings: {
    child: true
  }
}`,
        'base.prs': `@meta { id: "parent" syntax: "1.0.0" }
@context {
  settings: {
    parent: true
  }
}`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('project.prs');

      expect(result.ast).not.toBeNull();
      const contextBlock = result.ast?.blocks.find((b) => b.name === 'context');
      if (contextBlock?.content.type === 'ObjectContent') {
        const settings = contextBlock.content.properties.settings as Record<string, unknown>;
        expect(settings).toHaveProperty('parent');
        expect(settings).toHaveProperty('child');
      }
    });

    it('should override primitive values in properties', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "child" syntax: "1.0.0" }
@inherit ./base
@context { version: "2.0" }`,
        'base.prs': `@meta { id: "parent" syntax: "1.0.0" }
@context { version: "1.0" }`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('project.prs');

      expect(result.ast).not.toBeNull();
      const contextBlock = result.ast?.blocks.find((b) => b.name === 'context');
      if (contextBlock?.content.type === 'ObjectContent') {
        expect(contextBlock.content.properties.version).toBe('2.0');
      }
    });

    it('should add new properties from child', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "child" syntax: "1.0.0" }
@inherit ./base
@context { childOnly: "value" }`,
        'base.prs': `@meta { id: "parent" syntax: "1.0.0" }
@context { parentOnly: "value" }`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('project.prs');

      expect(result.ast).not.toBeNull();
      const contextBlock = result.ast?.blocks.find((b) => b.name === 'context');
      if (contextBlock?.content.type === 'ObjectContent') {
        expect(contextBlock.content.properties).toHaveProperty('parentOnly');
        expect(contextBlock.content.properties).toHaveProperty('childOnly');
      }
    });
  });

  describe('extend path handling', () => {
    it('should handle single-segment path extension', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "test" syntax: "1.0.0" }
@context { key: "value" }
@extend context { newKey: "newValue" }`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('project.prs');

      expect(result.ast).not.toBeNull();
    });

    it('should handle extending TextContent target', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "test" syntax: "1.0.0" }
@identity { """Original""" }
@extend identity { """Extended""" }`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('project.prs');

      const identityBlock = result.ast?.blocks.find((b) => b.name === 'identity');
      if (identityBlock?.content.type === 'TextContent') {
        expect(identityBlock.content.value).toContain('Original');
        expect(identityBlock.content.value).toContain('Extended');
      }
    });

    it('should handle extending into array element path', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "test" syntax: "1.0.0" }
@context { items: ["a", "b"] }
@extend context.items { - "c" }`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('project.prs');

      expect(result.ast).not.toBeNull();
    });
  });

  describe('MixedContent extension merging', () => {
    it('should merge MixedContent with MixedContent preserving both texts', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "test" syntax: "1.0.0" }
@context {
  """Target text"""
  targetKey: "targetValue"
}
@extend context {
  """Extension text"""
  extKey: "extValue"
}`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('project.prs');

      expect(result.ast).not.toBeNull();
      const contextBlock = result.ast?.blocks.find((b) => b.name === 'context');
      if (contextBlock?.content.type === 'MixedContent') {
        expect(contextBlock.content.text?.value).toContain('Target text');
        expect(contextBlock.content.text?.value).toContain('Extension text');
        expect(contextBlock.content.properties).toHaveProperty('targetKey');
        expect(contextBlock.content.properties).toHaveProperty('extKey');
      }
    });

    it('should handle MixedContent extension when target has no text', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "test" syntax: "1.0.0" }
@context { targetKey: "targetValue" }
@extend context {
  """Extension text"""
  extKey: "extValue"
}`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('project.prs');

      expect(result.ast).not.toBeNull();
    });

    it('should handle ArrayContent extension with ArrayContent', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "test" syntax: "1.0.0" }
@restrictions {
  - "Rule 1"
  - "Rule 2"
}
@extend restrictions {
  - "Rule 3"
  - "Rule 4"
}`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('project.prs');

      expect(result.ast).not.toBeNull();
      const restrictionsBlock = result.ast?.blocks.find((b) => b.name === 'restrictions');
      if (restrictionsBlock?.content.type === 'ArrayContent') {
        expect(restrictionsBlock.content.elements.length).toBeGreaterThanOrEqual(4);
      }
    });
  });

  describe('unique concat with complex values', () => {
    it('should handle arrays with object elements during inheritance', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "child" syntax: "1.0.0" }
@inherit ./base
@tools {
  childTool: {
    name: "childTool"
    description: "Child tool"
  }
}`,
        'base.prs': `@meta { id: "parent" syntax: "1.0.0" }
@tools {
  parentTool: {
    name: "parentTool"
    description: "Parent tool"
  }
}`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('project.prs');

      expect(result.ast).not.toBeNull();
    });

    it('should handle arrays with primitive duplicates', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "child" syntax: "1.0.0" }
@inherit ./base
@restrictions {
  - "Same rule"
  - "Child only rule"
}`,
        'base.prs': `@meta { id: "parent" syntax: "1.0.0" }
@restrictions {
  - "Same rule"
  - "Parent only rule"
}`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('project.prs');

      expect(result.ast).not.toBeNull();
      const restrictionsBlock = result.ast?.blocks.find((b) => b.name === 'restrictions');
      if (restrictionsBlock?.content.type === 'ArrayContent') {
        // "Same rule" should appear only once
        const values = restrictionsBlock.content.elements.filter((e) => e === 'Same rule');
        expect(values.length).toBeLessThanOrEqual(1);
      }
    });
  });

  describe('deep clone with nested structures', () => {
    it('should deep clone nested arrays', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "test" syntax: "1.0.0" }
@standards {
  matrix: [
    ["a", "b"],
    ["c", "d"]
  ]
}`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('project.prs');

      expect(result.ast).not.toBeNull();
    });

    it('should deep clone deeply nested objects', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "test" syntax: "1.0.0" }
@context {
  a: {
    b: {
      c: {
        d: "deep value"
      }
    }
  }
}`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('project.prs');

      expect(result.ast).not.toBeNull();
    });

    it('should handle mixed arrays and objects in cloning', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "test" syntax: "1.0.0" }
@standards {
  items: [
    { type: "object", value: 1 },
    ["nested", "array"],
    "plain string",
    123
  ]
}`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('project.prs');

      expect(result.ast).not.toBeNull();
    });
  });

  describe('isPlainObject type guard', () => {
    it('should handle objects during property merging', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "child" syntax: "1.0.0" }
@inherit ./base
@context {
  nested: {
    child: "value"
  }
}`,
        'base.prs': `@meta { id: "parent" syntax: "1.0.0" }
@context {
  nested: {
    parent: "value"
  }
}`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('project.prs');

      expect(result.ast).not.toBeNull();
      const contextBlock = result.ast?.blocks.find((b) => b.name === 'context');
      if (contextBlock?.content.type === 'ObjectContent') {
        const nested = contextBlock.content.properties.nested as Record<string, unknown>;
        expect(nested).toHaveProperty('parent');
        expect(nested).toHaveProperty('child');
      }
    });
  });

  describe('registry path version handling', () => {
    it('should strip version suffix from registry path', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "test" syntax: "1.0.0" }
@inherit @org/package@2.0.0`,
        '@org/package.prs': `@meta { id: "pkg" syntax: "1.0.0" }
@identity { """Package identity""" }`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('project.prs');

      expect(result.ast).not.toBeNull();
      expect(result.sources).toContain('@org/package.prs');
    });

    it('should handle registry path without version', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "test" syntax: "1.0.0" }
@inherit @simple/pkg`,
        '@simple/pkg.prs': `@meta { id: "simple" syntax: "1.0.0" }`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('project.prs');

      expect(result.ast).not.toBeNull();
    });
  });

  describe('text content merging edge cases', () => {
    it('should use parent text if child text is contained in parent', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "child" syntax: "1.0.0" }
@inherit ./base
@identity { """Base""" }`,
        'base.prs': `@meta { id: "parent" syntax: "1.0.0" }
@identity { """Base identity text""" }`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('project.prs');

      const identityBlock = result.ast?.blocks.find((b) => b.name === 'identity');
      if (identityBlock?.content.type === 'TextContent') {
        // Parent text contains child text, so parent should be used
        expect(identityBlock.content.value).toBe('Base identity text');
      }
    });

    it('should append child text when neither contains the other', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "child" syntax: "1.0.0" }
@inherit ./base
@identity { """Unique child content""" }`,
        'base.prs': `@meta { id: "parent" syntax: "1.0.0" }
@identity { """Different parent content""" }`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('project.prs');

      const identityBlock = result.ast?.blocks.find((b) => b.name === 'identity');
      if (identityBlock?.content.type === 'TextContent') {
        expect(identityBlock.content.value).toContain('parent content');
        expect(identityBlock.content.value).toContain('child content');
      }
    });
  });

  describe('MixedContent text merge edge cases', () => {
    it('should use extension text when target MixedContent has no text', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "test" syntax: "1.0.0" }
@inherit ./base
@context {
  """Child text"""
  childKey: "childValue"
}`,
        'base.prs': `@meta { id: "parent" syntax: "1.0.0" }
@context { parentKey: "parentValue" }`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('project.prs');

      expect(result.ast).not.toBeNull();
      const contextBlock = result.ast?.blocks.find((b) => b.name === 'context');
      if (contextBlock?.content.type === 'MixedContent') {
        expect(contextBlock.content.text?.value).toContain('Child text');
      }
    });

    it('should use target text when extension MixedContent has no text', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "test" syntax: "1.0.0" }
@inherit ./base
@context { childKey: "childValue" }`,
        'base.prs': `@meta { id: "parent" syntax: "1.0.0" }
@context {
  """Parent text"""
  parentKey: "parentValue"
}`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('project.prs');

      expect(result.ast).not.toBeNull();
      const contextBlock = result.ast?.blocks.find((b) => b.name === 'context');
      if (contextBlock?.content.type === 'MixedContent') {
        expect(contextBlock.content.text?.value).toContain('Parent text');
      }
    });
  });

  describe('extend to nested path with primitive value', () => {
    it('should replace primitive value at nested path', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "test" syntax: "1.0.0" }
@context {
  settings: {
    mode: "development"
  }
}
@extend context.settings.mode { value: "production" }`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('project.prs');

      expect(result.ast).not.toBeNull();
    });

    it('should handle extending deep path when intermediate is array', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "test" syntax: "1.0.0" }
@context {
  items: ["a", "b"]
}
@extend context.items.extra { value: "new" }`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('project.prs');

      expect(result.ast).not.toBeNull();
    });
  });

  describe('buildPathValue edge cases', () => {
    it('should build nested path structure from empty', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "test" syntax: "1.0.0" }
@context { existing: "value" }
@extend context.a.b.c.d { deep: "value" }`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('project.prs');

      expect(result.ast).not.toBeNull();
    });
  });

  describe('array value extension', () => {
    it('should convert array to ArrayContent when extending with array', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "test" syntax: "1.0.0" }
@standards {
  rules: ["rule1"]
}
@extend standards.rules { - "rule2" - "rule3" }`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('project.prs');

      expect(result.ast).not.toBeNull();
    });
  });

  describe('object merging with null values', () => {
    it('should handle null in parent being overwritten by child', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "child" syntax: "1.0.0" }
@inherit ./base
@context { value: "defined" }`,
        'base.prs': `@meta { id: "parent" syntax: "1.0.0" }
@context { value: null }`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('project.prs');

      expect(result.ast).not.toBeNull();
      const contextBlock = result.ast?.blocks.find((b) => b.name === 'context');
      if (contextBlock?.content.type === 'ObjectContent') {
        expect(contextBlock.content.properties.value).toBe('defined');
      }
    });
  });

  describe('extend with different content type combinations', () => {
    it('should handle ArrayContent extended with ObjectContent', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "test" syntax: "1.0.0" }
@restrictions { - "Rule 1" }
@extend restrictions { key: "converts to object" }`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('project.prs');

      expect(result.ast).not.toBeNull();
    });

    it('should handle TextContent extended with ArrayContent', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "test" syntax: "1.0.0" }
@identity { """Some text""" }
@extend identity { - "array item" }`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('project.prs');

      expect(result.ast).not.toBeNull();
    });
  });

  describe('multi-level inheritance', () => {
    it('should handle three levels of inheritance', async () => {
      const fs = new VirtualFileSystem({
        'child.prs': `@meta { id: "child" syntax: "1.0.0" }
@inherit ./parent
@identity { """Child level""" }`,
        'parent.prs': `@meta { id: "parent" syntax: "1.0.0" }
@inherit ./grandparent
@identity { """Parent level""" }`,
        'grandparent.prs': `@meta { id: "grandparent" syntax: "1.0.0" }
@identity { """Grandparent level""" }`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('child.prs');

      expect(result.ast).not.toBeNull();
      expect(result.sources).toContain('child.prs');
      expect(result.sources).toContain('parent.prs');
      expect(result.sources).toContain('grandparent.prs');
    });
  });

  describe('unique array concat with complex objects', () => {
    it('should not duplicate identical object values', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "child" syntax: "1.0.0" }
@inherit ./base
@tools {
  tool1: {
    name: "same"
    version: "1.0"
  }
}`,
        'base.prs': `@meta { id: "parent" syntax: "1.0.0" }
@tools {
  tool1: {
    name: "same"
    version: "1.0"
  }
}`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('project.prs');

      expect(result.ast).not.toBeNull();
    });
  });

  describe('mergeExtendValue edge cases', () => {
    it('should extend existing array value with ArrayContent', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "test" syntax: "1.0.0" }
@standards {
  languages: ["TypeScript", "JavaScript"]
}
@extend standards.languages { - "Python" - "Go" }`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('project.prs');

      expect(result.ast).not.toBeNull();
    });

    it('should extend existing object value with ObjectContent', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "test" syntax: "1.0.0" }
@context {
  config: {
    existingKey: "existingValue"
  }
}
@extend context.config { newKey: "newValue" }`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('project.prs');

      expect(result.ast).not.toBeNull();
      const contextBlock = result.ast?.blocks.find((b) => b.name === 'context');
      if (contextBlock?.content.type === 'ObjectContent') {
        const config = contextBlock.content.properties.config as Record<string, unknown>;
        expect(config).toHaveProperty('existingKey');
        expect(config).toHaveProperty('newKey');
      }
    });
  });

  describe('deepCloneValue edge cases', () => {
    it('should deep clone arrays within uniqueConcat', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "child" syntax: "1.0.0" }
@inherit ./base
@restrictions {
  - "child rule 1"
  - "child rule 2"
}`,
        'base.prs': `@meta { id: "parent" syntax: "1.0.0" }
@restrictions {
  - "parent rule 1"
  - "parent rule 2"
}`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('project.prs');

      expect(result.ast).not.toBeNull();
      const restrictionsBlock = result.ast?.blocks.find((b) => b.name === 'restrictions');
      expect(restrictionsBlock).toBeDefined();
      if (restrictionsBlock?.content.type === 'ArrayContent') {
        // Should have merged unique values from both
        expect(restrictionsBlock.content.elements.length).toBeGreaterThanOrEqual(4);
      }
    });
  });

  describe('mergeExtendContent additional branches', () => {
    it('should merge ArrayContent with ArrayContent in extensions', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "test" syntax: "1.0.0" }
@restrictions {
  - "original1"
  - "original2"
}
@extend restrictions {
  - "extended1"
  - "extended2"
}`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('project.prs');

      expect(result.ast).not.toBeNull();
      const block = result.ast?.blocks.find((b) => b.name === 'restrictions');
      if (block?.content.type === 'ArrayContent') {
        expect(block.content.elements.length).toBeGreaterThanOrEqual(4);
      }
    });

    it('should merge incompatible types by using extension content', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "test" syntax: "1.0.0" }
@restrictions {
  - "array item"
}
@extend restrictions { """text replaces array""" }`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('project.prs');

      expect(result.ast).not.toBeNull();
    });
  });

  describe('MixedContent with no text branches', () => {
    it('should handle extension MixedContent with only properties no text', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "test" syntax: "1.0.0" }
@context {
  """Target has text"""
  targetKey: "value"
}
@extend context { extKey: "extValue" }`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('project.prs');

      expect(result.ast).not.toBeNull();
      const contextBlock = result.ast?.blocks.find((b) => b.name === 'context');
      if (contextBlock?.content.type === 'MixedContent') {
        expect(contextBlock.content.text?.value).toContain('Target has text');
        expect(contextBlock.content.properties).toHaveProperty('extKey');
      }
    });
  });

  describe('path resolution edge cases', () => {
    it('should handle path without directory separator', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "test" syntax: "1.0.0" }
@inherit ./base`,
        'base.prs': `@meta { id: "base" syntax: "1.0.0" }`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('project.prs');

      expect(result.ast).not.toBeNull();
    });

    it('should handle non-registry path starting with @ but invalid format', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "test" syntax: "1.0.0" }
@inherit @invalid`,
        '@invalid.prs': `@meta { id: "invalid" syntax: "1.0.0" }`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('project.prs');

      // Invalid registry path format, normalized as regular path but file not found at that location
      expect(result.errors.length).toBeGreaterThan(0);
    });
  });

  describe('extend logging branch', () => {
    it('should log when applying extensions', async () => {
      const logger = {
        debug: vi.fn(),
        verbose: vi.fn(),
        info: vi.fn(),
        warn: vi.fn(),
        error: vi.fn(),
      };
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "test" syntax: "1.0.0" }
@context { key: "value" }
@extend context { another: "value" }`,
      });
      const resolver = new BrowserResolver({ fs, logger });

      await resolver.resolve('project.prs');

      expect(logger.debug).toHaveBeenCalledWith(expect.stringContaining('extension'));
    });
  });

  describe('MixedContent mergeAtPath branches', () => {
    it('should handle extending MixedContent block at property path', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "test" syntax: "1.0.0" }
@context {
  """Some context description"""
  settings: {
    debug: true
  }
}
@extend context.settings { verbose: true }`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('project.prs');

      expect(result.ast).not.toBeNull();
      const contextBlock = result.ast?.blocks.find((b) => b.name === 'context');
      if (contextBlock?.content.type === 'MixedContent') {
        const settings = contextBlock.content.properties.settings as Record<string, unknown>;
        expect(settings).toHaveProperty('debug');
        expect(settings).toHaveProperty('verbose');
      }
    });

    it('should handle extending MixedContent at deep nested path', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "test" syntax: "1.0.0" }
@context {
  """Description"""
  level1: {
    level2: {
      value: "original"
    }
  }
}
@extend context.level1.level2 { extra: "added" }`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('project.prs');

      expect(result.ast).not.toBeNull();
    });

    it('should build new path in MixedContent when property does not exist', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "test" syntax: "1.0.0" }
@context {
  """Description"""
  existing: "value"
}
@extend context.newPath.deep { content: "value" }`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('project.prs');

      expect(result.ast).not.toBeNull();
    });
  });

  describe('circular dependency in imports', () => {
    it('should detect circular dependency in @use imports', async () => {
      const fs = new VirtualFileSystem({
        'a.prs': `@meta { id: "a" syntax: "1.0.0" }
@use ./b`,
        'b.prs': `@meta { id: "b" syntax: "1.0.0" }
@use ./a`,
      });
      const resolver = new BrowserResolver({ fs });

      await expect(resolver.resolve('a.prs')).rejects.toThrow('Circular');
    });
  });

  describe('ArrayContent block merging', () => {
    it('should merge ArrayContent blocks during inheritance', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "child" syntax: "1.0.0" }
@inherit ./base
@restrictions {
  - "Child restriction"
}`,
        'base.prs': `@meta { id: "parent" syntax: "1.0.0" }
@restrictions {
  - "Parent restriction"
}`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('project.prs');

      expect(result.ast).not.toBeNull();
      const block = result.ast?.blocks.find((b) => b.name === 'restrictions');
      if (block?.content.type === 'ArrayContent') {
        expect(block.content.elements.length).toBe(2);
      }
    });
  });

  describe('child-only blocks in inheritance', () => {
    it('should include blocks only in child', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "child" syntax: "1.0.0" }
@inherit ./base
@childOnly { childContent: "value" }`,
        'base.prs': `@meta { id: "parent" syntax: "1.0.0" }
@parentOnly { parentContent: "value" }`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('project.prs');

      expect(result.ast).not.toBeNull();
      expect(result.ast?.blocks.some((b) => b.name === 'childOnly')).toBe(true);
      expect(result.ast?.blocks.some((b) => b.name === 'parentOnly')).toBe(true);
    });
  });

  describe('fallback content merging', () => {
    it('should use child content when types are incompatible during inheritance', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "child" syntax: "1.0.0" }
@inherit ./base
@example { """Child is text""" }`,
        'base.prs': `@meta { id: "parent" syntax: "1.0.0" }
@example {
  - "Parent is array"
}`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('project.prs');

      expect(result.ast).not.toBeNull();
    });
  });

  describe('mergeAtPathValue edge cases', () => {
    it('should build path when value is primitive', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "test" syntax: "1.0.0" }
@context {
  simpleString: "just a string"
}
@extend context.simpleString.deeper { content: "new" }`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('project.prs');

      expect(result.ast).not.toBeNull();
    });

    it('should merge at path when value is array', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "test" syntax: "1.0.0" }
@context {
  items: ["a", "b"]
}
@extend context.items.deeper { content: "new" }`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('project.prs');

      expect(result.ast).not.toBeNull();
    });
  });

  describe('extractValue branches', () => {
    it('should handle TextContent extraction', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "test" syntax: "1.0.0" }
@context { existing: "value" }
@extend context.newProp { """Text content to extract""" }`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('project.prs');

      expect(result.ast).not.toBeNull();
    });

    it('should handle ArrayContent extraction', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "test" syntax: "1.0.0" }
@context { existing: "value" }
@extend context.newArray { - "item1" - "item2" }`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('project.prs');

      expect(result.ast).not.toBeNull();
    });
  });

  describe('property cloning edge cases', () => {
    it('should clone new property values', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "child" syntax: "1.0.0" }
@inherit ./base
@context {
  childOnly: {
    nested: "value"
  }
}`,
        'base.prs': `@meta { id: "parent" syntax: "1.0.0" }
@context {
  parentOnly: "value"
}`,
      });
      const resolver = new BrowserResolver({ fs });

      const result = await resolver.resolve('project.prs');

      expect(result.ast).not.toBeNull();
      const contextBlock = result.ast?.blocks.find((b) => b.name === 'context');
      if (contextBlock?.content.type === 'ObjectContent') {
        expect(contextBlock.content.properties).toHaveProperty('childOnly');
        expect(contextBlock.content.properties).toHaveProperty('parentOnly');
      }
    });
  });

  describe('@use block filtering with reserved params', () => {
    it('should respect only: to keep listed blocks and drop others', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "test" syntax: "1.1.0" }
@use ./shared(only: ["standards", "restrictions"])`,
        'shared.prs': `@meta { id: "shared" syntax: "1.1.0" }
@identity { """Should be filtered out""" }
@standards { code: { language: "TypeScript" } }
@restrictions { - "No global state" }
@knowledge { """Should be filtered out""" }`,
      });

      const resolver = new BrowserResolver({ fs });
      const result = await resolver.resolve('project.prs');

      expect(result.errors).toEqual([]);
      const blockNames = result.ast?.blocks.map((b) => b.name) ?? [];
      expect(blockNames).toContain('standards');
      expect(blockNames).toContain('restrictions');
      expect(blockNames).not.toContain('identity');
      expect(blockNames).not.toContain('knowledge');
    });

    it('should respect exclude: to drop listed blocks and keep others', async () => {
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "test" syntax: "1.1.0" }
@use ./shared(exclude: ["knowledge"])`,
        'shared.prs': `@meta { id: "shared" syntax: "1.1.0" }
@standards { code: { language: "TypeScript" } }
@knowledge { """Should be filtered out""" }`,
      });

      const resolver = new BrowserResolver({ fs });
      const result = await resolver.resolve('project.prs');

      expect(result.errors).toEqual([]);
      const blockNames = result.ast?.blocks.map((b) => b.name) ?? [];
      expect(blockNames).toContain('standards');
      expect(blockNames).not.toContain('knowledge');
    });

    it('should not pass only/exclude into bindParams as template params', async () => {
      // Regression: previously the resolver passed only/exclude through to
      // bindParams, which threw "Unknown parameter 'only' for template …"
      // for any source file that didn't declare params.
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "test" syntax: "1.1.0" }
@use ./shared(only: ["standards"])`,
        'shared.prs': `@meta { id: "shared" syntax: "1.1.0" }
@standards { code: { language: "TypeScript" } }`,
      });

      const resolver = new BrowserResolver({ fs });
      const result = await resolver.resolve('project.prs');

      expect(result.errors).toEqual([]);
      expect(result.ast).not.toBeNull();
    });

    it('should still report bindParams errors for genuinely unknown template params', async () => {
      // Sanity: real template-parameter mistakes (i.e. non-reserved keys
      // against a source that declares params) must still surface as
      // ResolveError, not be silently dropped by the reserved-param split.
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "test" syntax: "1.1.0" }
@use ./shared(bogusParam: "value")`,
        'shared.prs': `@meta {
  id: "shared"
  syntax: "1.1.0"
  params: { knownParam: string = "default" }
}
@standards { code: { language: "TypeScript" } }`,
      });

      const resolver = new BrowserResolver({ fs });
      const result = await resolver.resolve('project.prs');

      expect(result.errors.length).toBeGreaterThan(0);
      expect(result.errors[0]?.message).toMatch(/bogusParam|parameter/i);
    });

    it('should bind template params when only reserved params are present and source declares params', async () => {
      // Covers the `remaining.length === 0` ternary branch in resolveImports:
      // source declares params (so bindParams must run), but the call site
      // only passes reserved params, so we forward `undefined` to bindParams.
      const fs = new VirtualFileSystem({
        'project.prs': `@meta { id: "test" syntax: "1.1.0" }
@use ./shared(only: ["standards"])`,
        'shared.prs': `@meta {
  id: "shared"
  syntax: "1.1.0"
  params: { greeting: string = "hello" }
}
@standards { code: { language: "TypeScript" } }`,
      });

      const resolver = new BrowserResolver({ fs });
      const result = await resolver.resolve('project.prs');

      expect(result.errors).toEqual([]);
      const blockNames = result.ast?.blocks.map((b) => b.name) ?? [];
      expect(blockNames).toContain('standards');
    });
  });
});
