import { describe, it, expect, beforeEach, afterEach } from 'vitest';
import path from 'node:path';
import { promises as fs } from 'node:fs';
import os from 'node:os';
import { hasMatchingAgentPath, extractAgentConfigOrTemplate, generateEmptyTemplate, autoFillPathInYml, loadYmlWithUpwardSearch, } from './yaml-utils.js';
describe('yaml-utils', () => {
    describe('hasMatchingAgentPath', () => {
        it('should return null for invalid YAML content', () => {
            expect(hasMatchingAgentPath('invalid yaml [[', 'test')).toBeNull();
        });
        it('should return null for empty content', () => {
            expect(hasMatchingAgentPath('', 'test')).toBeNull();
        });
        it('should return null when no agent key exists', () => {
            const yaml = `
other:
  - name: test
`;
            expect(hasMatchingAgentPath(yaml, 'test')).toBeNull();
        });
        it('should return null when agent is not an array', () => {
            const yaml = `
agent:
  name: single
`;
            expect(hasMatchingAgentPath(yaml, 'test')).toBeNull();
        });
        it('should return null when agent has no path', () => {
            const yaml = `
agent:
  - name: test
    description: no path
`;
            expect(hasMatchingAgentPath(yaml, 'test')).toBeNull();
        });
        it('should match exact path', () => {
            const yaml = `
agent:
  - name: test
    path: src/modules
`;
            expect(hasMatchingAgentPath(yaml, 'src/modules')).toBe('src/modules');
        });
        it('should match path with different separators (backslash)', () => {
            const yaml = `
agent:
  - name: test
    path: src/modules
`;
            expect(hasMatchingAgentPath(yaml, 'src\\modules')).toBe('src/modules');
        });
        it('should match path with forward slash when yaml has backslash', () => {
            const yaml = `
agent:
  - name: test
    path: src\\modules
`;
            expect(hasMatchingAgentPath(yaml, 'src/modules')).toBe('src\\modules');
        });
        it('should match current directory "." path', () => {
            const yaml = `
agent:
  - name: test
    path: .
`;
            expect(hasMatchingAgentPath(yaml, '.')).toBe('.');
        });
        it('should match empty path when target is "."', () => {
            const yaml = `
agent:
  - name: test
    path: ''
`;
            expect(hasMatchingAgentPath(yaml, '.')).toBe('');
        });
        it('should return null when no matching path found', () => {
            const yaml = `
agent:
  - name: test
    path: other/path
`;
            expect(hasMatchingAgentPath(yaml, 'different/path')).toBeNull();
        });
        it('should return first matching path from multiple agents', () => {
            const yaml = `
agent:
  - name: first
    path: first/path
  - name: second
    path: second/path
`;
            expect(hasMatchingAgentPath(yaml, 'first/path')).toBe('first/path');
            expect(hasMatchingAgentPath(yaml, 'second/path')).toBe('second/path');
        });
        it('should handle complex YAML with nested objects', () => {
            const yaml = `
agent:
  - name: complex
    path: complex/path
    project: my-project
    prompt: |
      This is a multi-line
      prompt
`;
            expect(hasMatchingAgentPath(yaml, 'complex/path')).toBe('complex/path');
        });
    });
    describe('extractAgentConfigOrTemplate', () => {
        it('should return original content for invalid YAML', () => {
            const invalidYaml = 'invalid: [[[';
            const result = extractAgentConfigOrTemplate(invalidYaml, 'test');
            expect(result.content).toBe(invalidYaml);
            expect(result.isTemplate).toBe(false);
        });
        it('should return matching agent config', () => {
            const yaml = `
agent:
  - name: my-agent
    path: src/modules
    project: my-project
    prompt: test prompt
`;
            const result = extractAgentConfigOrTemplate(yaml, 'src/modules');
            expect(result.isTemplate).toBe(false);
            expect(result.content).toContain('my-agent');
            expect(result.content).toContain('src/modules');
            expect(result.content).toContain('my-project');
        });
        it('should generate template when no matching agent found', () => {
            const yaml = `
agent:
  - name: other-agent
    path: other/path
    project: existing-project
`;
            const result = extractAgentConfigOrTemplate(yaml, 'new/path');
            expect(result.isTemplate).toBe(true);
            expect(result.projectFromSibling).toBe('existing-project');
            expect(result.content).toContain('new/path');
        });
        it('should generate template with empty project when no agents have project', () => {
            const yaml = `
agent:
  - name: agent1
    path: path1
`;
            const result = extractAgentConfigOrTemplate(yaml, 'new/path');
            expect(result.isTemplate).toBe(true);
            expect(result.projectFromSibling).toBeNull();
            expect(result.content).toContain('project: ""');
        });
        it('should match current directory "." path', () => {
            const yaml = `
agent:
  - name: root-agent
    path: .
    project: root-project
`;
            const result = extractAgentConfigOrTemplate(yaml, '.');
            expect(result.isTemplate).toBe(false);
            expect(result.content).toContain('root-agent');
        });
        it('should normalize path separators in output', () => {
            const yaml = `
agent:
  - name: test
    path: src\\modules
`;
            const result = extractAgentConfigOrTemplate(yaml, 'src/modules');
            expect(result.isTemplate).toBe(false);
            expect(result.content).toContain('src/modules');
        });
    });
    describe('generateEmptyTemplate', () => {
        it('should generate valid YAML with empty agent', () => {
            const template = generateEmptyTemplate('.');
            expect(template).toContain('agent:');
            expect(template).toContain('name: ""');
            expect(template).toContain('path: .');
            expect(template).toContain('project: ""');
        });
        it('should use normalized target path in generated template', () => {
            const template1 = generateEmptyTemplate('path1');
            const template2 = generateEmptyTemplate('path\\to\\child');
            expect(template1).toContain('path: path1');
            expect(template2).toContain('path: path/to/child');
        });
    });
    describe('autoFillPathInYml', () => {
        it('should return original content for invalid YAML', () => {
            const invalidYaml = 'invalid: [[[';
            expect(autoFillPathInYml(invalidYaml, 'test/path')).toBe(invalidYaml);
        });
        it('should return original content when no agent key', () => {
            const yaml = `
other:
  - name: test
`;
            expect(autoFillPathInYml(yaml, 'test/path')).toBe(yaml);
        });
        it('should fill empty path', () => {
            const yaml = `
agent:
  - name: test
    path: ''
    project: my-project
`;
            const result = autoFillPathInYml(yaml, 'new/path');
            expect(result).toContain('new/path');
            expect(result).not.toContain("path: ''");
        });
        it('should fill undefined path', () => {
            const yaml = `
agent:
  - name: test
    project: my-project
`;
            const result = autoFillPathInYml(yaml, 'new/path');
            expect(result).toContain('new/path');
        });
        it('should fill null path', () => {
            const yaml = `
agent:
  - name: test
    path: null
`;
            const result = autoFillPathInYml(yaml, 'new/path');
            expect(result).toContain('new/path');
        });
        it('should fill whitespace-only path', () => {
            const yaml = `
agent:
  - name: test
    path: '   '
`;
            const result = autoFillPathInYml(yaml, 'new/path');
            expect(result).toContain('new/path');
        });
        it('should not modify existing non-empty path', () => {
            const yaml = `
agent:
  - name: test
    path: existing/path
`;
            const result = autoFillPathInYml(yaml, 'new/path');
            expect(result).toContain('existing/path');
            expect(result).not.toContain('new/path');
        });
        it('should handle multiple agents', () => {
            const yaml = `
agent:
  - name: agent1
    path: ''
  - name: agent2
    path: existing/path
  - name: agent3
`;
            const result = autoFillPathInYml(yaml, 'new/path');
            // agent1 should have path filled
            expect(result).toContain('new/path');
        });
        it('should return original content when no modification needed', () => {
            const yaml = `
agent:
  - name: test
    path: existing/path
`;
            const result = autoFillPathInYml(yaml, 'new/path');
            expect(result).toBe(yaml);
        });
    });
    describe('loadYmlWithUpwardSearch', () => {
        const tempRoot = path.join(os.tmpdir(), `aws-yaml-test-${Date.now()}`);
        const workspacePath = path.join(tempRoot, 'project', 'module', 'src');
        const relativePath = '.agentswork/my.yml';
        beforeEach(async () => {
            // 创建目录结构
            await fs.mkdir(workspacePath, { recursive: true });
            await fs.mkdir(path.join(tempRoot, 'project', 'module', relativePath.split('/')[0]), {
                recursive: true,
            });
            await fs.mkdir(path.join(tempRoot, 'project', relativePath.split('/')[0]), {
                recursive: true,
            });
            await fs.mkdir(path.join(tempRoot, relativePath.split('/')[0]), { recursive: true });
        });
        afterEach(async () => {
            await fs.rm(tempRoot, { recursive: true, force: true });
        });
        it('should return null content when no config file exists', async () => {
            const result = await loadYmlWithUpwardSearch(workspacePath, relativePath);
            expect(result.content).toBeNull();
            expect(result.foundInParent).toBe(false);
            expect(result.matchedAgentPath).toBeNull();
        });
        it('should load config from workspace directory with matching path "."', async () => {
            const configPath = path.join(workspacePath, relativePath);
            await fs.mkdir(path.dirname(configPath), { recursive: true });
            await fs.writeFile(configPath, `
agent:
  - name: local-agent
    path: .
    project: local-project
`, 'utf-8');
            const result = await loadYmlWithUpwardSearch(workspacePath, relativePath);
            expect(result.content).not.toBeNull();
            expect(result.content).toContain('local-agent');
            expect(result.foundInParent).toBe(false);
            expect(result.matchedAgentPath).toBe('.');
        });
        it('should find matching config in parent directory', async () => {
            // 在 project/module 目录创建配置，匹配 src 路径
            const parentConfigPath = path.join(tempRoot, 'project', 'module', relativePath);
            await fs.mkdir(path.dirname(parentConfigPath), { recursive: true });
            await fs.writeFile(parentConfigPath, `
agent:
  - name: module-agent
    path: src
    project: module-project
`, 'utf-8');
            const result = await loadYmlWithUpwardSearch(workspacePath, relativePath);
            expect(result.content).not.toBeNull();
            expect(result.content).toContain('module-agent');
            expect(result.foundInParent).toBe(true);
            expect(result.matchedAgentPath).toBe('src');
        });
        it('should use last found config when no matching path', async () => {
            // 在 project/module 目录创建配置，但不匹配 src 路径
            const parentConfigPath = path.join(tempRoot, 'project', 'module', relativePath);
            await fs.mkdir(path.dirname(parentConfigPath), { recursive: true });
            await fs.writeFile(parentConfigPath, `
agent:
  - name: other-agent
    path: other/path
`, 'utf-8');
            const result = await loadYmlWithUpwardSearch(workspacePath, relativePath);
            expect(result.content).not.toBeNull();
            expect(result.content).toContain('other-agent');
            expect(result.matchedAgentPath).toBeNull();
        });
        it('should prioritize closer matching config', async () => {
            // 在 workspace 目录创建匹配的配置
            const localConfigPath = path.join(workspacePath, relativePath);
            await fs.mkdir(path.dirname(localConfigPath), { recursive: true });
            await fs.writeFile(localConfigPath, `
agent:
  - name: local-agent
    path: .
`, 'utf-8');
            // 在 parent 目录也创建配置
            const parentConfigPath = path.join(tempRoot, 'project', 'module', relativePath);
            await fs.writeFile(parentConfigPath, `
agent:
  - name: parent-agent
    path: src
`, 'utf-8');
            const result = await loadYmlWithUpwardSearch(workspacePath, relativePath);
            // 应该使用 local 的配置，因为更近且匹配
            expect(result.content).toContain('local-agent');
            expect(result.foundInParent).toBe(false);
        });
    });
});
