import { describe, it, expect } from 'vitest'
import { ASNSampler } from '../sampler'

describe('ASNSampler', () => {
  const sampler = new ASNSampler()

  describe('sample', () => {
    it('should return correct number of ASNs in simple random mode', () => {
      const result = sampler.sample(100, { stratifiedByRegion: false, minASNsPerRegion: 0 })
      expect(result.asns.length).toBe(100)
      expect(result.totalSampled).toBe(100)
    })

    it('should return stratified samples with regional distribution', () => {
      const result = sampler.sample(500, {
        stratifiedByRegion: true,
        minASNsPerRegion: 50,
      })

      expect(result.asns.length).toBeLessThanOrEqual(500)
      expect(result.totalSampled).toBeLessThanOrEqual(500)
      expect(Object.keys(result.weightedByRegion).length).toBeGreaterThan(0)
    })

    it('should have timestamp set to current date', () => {
      const result = sampler.sample(50)
      const now = new Date()
      const diff = Math.abs(result.timestamp.getTime() - now.getTime())
      expect(diff).toBeLessThan(1000)
    })

    it('should not contain duplicate ASNs', () => {
      const result = sampler.sample(200, { stratifiedByRegion: true, minASNsPerRegion: 50 })
      const unique = new Set(result.asns)
      expect(unique.size).toBe(result.asns.length)
    })

    it('should exclude private ASN ranges', () => {
      const result = sampler.sample(1000)
      for (const asn of result.asns) {
        const inPrivateRange1 = asn >= 64512 && asn <= 65534
        const inPrivateRange2 = asn >= 4200000000 && asn <= 4294967294
        expect(inPrivateRange1 || inPrivateRange2).toBe(false)
      }
    })

    it('should respect minASNsPerRegion constraint', () => {
      const minPerRegion = 100
      const result = sampler.sample(500, {
        stratifiedByRegion: true,
        minASNsPerRegion: minPerRegion,
      })

      for (const count of Object.values(result.weightedByRegion)) {
        expect(count).toBeGreaterThanOrEqual(minPerRegion)
      }
    })

    it('should use seed parameter when provided', () => {
      const result = sampler.sample(50, { stratifiedByRegion: false, seed: 12345 })
      expect(result.asns).toHaveLength(50)
      expect(result.totalSampled).toBe(50)
    })
  })

  describe('validateASN', () => {
    it('should accept valid public ASNs', () => {
      expect(sampler.validateASN(1)).toBe(true)
      expect(sampler.validateASN(13335)).toBe(true)
      expect(sampler.validateASN(15169)).toBe(true)
    })

    it('should reject private ASN ranges', () => {
      expect(sampler.validateASN(64512)).toBe(false)
      expect(sampler.validateASN(65000)).toBe(false)
      expect(sampler.validateASN(65534)).toBe(false)
      expect(sampler.validateASN(4200000000)).toBe(false)
      expect(sampler.validateASN(4294967294)).toBe(false)
    })

    it('should reject invalid ASN ranges', () => {
      expect(sampler.validateASN(-1)).toBe(false)
      expect(sampler.validateASN(4294967296)).toBe(false)
    })
  })

  describe('getRegionalDistribution', () => {
    it('should return 5 regions', () => {
      const distribution = sampler.getRegionalDistribution()
      expect(distribution.length).toBe(5)
    })

    it('should have valid weight distribution', () => {
      const distribution = sampler.getRegionalDistribution()
      const totalWeight = distribution.reduce((sum, r) => sum + r.weight, 0)
      expect(totalWeight).toBeCloseTo(1.0, 2)
    })

    it('should include APNIC as largest region', () => {
      const distribution = sampler.getRegionalDistribution()
      const apnic = distribution.find((r) => r.region === 'APNIC')
      expect(apnic).toBeDefined()
      expect(apnic?.weight).toBe(0.35)
    })
  })
})
