const PromptProtocol = require('../../../../lib/core/resource/protocols/PromptProtocol')
const PackageProtocol = require('../../../../lib/core/resource/protocols/PackageProtocol')
const { QueryParams } = require('../../../../lib/core/resource/types')

describe('PromptProtocol', () => {
  let promptProtocol
  let mockPackageProtocol

  beforeEach(() => {
    promptProtocol = new PromptProtocol()

    // 创建模拟的 PackageProtocol
    mockPackageProtocol = {
      getPackageRoot: jest.fn().mockResolvedValue('/mock/package/root'),
      loadContent: jest.fn(),
      exists: jest.fn()
    }

    promptProtocol.setPackageProtocol(mockPackageProtocol)
  })

  afterEach(() => {
    promptProtocol.clearCache()
  })

  describe('基础功能', () => {
    test('应该正确初始化协议', () => {
      expect(promptProtocol.name).toBe('prompt')
      expect(promptProtocol.registry).toBeInstanceOf(Map)
      expect(promptProtocol.registry.size).toBeGreaterThan(0)
    })

    test('应该提供协议信息', () => {
      const info = promptProtocol.getProtocolInfo()

      expect(info.name).toBe('prompt')
      expect(info.description).toContain('PromptX内置提示词资源协议')
      expect(info.location).toBe('prompt://{resource_id}')
      expect(info.availableResources).toContain('protocols')
      expect(info.availableResources).toContain('core')
      expect(info.availableResources).toContain('domain')
      expect(info.availableResources).toContain('bootstrap')
    })

    test('应该设置包协议依赖', () => {
      const newMockPackage = { test: 'protocol' }
      promptProtocol.setPackageProtocol(newMockPackage)
      expect(promptProtocol.packageProtocol).toBe(newMockPackage)
    })

    test('应该提供支持的查询参数', () => {
      const params = promptProtocol.getSupportedParams()
      expect(params.merge).toContain('是否合并多个文件内容')
      expect(params.separator).toContain('文件间分隔符')
      expect(params.include_filename).toContain('是否包含文件名标题')
    })
  })

  describe('路径验证', () => {
    test('应该验证有效的资源路径', () => {
      expect(promptProtocol.validatePath('protocols')).toBe(true)
      expect(promptProtocol.validatePath('core')).toBe(true)
      expect(promptProtocol.validatePath('domain')).toBe(true)
      expect(promptProtocol.validatePath('bootstrap')).toBe(true)
    })

    test('应该拒绝无效的资源路径', () => {
      expect(promptProtocol.validatePath('invalid')).toBe(false)
      expect(promptProtocol.validatePath('unknown')).toBe(false)
      expect(promptProtocol.validatePath('')).toBe(false)
      expect(promptProtocol.validatePath(null)).toBe(false)
    })
  })

  describe('路径解析', () => {
    test('应该解析有效的资源路径', async () => {
      const resolved = await promptProtocol.resolvePath('protocols')
      expect(resolved).toBe('@package://prompt/protocol/**/*.md')
    })

    test('应该解析所有注册的资源', async () => {
      for (const resourceId of promptProtocol.registry.keys()) {
        const resolved = await promptProtocol.resolvePath(resourceId)
        expect(resolved).toMatch(/@package:\/\//)
      }
    })

    test('应该拒绝未注册的资源', async () => {
      await expect(promptProtocol.resolvePath('nonexistent'))
        .rejects.toThrow('未找到 prompt 资源: nonexistent')
    })
  })

  describe('单个文件加载', () => {
    test('应该加载单个文件', async () => {
      const mockContent = '# Test Content\n\nThis is test content.'
      mockPackageProtocol.loadContent.mockResolvedValue({
        content: mockContent,
        metadata: { path: '/test/path' }
      })

      const content = await promptProtocol.loadSingleFile('@package://bootstrap.md')

      expect(content).toBe(mockContent)
      expect(mockPackageProtocol.loadContent).toHaveBeenCalledWith('bootstrap.md', undefined)
    })

    test('应该处理加载错误', async () => {
      mockPackageProtocol.loadContent.mockRejectedValue(new Error('File not found'))

      await expect(promptProtocol.loadSingleFile('@package://nonexistent.md'))
        .rejects.toThrow('加载单个文件失败')
    })
  })

  describe('多个文件加载', () => {
    test('应该加载多个文件并合并', async () => {
      // 为这个测试使用真实的PackageProtocol
      const realPackageProtocol = new PackageProtocol()
      promptProtocol.setPackageProtocol(realPackageProtocol)
      
      const content = await promptProtocol.loadMultipleFiles('@package://prompt/protocol/**/*.md')

      expect(content).toContain('protocol')
      expect(content).toContain('prompt/protocol/')
      expect(typeof content).toBe('string')
      expect(content.length).toBeGreaterThan(0)
    })

    test('应该处理没有匹配文件的情况', async () => {
      const glob = require('glob')

      jest.doMock('glob', () => ({
        ...jest.requireActual('glob'),
        __esModule: true,
        default: jest.fn().mockImplementation((pattern, options, callback) => {
          if (typeof options === 'function') {
            callback = options
            options = {}
          }
          callback(null, []) // 返回空文件列表
        })
      }))

      await expect(promptProtocol.loadMultipleFiles('@package://prompt/nonexistent/**/*.md'))
        .rejects.toThrow('没有找到匹配的文件')
    })
  })

  describe('内容合并', () => {
    test('应该合并多个文件内容', () => {
      const contents = [
        { path: 'file1.md', content: '# File 1\n\nContent 1' },
        { path: 'file2.md', content: '# File 2\n\nContent 2' }
      ]

      const merged = promptProtocol.mergeContents(contents)

      expect(merged).toContain('# file1.md')
      expect(merged).toContain('# File 1')
      expect(merged).toContain('# file2.md')
      expect(merged).toContain('# File 2')
      expect(merged).toContain('---')
    })

    test('应该支持不合并返回JSON', () => {
      const contents = [
        { path: 'file1.md', content: 'Content 1' },
        { path: 'file2.md', content: 'Content 2' }
      ]

      const queryParams = new QueryParams()
      queryParams.set('merge', 'false')

      const result = promptProtocol.mergeContents(contents, queryParams)

      expect(() => JSON.parse(result)).not.toThrow()
      const parsed = JSON.parse(result)
      expect(parsed).toHaveLength(2)
      expect(parsed[0]).toHaveProperty('path', 'file1.md')
      expect(parsed[0]).toHaveProperty('content', 'Content 1')
    })

    test('应该支持自定义分隔符', () => {
      const contents = [
        { path: 'file1.md', content: 'Content 1' },
        { path: 'file2.md', content: 'Content 2' }
      ]

      const queryParams = new QueryParams()
      queryParams.set('separator', '\n\n===\n\n')

      const result = promptProtocol.mergeContents(contents, queryParams)

      expect(result).toContain('===')
      expect(result).not.toContain('---')
    })

    test('应该支持隐藏文件名', () => {
      const contents = [
        { path: 'file1.md', content: 'Content 1' }
      ]

      const queryParams = new QueryParams()
      queryParams.set('include_filename', 'false')

      const result = promptProtocol.mergeContents(contents, queryParams)

      expect(result).not.toContain('# file1.md')
      expect(result).toContain('Content 1')
    })
  })

  describe('资源存在性检查', () => {
    test('应该检查单个文件是否存在', async () => {
      mockPackageProtocol.exists.mockResolvedValue(true)

      const exists = await promptProtocol.exists('bootstrap')

      expect(exists).toBe(true)
      expect(mockPackageProtocol.exists).toHaveBeenCalledWith('bootstrap.md', undefined)
    })

    test('应该检查通配符文件是否存在', async () => {
      // 为这个测试使用真实的PackageProtocol
      const realPackageProtocol = new PackageProtocol()
      promptProtocol.setPackageProtocol(realPackageProtocol)
      
      const exists = await promptProtocol.exists('protocols')

      expect(exists).toBe(true)
    })

    test('应该处理不存在的资源', async () => {
      const exists = await promptProtocol.exists('nonexistent')

      expect(exists).toBe(false)
    })
  })

  describe('完整协议解析', () => {
    test('应该完整加载内容', async () => {
      mockPackageProtocol.loadContent.mockResolvedValue({
        content: '# Bootstrap Content\n\nThis is bootstrap.',
        metadata: {}
      })

      const content = await promptProtocol.loadContent('@package://bootstrap.md')

      expect(content).toBe('# Bootstrap Content\n\nThis is bootstrap.')
    })

    test('应该处理缺少依赖的情况', async () => {
      const newProtocol = new PromptProtocol()
      // 不设置 packageProtocol 依赖

      await expect(newProtocol.loadContent('@package://test.md'))
        .rejects.toThrow('PromptProtocol 需要 PackageProtocol 依赖')
    })
  })

  describe('工具方法', () => {
    test('应该列出所有可用资源', () => {
      const resources = promptProtocol.listResources()

      expect(resources).toBeInstanceOf(Array)
      expect(resources.length).toBeGreaterThan(0)

      const protocolsResource = resources.find(r => r.id === 'protocols')
      expect(protocolsResource).toBeDefined()
      expect(protocolsResource.description).toContain('DPML协议规范文档')
    })

    test('应该获取资源描述', () => {
      expect(promptProtocol.getResourceDescription('protocols')).toContain('DPML协议规范文档')
      expect(promptProtocol.getResourceDescription('core')).toContain('核心思维和执行模式')
      expect(promptProtocol.getResourceDescription('unknown')).toBe('未知资源')
    })
  })

  describe('缓存管理', () => {
    test('应该提供缓存统计', () => {
      const stats = promptProtocol.getCacheStats()
      expect(stats.protocol).toBe('prompt')
      expect(typeof stats.size).toBe('number')
      expect(typeof stats.enabled).toBe('boolean')
    })

    test('应该能清除缓存', () => {
      // 模拟一些缓存数据
      promptProtocol.cache.set('test', 'value')
      expect(promptProtocol.cache.size).toBeGreaterThan(0)

      promptProtocol.clearCache()
      expect(promptProtocol.cache.size).toBe(0)
    })
  })
})
