import { describe, expect, it, beforeEach, vi, afterEach } from 'vitest';
import type { Program, SourceLocation } from '@promptscript/core';
import { AntigravityFormatter, ANTIGRAVITY_VERSIONS } from '../formatters/antigravity.js';

const createLoc = (): SourceLocation => ({
  file: 'test.prs',
  line: 1,
  column: 1,
});

const createMinimalProgram = (): Program => ({
  type: 'Program',
  uses: [],
  blocks: [],
  extends: [],
  loc: createLoc(),
  meta: {
    type: 'MetaBlock',
    fields: {
      id: 'test-project',
      syntax: '1.0.0',
    },
    loc: createLoc(),
  },
});

describe('AntigravityFormatter', () => {
  let formatter: AntigravityFormatter;

  beforeEach(() => {
    formatter = new AntigravityFormatter();
  });

  afterEach(() => {
    vi.restoreAllMocks();
  });

  it('should have correct name, outputPath and description', () => {
    expect(formatter.name).toBe('antigravity');
    expect(formatter.outputPath).toBe('.agent/rules/project.md');
    expect(formatter.description).toBe('Google Antigravity rules (Markdown)');
  });

  it('should have markdown as default convention', () => {
    expect(formatter.defaultConvention).toBe('markdown');
  });

  describe('getSupportedVersions', () => {
    it('should return supported versions', () => {
      const versions = AntigravityFormatter.getSupportedVersions();
      expect(versions).toBe(ANTIGRAVITY_VERSIONS);
      expect(versions.simple).toBeDefined();
      expect(versions.frontmatter).toBeDefined();
    });

    it('should have correct version metadata', () => {
      const versions = AntigravityFormatter.getSupportedVersions();
      expect(versions.simple.name).toBe('simple');
      expect(versions.simple.description).toBe('Plain Markdown without frontmatter');
      expect(versions.frontmatter.name).toBe('frontmatter');
      expect(versions.frontmatter.description).toBe(
        'Markdown with YAML frontmatter for activation'
      );
    });
  });

  describe('format', () => {
    it('should generate header with title', () => {
      const ast = createMinimalProgram();
      const result = formatter.format(ast);

      expect(result.path).toBe('.agent/rules/project.md');
      expect(result.content).toContain('# Project Rules');
    });

    it('should include identity section when present', () => {
      const ast: Program = {
        ...createMinimalProgram(),
        blocks: [
          {
            type: 'Block',
            name: 'identity',
            content: {
              type: 'TextContent',
              value: 'You are a TypeScript developer.',
              loc: createLoc(),
            },
            loc: createLoc(),
          },
        ],
      };

      const result = formatter.format(ast);
      expect(result.content).toContain('## Project Identity');
      expect(result.content).toContain('You are a TypeScript developer.');
    });

    it('should include tech stack from context block', () => {
      const ast: Program = {
        ...createMinimalProgram(),
        blocks: [
          {
            type: 'Block',
            name: 'context',
            content: {
              type: 'ObjectContent',
              properties: {
                languages: ['TypeScript', 'JavaScript'],
                runtime: 'Node.js 20+',
                monorepo: {
                  tool: 'Nx',
                  packageManager: 'pnpm',
                },
              },
              loc: createLoc(),
            },
            loc: createLoc(),
          },
        ],
      };

      const result = formatter.format(ast);
      expect(result.content).toContain('## Tech Stack');
      expect(result.content).toContain('**Languages:** TypeScript, JavaScript');
      expect(result.content).toContain('**Runtime:** Node.js 20+');
      expect(result.content).toContain('**Monorepo:** Nx with pnpm workspaces');
    });

    it('should include TypeScript standards from array format', () => {
      const ast: Program = {
        ...createMinimalProgram(),
        blocks: [
          {
            type: 'Block',
            name: 'standards',
            content: {
              type: 'ObjectContent',
              properties: {
                typescript: [
                  'Strict mode enabled',
                  'Never use `any` type - use `unknown` with type guards',
                  'Named exports only',
                ],
              },
              loc: createLoc(),
            },
            loc: createLoc(),
          },
        ],
      };

      const result = formatter.format(ast);
      expect(result.content).toContain('## Code Standards');
      expect(result.content).toContain('### TypeScript');
      expect(result.content).toContain('- Strict mode enabled');
      expect(result.content).toContain('- Never use `any` type - use `unknown` with type guards');
      expect(result.content).toContain('- Named exports only');
    });

    it('should include naming conventions from array format', () => {
      const ast: Program = {
        ...createMinimalProgram(),
        blocks: [
          {
            type: 'Block',
            name: 'standards',
            content: {
              type: 'ObjectContent',
              properties: {
                naming: [
                  'Files: `kebab-case.ts`',
                  'Classes: `PascalCase`',
                  'Functions: `camelCase`',
                ],
              },
              loc: createLoc(),
            },
            loc: createLoc(),
          },
        ],
      };

      const result = formatter.format(ast);
      expect(result.content).toContain('### Naming Conventions');
      expect(result.content).toContain('- Files: `kebab-case.ts`');
      expect(result.content).toContain('- Classes: `PascalCase`');
    });

    it('should include git commits from standards', () => {
      const ast: Program = {
        ...createMinimalProgram(),
        blocks: [
          {
            type: 'Block',
            name: 'standards',
            content: {
              type: 'ObjectContent',
              properties: {
                git: {
                  format: 'Conventional Commits',
                  maxSubjectLength: 72,
                  types: ['feat', 'fix', 'docs', 'refactor'],
                  example: 'feat(parser): add multiline string support',
                },
              },
              loc: createLoc(),
            },
            loc: createLoc(),
          },
        ],
      };

      const result = formatter.format(ast);
      expect(result.content).toContain('## Git Commits');
      expect(result.content).toContain('Conventional Commits');
      expect(result.content).toContain('max 72 characters');
      expect(result.content).toContain('`<type>(<scope>): <description>`');
      expect(result.content).toContain('`feat`, `fix`, `docs`, `refactor`');
      expect(result.content).toContain('feat(parser): add multiline string support');
    });

    it('should include config files from standards', () => {
      const ast: Program = {
        ...createMinimalProgram(),
        blocks: [
          {
            type: 'Block',
            name: 'standards',
            content: {
              type: 'ObjectContent',
              properties: {
                config: {
                  eslint: 'inherit from eslint.base.config.cjs',
                  viteRoot: '__dirname (not import.meta.dirname)',
                },
              },
              loc: createLoc(),
            },
            loc: createLoc(),
          },
        ],
      };

      const result = formatter.format(ast);
      expect(result.content).toContain('## Configuration Files');
      expect(result.content).toContain('### ESLint');
      expect(result.content).toContain('eslint.base.config.cjs');
      expect(result.content).toContain('### Vite/Vitest');
      // __dirname is escaped to \_\_dirname for Prettier compatibility
      expect(result.content).toContain('\\_\\_dirname');
    });

    it('should include testing standards from array format', () => {
      const ast: Program = {
        ...createMinimalProgram(),
        blocks: [
          {
            type: 'Block',
            name: 'standards',
            content: {
              type: 'ObjectContent',
              properties: {
                testing: [
                  'Framework: vitest',
                  'Test files: `*.spec.ts`',
                  'Follow Arrange-Act-Assert pattern',
                  'Target >90% coverage for libraries',
                ],
              },
              loc: createLoc(),
            },
            loc: createLoc(),
          },
        ],
      };

      const result = formatter.format(ast);
      expect(result.content).toContain('### Testing');
      expect(result.content).toContain('- Framework: vitest');
      expect(result.content).toContain('- Test files: `*.spec.ts`');
      expect(result.content).toContain('- Follow Arrange-Act-Assert pattern');
      expect(result.content).toContain('- Target >90% coverage for libraries');
    });

    it('should include error handling standards from array format', () => {
      const ast: Program = {
        ...createMinimalProgram(),
        blocks: [
          {
            type: 'Block',
            name: 'standards',
            content: {
              type: 'ObjectContent',
              properties: {
                errors: [
                  'Use custom error classes extending `BaseError`',
                  'Always include location information',
                  'Provide descriptive error messages',
                ],
              },
              loc: createLoc(),
            },
            loc: createLoc(),
          },
        ],
      };

      const result = formatter.format(ast);
      expect(result.content).toContain('### Error Handling');
      expect(result.content).toContain('- Use custom error classes extending `BaseError`');
      expect(result.content).toContain('- Always include location information');
      expect(result.content).toContain('- Provide descriptive error messages');
    });

    it('should include commands section from shortcuts', () => {
      const ast: Program = {
        ...createMinimalProgram(),
        blocks: [
          {
            type: 'Block',
            name: 'shortcuts',
            content: {
              type: 'ObjectContent',
              properties: {
                '/test': {
                  type: 'TextContent',
                  value: 'Run unit tests',
                  loc: createLoc(),
                },
                '/lint': {
                  type: 'TextContent',
                  value: 'Run linter',
                  loc: createLoc(),
                },
              },
              loc: createLoc(),
            },
            loc: createLoc(),
          },
        ],
      };

      const result = formatter.format(ast);
      expect(result.content).toContain('## Commands');
      expect(result.content).toContain('**/test**: Run unit tests');
      expect(result.content).toContain('**/lint**: Run linter');
    });

    it('should include development commands from knowledge block', () => {
      const ast: Program = {
        ...createMinimalProgram(),
        blocks: [
          {
            type: 'Block',
            name: 'knowledge',
            content: {
              type: 'TextContent',
              value: `## Development Commands

\`\`\`bash
pnpm install              # Install dependencies
pnpm nx build <pkg>       # Build package
pnpm nx test <pkg>        # Run tests
\`\`\``,
              loc: createLoc(),
            },
            loc: createLoc(),
          },
        ],
      };

      const result = formatter.format(ast);
      expect(result.content).toContain('## Development Commands');
      expect(result.content).toContain('pnpm install');
      expect(result.content).toContain('pnpm nx build');
    });

    it('should include post-work verification from knowledge block', () => {
      const ast: Program = {
        ...createMinimalProgram(),
        blocks: [
          {
            type: 'Block',
            name: 'knowledge',
            content: {
              type: 'TextContent',
              value: `## Post-Work Verification

\`\`\`bash
pnpm run format     # Format code
pnpm run lint       # Lint check
pnpm run test       # Run tests
\`\`\``,
              loc: createLoc(),
            },
            loc: createLoc(),
          },
        ],
      };

      const result = formatter.format(ast);
      expect(result.content).toContain('## Post-Work Verification');
      expect(result.content).toContain('pnpm run format');
      expect(result.content).toContain('After completing any code changes');
    });

    it('should include documentation from standards', () => {
      const ast: Program = {
        ...createMinimalProgram(),
        blocks: [
          {
            type: 'Block',
            name: 'standards',
            content: {
              type: 'ObjectContent',
              properties: {
                documentation: {
                  verifyBefore: true,
                  verifyAfter: true,
                  codeExamples: true,
                },
              },
              loc: createLoc(),
            },
            loc: createLoc(),
          },
        ],
      };

      const result = formatter.format(ast);
      expect(result.content).toContain('## Documentation');
      expect(result.content).toContain('**Before** making code changes');
      expect(result.content).toContain('**After** making code changes');
      expect(result.content).toContain('code examples in documentation');
    });

    it('should include diagrams from standards', () => {
      const ast: Program = {
        ...createMinimalProgram(),
        blocks: [
          {
            type: 'Block',
            name: 'standards',
            content: {
              type: 'ObjectContent',
              properties: {
                diagrams: {
                  format: 'Mermaid',
                  types: ['flowchart', 'sequence', 'class', 'ER'],
                },
              },
              loc: createLoc(),
            },
            loc: createLoc(),
          },
        ],
      };

      const result = formatter.format(ast);
      expect(result.content).toContain('## Diagrams');
      expect(result.content).toContain('**Mermaid**');
      expect(result.content).toContain('flowchart, sequence, class, ER');
      expect(result.content).toContain('```mermaid');
    });

    it('should include restrictions as donts', () => {
      const ast: Program = {
        ...createMinimalProgram(),
        blocks: [
          {
            type: 'Block',
            name: 'restrictions',
            content: {
              type: 'ArrayContent',
              elements: [
                'Never use any type',
                'Never use default exports',
                'Never commit without tests',
              ],
              loc: createLoc(),
            },
            loc: createLoc(),
          },
        ],
      };

      const result = formatter.format(ast);
      expect(result.content).toContain("## Don'ts");
      expect(result.content).toContain("Don't use any type");
      expect(result.content).toContain("Don't use default exports");
      expect(result.content).toContain("Don't commit without tests");
    });

    it('should include restrictions as text format', () => {
      const ast: Program = {
        ...createMinimalProgram(),
        blocks: [
          {
            type: 'Block',
            name: 'restrictions',
            content: {
              type: 'TextContent',
              value: `Never use any type
Never skip error handling
Never leave TODO without issue reference`,
              loc: createLoc(),
            },
            loc: createLoc(),
          },
        ],
      };

      const result = formatter.format(ast);
      expect(result.content).toContain("## Don'ts");
      expect(result.content).toContain("Don't use any type");
      expect(result.content).toContain("Don't skip error handling");
    });

    it('should respect outputPath override', () => {
      const ast = createMinimalProgram();
      const result = formatter.format(ast, {
        outputPath: '.agent/rules/custom.md',
      });

      expect(result.path).toBe('.agent/rules/custom.md');
    });

    it('should generate complete output with all sections', () => {
      const ast: Program = {
        ...createMinimalProgram(),
        blocks: [
          {
            type: 'Block',
            name: 'identity',
            content: {
              type: 'TextContent',
              value: 'Building a React application',
              loc: createLoc(),
            },
            loc: createLoc(),
          },
          {
            type: 'Block',
            name: 'context',
            content: {
              type: 'ObjectContent',
              properties: {
                languages: ['TypeScript'],
                runtime: 'Node.js 20+',
              },
              loc: createLoc(),
            },
            loc: createLoc(),
          },
          {
            type: 'Block',
            name: 'standards',
            content: {
              type: 'ObjectContent',
              properties: {
                typescript: ['Strict mode enabled'],
                naming: ['Files: `kebab-case.ts`'],
              },
              loc: createLoc(),
            },
            loc: createLoc(),
          },
          {
            type: 'Block',
            name: 'shortcuts',
            content: {
              type: 'ObjectContent',
              properties: {
                '/build': {
                  type: 'TextContent',
                  value: 'Build the project',
                  loc: createLoc(),
                },
              },
              loc: createLoc(),
            },
            loc: createLoc(),
          },
        ],
      };

      const result = formatter.format(ast);

      // Check all major sections are present
      expect(result.content).toContain('# Project Rules');
      expect(result.content).toContain('## Project Identity');
      expect(result.content).toContain('## Tech Stack');
      expect(result.content).toContain('## Code Standards');
      expect(result.content).toContain('## Commands');

      // Check content is properly formatted
      expect(result.content).toContain('Building a React application');
      expect(result.content).toContain('TypeScript');
      expect(result.content).toContain('**/build**');
    });
  });

  describe('version support', () => {
    it('should use simple version by default (no frontmatter)', () => {
      const ast = createMinimalProgram();
      const result = formatter.format(ast);

      expect(result.content).not.toMatch(/^---\n/);
      expect(result.content).toContain('# Project Rules');
    });

    it('should add frontmatter when version is frontmatter', () => {
      const ast: Program = {
        ...createMinimalProgram(),
        meta: {
          type: 'MetaBlock',
          fields: {
            id: 'test-project',
            syntax: '1.0.0',
            name: 'My Project',
          },
          loc: createLoc(),
        },
      };

      const result = formatter.format(ast, { version: 'frontmatter' });

      expect(result.content).toMatch(/^---\n/);
      expect(result.content).toContain('title: "My Project"');
      expect(result.content).toContain('activation: "always"');
      expect(result.content).toContain('description:');
      expect(result.content).toMatch(/---\n\n# Project Rules/);
    });

    it('should fallback to simple when unknown version specified', () => {
      const ast = createMinimalProgram();
      const result = formatter.format(ast, { version: 'unknown' });

      expect(result.content).not.toMatch(/^---\n/);
    });
  });

  describe('frontmatter generation', () => {
    it('should use meta name as title', () => {
      const ast: Program = {
        ...createMinimalProgram(),
        meta: {
          type: 'MetaBlock',
          fields: {
            id: 'test-project',
            syntax: '1.0.0',
            name: 'Awesome Project',
          },
          loc: createLoc(),
        },
      };

      const result = formatter.format(ast, { version: 'frontmatter' });
      expect(result.content).toContain('title: "Awesome Project"');
    });

    it('should use default title when no name in meta', () => {
      const ast = createMinimalProgram();
      const result = formatter.format(ast, { version: 'frontmatter' });
      expect(result.content).toContain('title: "Project Rules"');
    });

    it('should use meta description if available', () => {
      const ast: Program = {
        ...createMinimalProgram(),
        meta: {
          type: 'MetaBlock',
          fields: {
            id: 'test-project',
            syntax: '1.0.0',
            description: 'Custom description',
          },
          loc: createLoc(),
        },
      };

      const result = formatter.format(ast, { version: 'frontmatter' });
      expect(result.content).toContain('description: "Custom description"');
    });

    it('should extract description from identity block', () => {
      const ast: Program = {
        ...createMinimalProgram(),
        blocks: [
          {
            type: 'Block',
            name: 'identity',
            content: {
              type: 'TextContent',
              value: 'Building a fast API. With multiple features.',
              loc: createLoc(),
            },
            loc: createLoc(),
          },
        ],
      };

      const result = formatter.format(ast, { version: 'frontmatter' });
      expect(result.content).toContain('description: "Building a fast API"');
    });
  });

  describe('activation types', () => {
    it('should default to always activation', () => {
      const ast = createMinimalProgram();
      const result = formatter.format(ast, { version: 'frontmatter' });
      expect(result.content).toContain('activation: "always"');
    });

    it('should use glob activation when guards has globs', () => {
      const ast: Program = {
        ...createMinimalProgram(),
        blocks: [
          {
            type: 'Block',
            name: 'guards',
            content: {
              type: 'ObjectContent',
              properties: {
                globs: ['*.ts', '*.tsx'],
              },
              loc: createLoc(),
            },
            loc: createLoc(),
          },
        ],
      };

      const result = formatter.format(ast, { version: 'frontmatter' });
      expect(result.content).toContain('activation: "glob"');
    });

    it('should use glob activation when guards has files', () => {
      const ast: Program = {
        ...createMinimalProgram(),
        blocks: [
          {
            type: 'Block',
            name: 'guards',
            content: {
              type: 'ObjectContent',
              properties: {
                files: ['src/**/*.ts'],
              },
              loc: createLoc(),
            },
            loc: createLoc(),
          },
        ],
      };

      const result = formatter.format(ast, { version: 'frontmatter' });
      expect(result.content).toContain('activation: "glob"');
    });

    it('should emit globs field in frontmatter when activation is glob', () => {
      const ast: Program = {
        ...createMinimalProgram(),
        blocks: [
          {
            type: 'Block',
            name: 'guards',
            content: {
              type: 'ObjectContent',
              properties: { globs: ['*.ts', 'src/**/*.tsx'] },
              loc: createLoc(),
            },
            loc: createLoc(),
          },
        ],
      };

      const result = formatter.format(ast, { version: 'frontmatter' });
      expect(result.content).toContain('activation: "glob"');
      expect(result.content).toContain('globs: ["*.ts", "src/**/*.tsx"]');
    });

    it('should emit globs field from guards.files in frontmatter', () => {
      const ast: Program = {
        ...createMinimalProgram(),
        blocks: [
          {
            type: 'Block',
            name: 'guards',
            content: {
              type: 'ObjectContent',
              properties: { files: ['src/**/*.ts'] },
              loc: createLoc(),
            },
            loc: createLoc(),
          },
        ],
      };

      const result = formatter.format(ast, { version: 'frontmatter' });
      expect(result.content).toContain('activation: "glob"');
      expect(result.content).toContain('globs: ["src/**/*.ts"]');
    });

    it('should use model activation when guards.activation is model', () => {
      const ast: Program = {
        ...createMinimalProgram(),
        blocks: [
          {
            type: 'Block',
            name: 'guards',
            content: {
              type: 'ObjectContent',
              properties: { activation: 'model' },
              loc: createLoc(),
            },
            loc: createLoc(),
          },
        ],
      };

      const result = formatter.format(ast, { version: 'frontmatter' });
      expect(result.content).toContain('activation: "model"');
      expect(result.content).not.toContain('globs:');
    });

    it('should use manual activation when guards.activation is manual', () => {
      const ast: Program = {
        ...createMinimalProgram(),
        blocks: [
          {
            type: 'Block',
            name: 'guards',
            content: {
              type: 'ObjectContent',
              properties: { activation: 'manual' },
              loc: createLoc(),
            },
            loc: createLoc(),
          },
        ],
      };

      const result = formatter.format(ast, { version: 'frontmatter' });
      expect(result.content).toContain('activation: "manual"');
      expect(result.content).not.toContain('globs:');
    });
  });

  describe('character limit validation', () => {
    it('should warn when content exceeds 12000 characters', () => {
      const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});

      // Create a large content
      const longContent = 'x'.repeat(15000);
      const ast: Program = {
        ...createMinimalProgram(),
        blocks: [
          {
            type: 'Block',
            name: 'identity',
            content: {
              type: 'TextContent',
              value: longContent,
              loc: createLoc(),
            },
            loc: createLoc(),
          },
        ],
      };

      formatter.format(ast);

      expect(warnSpy).toHaveBeenCalled();
      // Use regex to match locale-independent format (12,000 or 12 000)
      expect(warnSpy.mock.calls[0]?.[0]).toMatch(/12[,\s]000 character limit/);
    });

    it('should not warn when content is under limit', () => {
      const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});

      const ast = createMinimalProgram();
      formatter.format(ast);

      expect(warnSpy).not.toHaveBeenCalled();
    });
  });

  describe('workflow support', () => {
    it('should generate workflow files for shortcuts with steps', () => {
      const ast: Program = {
        ...createMinimalProgram(),
        blocks: [
          {
            type: 'Block',
            name: 'shortcuts',
            content: {
              type: 'ObjectContent',
              properties: {
                '/deploy': {
                  description: 'Deploy to production',
                  steps: ['Run tests', 'Build project', 'Deploy'],
                },
              },
              loc: createLoc(),
            },
            loc: createLoc(),
          },
        ],
      };

      const result = formatter.format(ast);

      expect(result.additionalFiles).toBeDefined();
      expect(result.additionalFiles).toHaveLength(1);

      const workflow = result.additionalFiles?.[0];
      expect(workflow?.path).toBe('.agent/workflows/deploy.md');
      expect(workflow?.content).toContain('title: "Deploy"');
      expect(workflow?.content).toContain('description: "Deploy to production"');
      expect(workflow?.content).toContain('## Steps');
      expect(workflow?.content).toContain('1. Run tests');
      expect(workflow?.content).toContain('2. Build project');
      expect(workflow?.content).toContain('3. Deploy');
    });

    it('should generate workflow files using workflow key', () => {
      const ast: Program = {
        ...createMinimalProgram(),
        blocks: [
          {
            type: 'Block',
            name: 'shortcuts',
            content: {
              type: 'ObjectContent',
              properties: {
                '/review': {
                  desc: 'Code review workflow',
                  workflow: ['Check lint', 'Run tests', 'Review code'],
                },
              },
              loc: createLoc(),
            },
            loc: createLoc(),
          },
        ],
      };

      const result = formatter.format(ast);

      expect(result.additionalFiles).toBeDefined();
      const workflow = result.additionalFiles?.[0];
      expect(workflow?.path).toBe('.agent/workflows/review.md');
      expect(workflow?.content).toContain('1. Check lint');
    });

    it('should exclude workflow shortcuts from commands section', () => {
      const ast: Program = {
        ...createMinimalProgram(),
        blocks: [
          {
            type: 'Block',
            name: 'shortcuts',
            content: {
              type: 'ObjectContent',
              properties: {
                '/test': {
                  type: 'TextContent',
                  value: 'Run tests',
                  loc: createLoc(),
                },
                '/deploy': {
                  description: 'Deploy workflow',
                  steps: ['Step 1', 'Step 2'],
                },
              },
              loc: createLoc(),
            },
            loc: createLoc(),
          },
        ],
      };

      const result = formatter.format(ast);

      // Commands section should have /test but not /deploy
      expect(result.content).toContain('**/test**: Run tests');
      expect(result.content).not.toContain('**/deploy**');
    });

    it('should not generate workflow files for simple shortcuts', () => {
      const ast: Program = {
        ...createMinimalProgram(),
        blocks: [
          {
            type: 'Block',
            name: 'shortcuts',
            content: {
              type: 'ObjectContent',
              properties: {
                '/test': {
                  type: 'TextContent',
                  value: 'Run tests',
                  loc: createLoc(),
                },
              },
              loc: createLoc(),
            },
            loc: createLoc(),
          },
        ],
      };

      const result = formatter.format(ast);
      expect(result.additionalFiles).toBeUndefined();
    });

    it('should format workflow title from shortcut name', () => {
      const ast: Program = {
        ...createMinimalProgram(),
        blocks: [
          {
            type: 'Block',
            name: 'shortcuts',
            content: {
              type: 'ObjectContent',
              properties: {
                '/deploy-production': {
                  description: 'Deploy',
                  steps: ['Step 1'],
                },
              },
              loc: createLoc(),
            },
            loc: createLoc(),
          },
        ],
      };

      const result = formatter.format(ast);
      const workflow = result.additionalFiles?.[0];
      expect(workflow?.content).toContain('title: "Deploy Production"');
    });

    it('should handle steps as string format', () => {
      const ast: Program = {
        ...createMinimalProgram(),
        blocks: [
          {
            type: 'Block',
            name: 'shortcuts',
            content: {
              type: 'ObjectContent',
              properties: {
                '/build': {
                  description: 'Build workflow',
                  steps: '1. Compile\n2. Bundle\n3. Minify',
                },
              },
              loc: createLoc(),
            },
            loc: createLoc(),
          },
        ],
      };

      const result = formatter.format(ast);
      const workflow = result.additionalFiles?.[0];
      expect(workflow?.content).toContain('1. Compile');
      expect(workflow?.content).toContain('2. Bundle');
      expect(workflow?.content).toContain('3. Minify');
    });
  });

  describe('architecture section', () => {
    it('should extract architecture from context block', () => {
      const ast: Program = {
        ...createMinimalProgram(),
        blocks: [
          {
            type: 'Block',
            name: 'context',
            content: {
              type: 'TextContent',
              value: `## Architecture

\`\`\`mermaid
flowchart TB
  A --> B --> C
\`\`\``,
              loc: createLoc(),
            },
            loc: createLoc(),
          },
        ],
      };

      const result = formatter.format(ast);
      expect(result.content).toContain('## Architecture');
      expect(result.content).toContain('flowchart TB');
    });

    it('should fallback to architecture block if context has no architecture', () => {
      const ast: Program = {
        ...createMinimalProgram(),
        blocks: [
          {
            type: 'Block',
            name: 'architecture',
            content: {
              type: 'TextContent',
              value: 'Layered architecture with clean separation',
              loc: createLoc(),
            },
            loc: createLoc(),
          },
        ],
      };

      const result = formatter.format(ast);
      expect(result.content).toContain('## Architecture');
      expect(result.content).toContain('Layered architecture');
    });

    it('should extract architecture from context.architecture property with string value', () => {
      const ast: Program = {
        ...createMinimalProgram(),
        blocks: [
          {
            type: 'Block',
            name: 'context',
            content: {
              type: 'ObjectContent',
              properties: {
                architecture: 'Clean Architecture with domain-driven design',
              },
              loc: createLoc(),
            },
            loc: createLoc(),
          },
        ],
      };

      const result = formatter.format(ast);
      expect(result.content).toContain('## Architecture');
      expect(result.content).toContain('Clean Architecture with domain-driven design');
    });
  });

  describe('restrictions edge cases', () => {
    it('should return empty list when restrictions has ObjectContent without items', () => {
      const ast: Program = {
        ...createMinimalProgram(),
        blocks: [
          {
            type: 'Block',
            name: 'restrictions',
            content: {
              type: 'ObjectContent',
              properties: {
                severity: 'high',
                category: 'security',
              },
              loc: createLoc(),
            },
            loc: createLoc(),
          },
        ],
      };

      const result = formatter.format(ast);
      // Should not crash and restrictions section should not appear
      expect(result.content).not.toContain("## Don'ts");
    });
  });

  describe('output convention support', () => {
    it('should support markdown convention', () => {
      const ast = createMinimalProgram();
      expect(() => formatter.format(ast, { convention: 'markdown' })).not.toThrow();
    });

    it('should work with default convention', () => {
      const ast = createMinimalProgram();
      const result = formatter.format(ast);
      expect(result.content).toBeDefined();
      expect(result.content.length).toBeGreaterThan(0);
    });
  });
});
