import { describe, expect, it } from 'vitest'

import { parseHex, contrastRatio, relativeLuminance } from './color'
import type { ModePair } from './types'
import { DEFAULT_RAMPS, type Ramp } from './ramps'

describe('DEFAULT_RAMPS', () => {
  const modes: Array<keyof ModePair<Ramp>> = ['light', 'dark']

  it('contains expected ramp keys', () => {
    expect(Object.keys(DEFAULT_RAMPS)).toEqual(['neutral', 'accent', 'success', 'warning', 'danger', 'info'])
  })

  for (const mode of modes) {
    it(`validates step scale structure for ${mode} mode`, () => {
      for (const [name, rampPair] of Object.entries(DEFAULT_RAMPS) as Array<[
        'neutral' | 'accent' | 'success' | 'warning' | 'danger' | 'info', ModePair<Ramp>
      ]>) {
        const ramp = rampPair[mode]
        expect(ramp.steps, name).toHaveLength(12)
        expect(ramp.alpha, name).toHaveLength(12)

        // every step is valid hex
        for (const step of ramp.steps) {
          expect(parseHex(step), `${name} ${step}`).not.toBeNull()
        }

        // 12 DISTINCT steps
        expect(new Set(ramp.steps).size, name).toBe(12)

        // Radix scales are PERCEPTUALLY tuned, NOT strictly relative-luminance monotonic
        // (bright hues bump at step 9, adjacent steps can near-tie). Assert OVERALL direction
        // only: light = step 1 lightest -> step 12 darkest; dark = inverse.
        const luminances = ramp.steps.map((step) => relativeLuminance(parseHex(step)!))
        if (mode === 'light') {
          expect(luminances[0]!, `${name} light first vs last`).toBeGreaterThan(luminances[11]!)
        } else {
          expect(luminances[0]!, `${name} dark first vs last`).toBeLessThan(luminances[11]!)
        }

        // contrast = text on the step-9 solid fill. MUST be the better polarity (white/black)
        // and MUST clear AA 4.5 (small text on a button label).
        const step9 = parseHex(ramp.steps[8]!)!
        const white = contrastRatio([255, 255, 255], step9)
        const black = contrastRatio([0, 0, 0], step9)
        const best = Math.max(white, black)
        expect(best, `${name} ${mode} step9 must reach AA with white or black`).toBeGreaterThanOrEqual(4.5)

        const contrastHex = parseHex(ramp.contrast)
        expect(contrastHex, `${name} contrast hex`).not.toBeNull()
        const chosen = contrastRatio(contrastHex!, step9)
        // chosen polarity must be the BEST available (within rounding), i.e. not the wrong polarity
        expect(chosen, `${name} ${mode} contrast picked wrong polarity`).toBeGreaterThanOrEqual(best - 0.01)
        expect(chosen, `${name} ${mode} contrast below AA`).toBeGreaterThanOrEqual(4.5)
      }
    })
  }
})
