/**
 * Tests for settings-yaml-generator.ts
 *
 * This test suite validates the YAML generation logic for settings files,
 * including both runtime-saved settings and example file generation.
 */

import { generateSettingsYaml } from '../../src/config/settings-yaml-generator';
import type { YamlGeneratorOptions } from '../../src/config/settings-yaml-generator';
import type { UserSettings } from '../../src/types';
import * as yaml from 'js-yaml';

// Import actual default settings for testing
import { defaultSettings } from '../../src/config/default-settings';

describe('settings-yaml-generator', () => {
  describe('generateSettingsYaml', () => {
    describe('minimal settings', () => {
      test('should generate YAML with only shortcuts and window settings', () => {
        const minimalSettings: UserSettings = {
          shortcuts: {
            main: 'Cmd+Shift+Space',
            paste: 'Cmd+Enter',
            close: 'Escape',
            historyNext: 'Ctrl+j',
            historyPrev: 'Ctrl+k',
            search: 'Cmd+f'
          },
          window: {
            position: 'active-text-field',
            width: 600,
            height: 300
          }
        };

        const result = generateSettingsYaml(minimalSettings);

        expect(result).toContain('shortcuts:');
        expect(result).toContain('Cmd+Shift+Space: main');
        expect(result).toContain('Cmd+Enter: paste');
        expect(result).toContain('Escape: close');
        expect(result).toContain('Ctrl+j: historyNext');
        expect(result).toContain('Ctrl+k: historyPrev');
        expect(result).toContain('Cmd+f: search');

        expect(result).toContain('window:');
        expect(result).toContain('position: active-text-field');
        expect(result).toContain('width: 600');
        expect(result).toContain('height: 300');
      });

      test('should include commented templates when sections are missing', () => {
        const minimalSettings: UserSettings = {
          shortcuts: {
            main: 'Cmd+Shift+Space',
            paste: 'Cmd+Enter',
            close: 'Escape',
            historyNext: 'Ctrl+j',
            historyPrev: 'Ctrl+k',
            search: 'Cmd+f'
          },
          window: {
            position: 'center',
            width: 800,
            height: 400
          }
        };

        const result = generateSettingsYaml(minimalSettings);

        // Should have commented extensions section
        expect(result).toContain('#extensions:');
        expect(result).toContain('#  ts: "WebStorm"');

        // Deprecated sections should not appear when data is empty
        expect(result).not.toContain('# AGENT BUILT-IN');
        expect(result).not.toContain('# AGENT SKILLS');

        // Should have commented fileSearch and symbolSearch sections
        expect(result).toContain('#fileSearch:');
        expect(result).toContain('#symbolSearch:');
      });
    });

    describe('full settings with all sections', () => {
      test('should generate complete YAML with all sections populated', () => {
        const fullSettings: UserSettings = {
          shortcuts: {
            main: 'Alt+Space',
            paste: 'Enter',
            close: 'Escape',
            historyNext: 'Ctrl+j',
            historyPrev: 'Ctrl+k',
            search: 'Cmd+f'
          },
          window: {
            position: 'cursor',
            width: 700,
            height: 350
          },
          fileOpener: {
            defaultEditor: 'Visual Studio Code',
            extensions: {
              ts: 'WebStorm',
              go: 'Goland',
              md: 'Typora'
            }
          },
          agentBuiltIn: ['claude', 'codex'],
          agentSkills: [
            {
              name: 'test-{basename}',
              description: 'Test command',
              sourcePath: '~/.claude/test/*.md',
              argumentHint: 'Enter argument',
              maxSuggestions: 10
            }
          ],
          fileSearch: {
            respectGitignore: false,
            includeHidden: false,
            maxFiles: 1000,
            maxDepth: 5,
            maxSuggestions: 30,
            followSymlinks: true,
            fdPath: '/usr/local/bin/fd',
            includePatterns: ['*.log', 'dist/**'],
            excludePatterns: ['node_modules', '*.min.js']
          },
          symbolSearch: {
            maxSymbols: 10000,
            timeout: 3000,
            rgPath: '/opt/homebrew/bin/rg'
          },
          customSearch: [
            {
              name: 'agent-{basename}',
              description: 'Agent files',
              sourcePath: '~/.claude/agents/*.md',
              searchPrefix: 'agent',
              maxSuggestions: 20,
              orderBy: 'name',
              inputFormat: '{filepath}'
            }
          ]
        };

        const result = generateSettingsYaml(fullSettings);

        // Shortcuts (new format: key → action)
        expect(result).toContain('Alt+Space: main');
        expect(result).toContain('Enter: paste');

        // Window
        expect(result).toContain('position: cursor');
        expect(result).toContain('width: 700');
        expect(result).toContain('height: 350');

        // File opener
        expect(result).toContain('defaultEditor: "Visual Studio Code"');
        expect(result).toContain('ts: "WebStorm"');
        expect(result).toContain('go: "Goland"');
        expect(result).toContain('md: "Typora"');

        // Slash commands
        expect(result).toContain('- claude');
        expect(result).toContain('- codex');
        expect(result).toContain('name: "test-{basename}"');
        expect(result).toContain('description: "Test command"');
        expect(result).toContain('sourcePath: ~/.claude/test/*.md');
        expect(result).toContain('argumentHint: "Enter argument"');
        expect(result).toContain('maxSuggestions: 10');

        // Mentions - file search
        expect(result).toContain('respectGitignore: false');
        expect(result).toContain('includeHidden: false');
        expect(result).toContain('maxFiles: 1000');
        expect(result).toContain('maxDepth: 5');
        expect(result).toContain('followSymlinks: true');
        expect(result).toContain('fdPath: "/usr/local/bin/fd"');
        // Arrays with values are formatted as multi-line with proper indentation
        expect(result).toContain('includePatterns:');
        expect(result).toContain('- "*.log"');
        expect(result).toContain('- "dist/**"');
        expect(result).toContain('excludePatterns:');
        expect(result).toContain('- "node_modules"');
        expect(result).toContain('- "*.min.js"');

        // Mentions - symbol search
        expect(result).toContain('maxSymbols: 10000');
        expect(result).toContain('timeout: 3000');
        expect(result).toContain('rgPath: "/opt/homebrew/bin/rg"');

        // Mentions - customSearch
        expect(result).toContain('searchPrefix: agent');
        expect(result).toContain('orderBy: "name"');
        expect(result).toContain('inputFormat: {filepath}');
      });
    });

    describe('commented examples option', () => {
      test('should not include commented examples when includeCommentedExamples=false', () => {
        const settings = { ...defaultSettings };
        const options: YamlGeneratorOptions = { includeCommentedExamples: false };

        const result = generateSettingsYaml(settings, options);

        // Should not include commented extension examples
        expect(result).not.toContain('# go: "Goland"');

        // Should not include commented slash command examples
        expect(result).not.toContain('# - codex');
        expect(result).not.toContain('# - gemini');

        // Should not include commented customSearch examples
        expect(result).not.toContain('# - name: "{frontmatter@name}"');
        // Note: ~/.claude/plugins/cache is now an active value in default settings
      });

      test('should include commented examples when includeCommentedExamples=true', () => {
        const settings = { ...defaultSettings };
        const options: YamlGeneratorOptions = { includeCommentedExamples: true };

        const result = generateSettingsYaml(settings, options);

        // Should include commented extension examples
        expect(result).toContain('# go: "Goland"');
        expect(result).toContain('# md: "Typora"');

        // Deprecated sections should not appear when data is empty (even with commentedExamples)
        expect(result).not.toContain('# AGENT BUILT-IN');
      });

      test('should add commented examples after active values', () => {
        const settings: UserSettings = {
          ...defaultSettings,
          fileOpener: {
            extensions: {
              ts: 'WebStorm'
            },
            defaultEditor: null
          }
        };
        const options: YamlGeneratorOptions = { includeCommentedExamples: true };

        const result = generateSettingsYaml(settings, options);

        // Active value should come before commented examples
        const tsIndex = result.indexOf('ts: "WebStorm"');
        const goIndex = result.indexOf('# go: "Goland"');

        expect(tsIndex).toBeGreaterThan(0);
        expect(goIndex).toBeGreaterThan(tsIndex);
      });
    });

    describe('empty arrays and null values', () => {
      test('should handle empty arrays correctly', () => {
        const settings: UserSettings = {
          shortcuts: defaultSettings.shortcuts,
          window: defaultSettings.window,
          agentBuiltIn: [],
          agentSkills: [],
          fileSearch: {
            respectGitignore: true,
            includeHidden: true,
            maxFiles: 5000,
            maxDepth: null,
            maxSuggestions: 50,
            followSymlinks: false,
            includePatterns: [],
            excludePatterns: []
          },
          symbolSearch: {
            maxSymbols: 20000,
            timeout: 5000
          },
          customSearch: []
        };

        const result = generateSettingsYaml(settings);

        // Empty arrays should be formatted as []
        expect(result).toContain('includePatterns: []');
        expect(result).toContain('excludePatterns: []');
      });

      test('should handle null values correctly', () => {
        const settings: UserSettings = {
          shortcuts: defaultSettings.shortcuts,
          window: defaultSettings.window,
          fileOpener: {
            defaultEditor: null,
            extensions: {}
          },
          fileSearch: {
            respectGitignore: true,
            includeHidden: true,
            maxFiles: 5000,
            maxDepth: null,
            maxSuggestions: 50,
            followSymlinks: false,
            includePatterns: [],
            excludePatterns: []
          },
          symbolSearch: {
            maxSymbols: 20000,
            timeout: 5000
          }
        };

        const result = generateSettingsYaml(settings);

        // null values should be formatted as 'null'
        expect(result).toContain('defaultEditor: null');
        expect(result).toContain('maxDepth: null');
      });

      test('should handle custom tool paths as null when not set', () => {
        const settings: UserSettings = {
          shortcuts: defaultSettings.shortcuts,
          window: defaultSettings.window,
          fileSearch: {
            respectGitignore: true,
            includeHidden: true,
            maxFiles: 5000,
            maxDepth: null,
            maxSuggestions: 50,
            followSymlinks: false,
            includePatterns: [],
            excludePatterns: []
          },
          symbolSearch: {
            maxSymbols: 20000,
            timeout: 5000
          }
        };

        const result = generateSettingsYaml(settings);

        // Should have commented fdPath and rgPath when null
        expect(result).toContain('#fdPath: null');
        expect(result).toContain('#rgPath: null');
      });
    });

    describe('special characters in strings', () => {
      test('should properly quote strings with special characters', () => {
        const settings: UserSettings = {
          shortcuts: defaultSettings.shortcuts,
          window: defaultSettings.window,
          agentBuiltIn: ['claude'],
          agentSkills: [
            {
              name: 'test: command',
              description: 'Command with "quotes" and special chars',
              sourcePath: '~/path/with spaces/commands/*.md'
            }
          ]
        };

        const result = generateSettingsYaml(settings);

        // Strings with special characters should be quoted
        expect(result).toContain('name: "test: command"');
        expect(result).toContain('description: "Command with "quotes" and special chars"');
      });

      test('should handle empty strings', () => {
        const settings: UserSettings = {
          shortcuts: defaultSettings.shortcuts,
          window: defaultSettings.window,
          agentBuiltIn: ['claude'],
          agentSkills: [
            {
              name: 'test',
              description: '',
              sourcePath: '~/.claude/commands/*.md'
            }
          ]
        };

        const result = generateSettingsYaml(settings);

        expect(result).toContain('description: ""');
      });
    });

    describe('missing optional sections', () => {
      test('should handle missing fileOpener section', () => {
        const settings: UserSettings = {
          shortcuts: defaultSettings.shortcuts,
          window: defaultSettings.window
        };

        const result = generateSettingsYaml(settings);

        // Should have commented extensions section
        expect(result).toContain('#extensions:');
        expect(result).toContain('defaultEditor: null');
      });

      test('should handle missing agentSkills section', () => {
        const settings: UserSettings = {
          shortcuts: defaultSettings.shortcuts,
          window: defaultSettings.window
        };

        const result = generateSettingsYaml(settings);

        // Deprecated sections should not appear when data is empty
        expect(result).not.toContain('# AGENT BUILT-IN');
        expect(result).not.toContain('# AGENT SKILLS');
      });

      test('should handle missing fileSearch/symbolSearch/customSearch sections', () => {
        const settings: UserSettings = {
          shortcuts: defaultSettings.shortcuts,
          window: defaultSettings.window
        };

        const result = generateSettingsYaml(settings);

        // Should have commented fileSearch, symbolSearch templates
        expect(result).toContain('#fileSearch:');
        expect(result).toContain('#symbolSearch:');
        // customSearch is deprecated — should not appear when empty
        expect(result).not.toContain('# CUSTOM SEARCH');
      });

      test('should handle agentBuiltIn without agentSkills', () => {
        const settings: UserSettings = {
          shortcuts: defaultSettings.shortcuts,
          window: defaultSettings.window,
          agentBuiltIn: ['claude']
          // No agentSkills
        };

        const result = generateSettingsYaml(settings);

        // agentBuiltIn section should appear when data exists
        expect(result).toContain('agentBuiltIn:');
        expect(result).toContain('- claude');
        // agentSkills section should not appear when data is empty
        expect(result).not.toContain('# AGENT SKILLS');
      });
    });

    describe('YAML parsing integration', () => {
      test('should generate valid YAML that can be parsed by js-yaml', () => {
        const settings = { ...defaultSettings };
        const result = generateSettingsYaml(settings);

        // Remove comment-only lines and header for parsing
        const yamlContent = result
          .split('\n')
          .filter(line => !line.trim().startsWith('#') || line.includes(':'))
          .join('\n');

        // Should be parseable without errors
        expect(() => yaml.load(yamlContent)).not.toThrow();
      });

      test('should generate parseable YAML with all optional fields', () => {
        const settings: UserSettings = {
          shortcuts: {
            main: 'Alt+Space',
            paste: 'Enter',
            close: 'Escape',
            historyNext: 'Ctrl+j',
            historyPrev: 'Ctrl+k',
            search: 'Cmd+f'
          },
          window: {
            position: 'cursor',
            width: 800,
            height: 400
          },
          fileOpener: {
            defaultEditor: 'VSCode',
            extensions: {
              ts: 'WebStorm',
              md: 'Typora'
            }
          },
          agentBuiltIn: ['claude', 'codex'],
          agentSkills: [
            {
              name: '{basename}',
              description: 'Test',
              sourcePath: '~/.claude/commands/*.md',
              argumentHint: 'hint',
              maxSuggestions: 20
            }
          ],
          fileSearch: {
            respectGitignore: true,
            includeHidden: true,
            maxFiles: 5000,
            maxDepth: null,
            maxSuggestions: 50,
            followSymlinks: false,
            includePatterns: ['*.log'],
            excludePatterns: ['*.tmp']
          },
          symbolSearch: {
            maxSymbols: 20000,
            timeout: 5000
          },
          customSearch: [
            {
              name: 'agent-{basename}',
              description: 'Test agent',
              sourcePath: '~/.claude/agents/*.md',
              searchPrefix: 'agent'
            }
          ]
        };

        const result = generateSettingsYaml(settings);

        // Remove comment-only lines for parsing
        const yamlContent = result
          .split('\n')
          .filter(line => !line.trim().startsWith('#') || line.includes(':'))
          .join('\n');

        const parsed = yaml.load(yamlContent) as any;

        // Verify key sections are parsed correctly (new key→action format)
        expect(parsed.shortcuts['Alt+Space']).toBe('main');
        expect(parsed.window.position).toBe('cursor');
        expect(parsed.fileOpener.defaultEditor).toBe('VSCode');
        expect(parsed.agentBuiltIn).toEqual(['claude', 'codex']);
      });

      test('should preserve data types after round-trip parsing', () => {
        const settings: UserSettings = {
          shortcuts: defaultSettings.shortcuts,
          window: {
            position: 'center',
            width: 600,
            height: 300
          },
          fileSearch: {
            respectGitignore: true,
            includeHidden: false,
            maxFiles: 5000,
            maxDepth: null,
            maxSuggestions: 50,
            followSymlinks: false,
            includePatterns: [],
            excludePatterns: []
          },
          symbolSearch: {
            maxSymbols: 20000,
            timeout: 5000
          }
        };

        const result = generateSettingsYaml(settings);

        // Remove comment-only lines
        const yamlContent = result
          .split('\n')
          .filter(line => !line.trim().startsWith('#') || line.includes(':'))
          .join('\n');

        const parsed = yaml.load(yamlContent) as any;

        // Check data types
        expect(typeof parsed.window.width).toBe('number');
        expect(typeof parsed.window.height).toBe('number');
        expect(typeof parsed.fileSearch.respectGitignore).toBe('boolean');
        expect(typeof parsed.fileSearch.includeHidden).toBe('boolean');
        expect(parsed.fileSearch.maxDepth).toBeNull();
      });
    });

    describe('formatting and structure', () => {
      test('should include section headers and comments', () => {
        const settings = { ...defaultSettings };
        const result = generateSettingsYaml(settings);

        // Should include main header and docs link
        expect(result).toContain('# Prompt Line Settings');
        expect(result).toContain('# See:');

        // Should include section comments
        expect(result).toContain('# Window:');
        expect(result).toContain('# Shortcuts');
        expect(result).toContain('# Plugins');
        expect(result).toContain('# File opener');
        expect(result).toContain('# File search');
        expect(result).toContain('# Symbol search');
        // Deprecated sections should not appear with default (empty) settings
        expect(result).not.toContain('# AGENT BUILT-IN');
        expect(result).not.toContain('# AGENT SKILLS');
        expect(result).not.toContain('# CUSTOM SEARCH');
      });

      test('should have proper indentation for nested structures', () => {
        const settings: UserSettings = {
          shortcuts: defaultSettings.shortcuts,
          window: defaultSettings.window,
          agentBuiltIn: ['claude'],
          agentSkills: [
            {
              name: 'test',
              description: 'desc',
              sourcePath: '~/.claude/commands/*.md'
            }
          ]
        };

        const result = generateSettingsYaml(settings);

        // Check indentation patterns
        expect(result).toContain('agentBuiltIn:');
        expect(result).toContain('  - claude');
        expect(result).toContain('agentSkills:');
        expect(result).toContain('  - name: "test"');
        expect(result).toContain('    description: "desc"');
      });

      test('should include inline comments for important fields', () => {
        const settings: UserSettings = {
          shortcuts: defaultSettings.shortcuts,
          window: defaultSettings.window,
          fileSearch: {
            respectGitignore: true,
            includeHidden: true,
            maxFiles: 5000,
            maxDepth: null,
            maxSuggestions: 50,
            followSymlinks: false,
            includePatterns: [],
            excludePatterns: []
          },
          symbolSearch: {
            maxSymbols: 20000,
            timeout: 5000
          },
          customSearch: [
            {
              name: 'agent-{basename}',
              description: 'Test',
              sourcePath: '~/.claude/agents/*.md',
              searchPrefix: 'agent',
              inputFormat: '{filepath}'
            }
          ]
        };

        const result = generateSettingsYaml(settings);

        // Should include key fields
        expect(result).toContain('respectGitignore:');
        expect(result).toContain('includeHidden:');
        expect(result).toMatch(/searchPrefix: agent/);
        expect(result).toMatch(/inputFormat: \{filepath\}/);
      });
    });

    describe('customSearch entry formatting', () => {
      test('should format customSearch entries with all optional fields', () => {
        const settings: UserSettings = {
          shortcuts: defaultSettings.shortcuts,
          window: defaultSettings.window,
          fileSearch: {
            respectGitignore: true,
            includeHidden: true,
            maxFiles: 5000,
            maxDepth: null,
            maxSuggestions: 50,
            followSymlinks: false,
            includePatterns: [],
            excludePatterns: []
          },
          symbolSearch: {
            maxSymbols: 20000,
            timeout: 5000
          },
          customSearch: [
            {
              name: 'test-{basename}',
              description: 'Test description',
              sourcePath: '~/.test/path/**/*.md',
              searchPrefix: 'test',
              maxSuggestions: 100,
              orderBy: 'name desc',
              inputFormat: '{filepath}'
            }
          ]
        };

        const result = generateSettingsYaml(settings);

        expect(result).toContain('- name: "test-{basename}"');
        expect(result).toContain('description: "Test description"');
        expect(result).toContain('sourcePath: ~/.test/path/**/*.md');
        expect(result).toContain('searchPrefix: test');
        expect(result).toContain('maxSuggestions: 100');
        expect(result).toContain('orderBy: "name desc"');
        expect(result).toContain('inputFormat: {filepath}');
      });

      test('should format customSearch entries without optional fields', () => {
        const settings: UserSettings = {
          shortcuts: defaultSettings.shortcuts,
          window: defaultSettings.window,
          fileSearch: {
            respectGitignore: true,
            includeHidden: true,
            maxFiles: 5000,
            maxDepth: null,
            maxSuggestions: 50,
            followSymlinks: false,
            includePatterns: [],
            excludePatterns: []
          },
          symbolSearch: {
            maxSymbols: 20000,
            timeout: 5000
          },
          customSearch: [
            {
              name: 'simple',
              description: 'Simple entry',
              sourcePath: '~/.simple/*.md'
            }
          ]
        };

        const result = generateSettingsYaml(settings);

        expect(result).toContain('- name: "simple"');
        expect(result).toContain('description: "Simple entry"');
        expect(result).toContain('sourcePath: ~/.simple/*.md');

        // The result will still contain "searchPrefix:" in the commented help text
        // Verify that optional fields are not present in the entry by checking for
        // specific values that would only appear if the field was set
        const lines = result.split('\n');
        let inSimpleEntry = false;
        let simpleEntryLines: string[] = [];

        for (const line of lines) {
          if (line.includes('- name: "simple"')) {
            inSimpleEntry = true;
            simpleEntryLines.push(line);
          } else if (inSimpleEntry) {
            if (line.trim().startsWith('-') || line.trim() === '') {
              // Next entry or empty line - stop collecting
              break;
            }
            simpleEntryLines.push(line);
          }
        }

        const simpleEntryText = simpleEntryLines.join('\n');
        // Check that optional field values are not in the actual entry
        expect(simpleEntryText).not.toMatch(/searchPrefix:\s+\w+/);  // No actual searchPrefix value
        expect(simpleEntryText).not.toMatch(/maxSuggestions:\s+\d+/);  // No actual maxSuggestions value
        expect(simpleEntryText).not.toMatch(/orderBy:\s+/);  // No actual orderBy value
      });
    });

    describe('legacy field support', () => {
      test('should handle fileSearch field correctly', () => {
        const settings: UserSettings = {
          shortcuts: defaultSettings.shortcuts,
          window: defaultSettings.window,
          fileSearch: {
            respectGitignore: false,
            includeHidden: true,
            maxFiles: 3000,
            maxDepth: 3,
            maxSuggestions: 40,
            followSymlinks: true,
            includePatterns: [],
            excludePatterns: []
          }
        };

        const result = generateSettingsYaml(settings);

        // Should use fileSearch values for generation
        expect(result).toContain('respectGitignore: false');
        expect(result).toContain('maxFiles: 3000');
        expect(result).toContain('maxDepth: 3');
      });

      test('should use top-level fileSearch values', () => {
        const settings: UserSettings = {
          shortcuts: defaultSettings.shortcuts,
          window: defaultSettings.window,
          fileSearch: {
            respectGitignore: true,
            includeHidden: true,
            maxFiles: 5000,
            maxDepth: null,
            maxSuggestions: 50,
            followSymlinks: false,
            includePatterns: [],
            excludePatterns: []
          },
          symbolSearch: {
            maxSymbols: 20000,
            timeout: 5000
          }
        };

        const result = generateSettingsYaml(settings);

        // Should use top-level fileSearch values
        expect(result).toContain('respectGitignore: true');
        expect(result).toContain('maxFiles: 5000');
        expect(result).toContain('maxDepth: null');
      });
    });

    describe('formatValue edge cases', () => {
      test('should handle non-string array elements safely', () => {
        const consoleSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});
        // Create malformed settings with non-string array elements
        const malformedSettings: UserSettings = {
          shortcuts: defaultSettings.shortcuts,
          window: defaultSettings.window,
          fileSearch: {
            respectGitignore: true,
            includeHidden: true,
            maxFiles: 5000,
            maxDepth: null,
            maxSuggestions: 50,
            followSymlinks: false,
            // Array with non-string elements (numbers)
            includePatterns: [123, 456] as any,
            // Array with non-string elements (objects)
            excludePatterns: [{ key: 'value' }, { key2: 'value2' }] as any
          },
          symbolSearch: {
            maxSymbols: 20000,
            timeout: 5000
          }
        };

        // Should not throw and should return safe fallback
        const result = generateSettingsYaml(malformedSettings);

        // Should output '[]' for safety when non-string elements are detected
        expect(result).toContain('includePatterns: []');
        expect(result).toContain('excludePatterns: []');
        consoleSpy.mockRestore();
      });

      test('should handle unexpected value types safely', () => {
        const consoleSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});
        // Create malformed settings with unexpected value types
        const malformedSettings: UserSettings = {
          shortcuts: defaultSettings.shortcuts,
          window: defaultSettings.window,
          fileSearch: {
            respectGitignore: true,
            includeHidden: true,
            maxFiles: 5000,
            maxDepth: null,
            maxSuggestions: 50,
            // Function as value (unexpected type)
            followSymlinks: (() => true) as any,
            includePatterns: [],
            excludePatterns: []
          },
          symbolSearch: {
            maxSymbols: 20000,
            // Symbol as value (unexpected type)
            timeout: Symbol('timeout') as any
          }
        };

        // Should not throw and should return safe fallback
        const result = generateSettingsYaml(malformedSettings);

        // Should output 'null' for safety when unexpected types are detected
        expect(result).toContain('followSymlinks: null');
        expect(result).toContain('timeout: null');
        consoleSpy.mockRestore();
      });
    });

    describe('edge cases', () => {
      test('should handle very long extension lists', () => {
        const extensions: Record<string, string> = {};
        for (let i = 0; i < 20; i++) {
          extensions[`ext${i}`] = `App${i}`;
        }

        const settings: UserSettings = {
          shortcuts: defaultSettings.shortcuts,
          window: defaultSettings.window,
          fileOpener: {
            defaultEditor: null,
            extensions
          }
        };

        const result = generateSettingsYaml(settings);

        // Should contain all extensions
        expect(result).toContain('ext0: "App0"');
        expect(result).toContain('ext19: "App19"');
      });

      test('should handle multiple customSearch entries', () => {
        const customSearch = [
          {
            name: 'entry1',
            description: 'First entry',
            sourcePath: '~/.path1/*.md'
          },
          {
            name: 'entry2',
            description: 'Second entry',
            sourcePath: '~/.path2/**/*.md'
          },
          {
            name: 'entry3',
            description: 'Third entry',
            sourcePath: '~/.path3/test-*.md'
          }
        ];

        const settings: UserSettings = {
          shortcuts: defaultSettings.shortcuts,
          window: defaultSettings.window,
          fileSearch: {
            respectGitignore: true,
            includeHidden: true,
            maxFiles: 5000,
            maxDepth: null,
            maxSuggestions: 50,
            followSymlinks: false,
            includePatterns: [],
            excludePatterns: []
          },
          symbolSearch: {
            maxSymbols: 20000,
            timeout: 5000
          },
          customSearch
        };

        const result = generateSettingsYaml(settings);

        expect(result).toContain('name: "entry1"');
        expect(result).toContain('name: "entry2"');
        expect(result).toContain('name: "entry3"');
      });

      test('should handle boolean false values correctly', () => {
        const settings: UserSettings = {
          shortcuts: defaultSettings.shortcuts,
          window: defaultSettings.window,
          fileSearch: {
            respectGitignore: false,
            includeHidden: false,
            maxFiles: 5000,
            maxDepth: null,
            maxSuggestions: 50,
            followSymlinks: false,
            includePatterns: [],
            excludePatterns: []
          },
          symbolSearch: {
            maxSymbols: 20000,
            timeout: 5000
          }
        };

        const result = generateSettingsYaml(settings);

        // Boolean false should be formatted as 'false', not empty or null
        expect(result).toContain('respectGitignore: false');
        expect(result).toContain('includeHidden: false');
        expect(result).toContain('followSymlinks: false');
      });

      test('should handle numeric zero values correctly', () => {
        const settings: UserSettings = {
          shortcuts: defaultSettings.shortcuts,
          window: {
            position: 'center',
            width: 0,
            height: 0
          }
        };

        const result = generateSettingsYaml(settings);

        // Numeric zero should be formatted as '0', not null or empty
        expect(result).toContain('width: 0');
        expect(result).toContain('height: 0');
      });
    });
  });
});
