import { describe, it, expect } from 'vitest'
import {
  licenseTierBadgeClass,
  commercialBadgeClass,
  groupUseCases,
  provenanceLabel,
  provenanceBadgeClass,
  splitByTier,
  severityBadgeClass,
  addresseeLabel,
  categorizeCorpusDoc,
  groupCorpusDocs,
  type UseCaseRow,
  type ControlItem,
  type CorpusDoc,
} from './_helpers'

const doc = (src: string, n = 1): CorpusDoc => ({
  source_regulation: src,
  license_rule: 1,
  license_tier: 't',
  atom_count: n,
  use_case: null,
})

const ctrl = (over: Partial<ControlItem>): ControlItem => ({
  id: 'id',
  title: 'T',
  relevant: true,
  tier: 'core',
  source_type: 'derived',
  applicable: true,
  is_gov: false,
  ...over,
})

const uc = (over: Partial<UseCaseRow>): UseCaseRow => ({
  key: 'x',
  label: 'X',
  group: 'security',
  regulations: [],
  verification_methods: [],
  mapped_controls: 0,
  atom_total: 0,
  atom_relevant: 0,
  ...over,
})

describe('coverage helpers', () => {
  it('license tier badge classes', () => {
    expect(licenseTierBadgeClass(1)).toContain('green')
    expect(licenseTierBadgeClass(2)).toContain('blue')
    expect(licenseTierBadgeClass(3)).toContain('amber')
    expect(licenseTierBadgeClass(null)).toContain('gray')
  })

  it('commercial-use badge classes', () => {
    expect(commercialBadgeClass('allowed')).toContain('green')
    expect(commercialBadgeClass('restricted')).toContain('amber')
    expect(commercialBadgeClass('prohibited')).toContain('red')
    expect(commercialBadgeClass(null)).toContain('gray')
  })

  it('groups use-cases in stable order and sorts by relevant desc', () => {
    const groups = groupUseCases([
      uc({ key: 'a', group: 'security', atom_relevant: 5 }),
      uc({ key: 'b', group: 'security', atom_relevant: 15 }),
      uc({ key: 'c', group: 'document', atom_relevant: 1 }),
    ])
    expect(groups[0].group).toBe('document')
    expect(groups[1].group).toBe('security')
    expect(groups[1].rows[0].key).toBe('b')
    expect(groups[1].rows[1].key).toBe('a')
  })

  it('appends unknown groups after the known order', () => {
    const groups = groupUseCases([
      uc({ key: 'z', group: 'mystery', atom_relevant: 9 }),
      uc({ key: 'd', group: 'document', atom_relevant: 2 }),
    ])
    expect(groups.map((g) => g.group)).toEqual(['document', 'mystery'])
  })

  it('provenance label: own library vs derived (with document + article)', () => {
    expect(provenanceLabel(ctrl({ source_type: 'own_library' }))).toBe(
      'Eigene Bibliothek',
    )
    expect(
      provenanceLabel(
        ctrl({ source_type: 'derived', source_regulation: 'DSGVO' }),
      ),
    ).toBe('Abgeleitet · DSGVO')
    expect(
      provenanceLabel(
        ctrl({
          source_type: 'derived',
          source_regulation: 'DSGVO',
          source_article: 'Art. 30',
        }),
      ),
    ).toBe('Abgeleitet · DSGVO Art. 30')
    // derived but no document known → graceful fallback
    expect(provenanceLabel(ctrl({ source_type: 'derived' }))).toBe('Abgeleitet')
  })

  it('provenance + severity badge classes', () => {
    expect(provenanceBadgeClass('own_library')).toContain('amber')
    expect(provenanceBadgeClass('derived')).toContain('blue')
    expect(severityBadgeClass('critical')).toContain('red')
    expect(severityBadgeClass('high')).toContain('orange')
    expect(severityBadgeClass(null)).toContain('gray')
  })

  it('addressee label maps keys to German labels', () => {
    expect(addresseeLabel('oeffentliche_stelle')).toBe('Öffentliche Stelle')
    expect(addresseeLabel('aufsichtsbefugnis')).toBe('Aufsichtsbehörde')
    expect(addresseeLabel('staat_eu')).toBe('Mitgliedstaat/EU')
    expect(addresseeLabel(null)).toBe('')
    expect(addresseeLabel('unbekannt_neu')).toBe('unbekannt_neu')
  })

  it('categorizes corpus docs by type + issuer family', () => {
    expect(categorizeCorpusDoc('DSGVO (EU) 2016/679').cat.key).toBe('law')
    expect(categorizeCorpusDoc('Medizinprodukteverordnung (EU) 2017/745 (MDR)').cat.key).toBe('law')
    expect(categorizeCorpusDoc('DSK OH Telemedien')).toMatchObject({
      cat: { key: 'guidance' },
      family: 'DSK (Datenschutzkonferenz)',
    })
    expect(categorizeCorpusDoc('EDPB Fines Calculation')).toMatchObject({
      cat: { key: 'guidance' },
      family: 'EDPB',
    })
    expect(categorizeCorpusDoc('OWASP Top 10 (2021)')).toMatchObject({
      cat: { key: 'standard' },
      family: 'OWASP',
    })
    expect(categorizeCorpusDoc('NIST SP 800-53 Rev. 5').family).toBe('NIST')
    expect(categorizeCorpusDoc('ENISA NIS2 Security Measures').family).toBe('ENISA')
    expect(categorizeCorpusDoc('BGH I ZR 7/16').cat.key).toBe('court')
  })

  it('groups corpus docs: laws → guidance → standards → court, families clustered', () => {
    const groups = groupCorpusDocs([
      doc('OWASP Top 10', 10),
      doc('DSGVO (EU) 2016/679', 50),
      doc('DSK OH Telemedien', 5),
      doc('EDPB Fines', 8),
      doc('NIST SP 800-53', 20),
      doc('DSK OH Direktwerbung', 3),
      doc('BGH I ZR 7/16', 1),
    ])
    expect(groups.map((g) => g.key)).toEqual(['law', 'guidance', 'standard', 'court'])
    const guidance = groups.find((g) => g.key === 'guidance')!
    // two DSK docs collapse into one family
    const dsk = guidance.families.find((f) => f.family.startsWith('DSK'))!
    expect(dsk.docs.length).toBe(2)
    const std = groups.find((g) => g.key === 'standard')!
    // NIST (20) before OWASP (10) — families sorted by size desc
    expect(std.families.map((f) => f.family)).toEqual(['NIST', 'OWASP'])
  })

  it('splitByTier separates core (relevant) from review', () => {
    const { core, review } = splitByTier([
      ctrl({ id: 'a', relevant: true }),
      ctrl({ id: 'b', relevant: false, tier: 'review' }),
      ctrl({ id: 'c', relevant: true }),
    ])
    expect(core.map((c) => c.id)).toEqual(['a', 'c'])
    expect(review.map((c) => c.id)).toEqual(['b'])
  })
})
