import { describe, it, expect } from 'vitest'
import { diagnoseVersionEntries, type VersionEntry } from '../cacheDoctor.js'

function entry(partial: Partial<VersionEntry> & { versionPath: string }): VersionEntry {
  return {
    marketplace: 'mp',
    plugin: 'p',
    versionId: 'v',
    hasClaudePlugin: true,
    hasSandcodePlugin: false,
    subdirs: [],
    ...partial,
  }
}

describe('diagnoseVersionEntries', () => {
  it('returns no issues for a healthy version dir', () => {
    const issues = diagnoseVersionEntries([
      entry({
        versionPath: 'mp/p/v',
        subdirs: ['agents', 'commands'],
      }),
    ])
    expect(issues).toEqual([])
  })

  it('flags missing manifest', () => {
    const issues = diagnoseVersionEntries([
      entry({
        versionPath: 'mp/p/v',
        hasClaudePlugin: false,
        hasSandcodePlugin: false,
      }),
    ])
    expect(issues).toHaveLength(1)
    expect(issues[0].kind).toBe('missing-manifest')
    expect(issues[0].path).toBe('mp/p/v')
  })

  it('accepts .sandcode-plugin manifest as valid', () => {
    const issues = diagnoseVersionEntries([
      entry({
        versionPath: 'mp/p/v',
        hasClaudePlugin: false,
        hasSandcodePlugin: true,
      }),
    ])
    expect(issues).toEqual([])
  })

  it('flags recursive plugin subdir (plugin name nested inside its own version)', () => {
    const issues = diagnoseVersionEntries([
      entry({
        versionPath: 'mp/accio-skills/1.0.0',
        plugin: 'accio-skills',
        subdirs: ['agents', 'accio-skills'],
      }),
    ])
    expect(issues).toHaveLength(1)
    expect(issues[0].kind).toBe('recursive-plugin-name')
    expect(issues[0].path).toBe('mp/accio-skills/1.0.0')
  })

  it('flags recursive marketplace subdir', () => {
    const issues = diagnoseVersionEntries([
      entry({
        versionPath: 'claude-plugins-official/p/v',
        marketplace: 'claude-plugins-official',
        subdirs: ['claude-plugins-official'],
      }),
    ])
    expect(issues).toHaveLength(1)
    expect(issues[0].kind).toBe('recursive-marketplace-name')
  })

  it('reports multiple issues across entries', () => {
    const issues = diagnoseVersionEntries([
      entry({
        versionPath: 'mp/a/v1',
        plugin: 'a',
        hasClaudePlugin: false,
        hasSandcodePlugin: false,
      }),
      entry({
        versionPath: 'mp/b/v1',
        plugin: 'b',
        subdirs: ['b'],
      }),
    ])
    expect(issues).toHaveLength(2)
    expect(issues.map((i) => i.kind).sort()).toEqual(['missing-manifest', 'recursive-plugin-name'])
  })

  it('does not flag .claude-plugin as a recursive subdir', () => {
    const issues = diagnoseVersionEntries([
      entry({
        versionPath: 'mp/.claude-plugin/v',
        plugin: '.claude-plugin',
        subdirs: ['.claude-plugin'],
      }),
    ])
    // Edge case: the plugin dir name is literally .claude-plugin — don't
    // flag it as recursive since .claude-plugin is a standard manifest marker.
    expect(issues.filter((i) => i.kind === 'recursive-plugin-name')).toEqual([])
  })
})
