/// <reference types="jest-enzyme" />
/// <reference path="../../../../../utilities/jest/extensions.ts" />

import * as fc from 'fast-check'
import * as Enzyme from 'enzyme'
import * as React from 'react'
import Slider, { Orientation } from '.'

it('should exist', () => {
  expect(Slider).toBeDefined()
})

it('should be a component', () => {
  expect(Slider).toBeComponent()
})

it('should render without crashing given required props', () => {
  expect(() => <Slider />).not.toThrow()
})

it('should render a label for describing the nature of the value associated with the component', () => {
  fc.assert(
    fc.property(fc.string(1, 20), (v) => {
      const wrapper = Enzyme.shallow(<Slider label={v} />)

      expect(wrapper.find('label').find('span')).toHaveText(v)
    }),
  )
})

const EnzymeMountMethod: Record<string, Function> = {
  shallow: Enzyme.shallow,
  mount: Enzyme.mount,
}

type MountType = keyof typeof EnzymeMountMethod

describe.each`
  label         | mountType
  ${'fallback'} | ${'shallow'}
  ${'enhanced'} | ${'mount'}
`('on $label mode', ({ mountType: maybeMountType }) => {
  const mountType: MountType = maybeMountType! as MountType
  const { [mountType]: mountMethod } = EnzymeMountMethod

  it('should render an input', () => {
    const wrapper = mountMethod(<Slider />)

    expect(wrapper.find('label').find('input')).toHaveLength(1)
  })

  it('should render as half-opaque when disabled', () => {
    const wrapper = mountMethod(<Slider disabled />)

    expect(wrapper.find('div').first()).toHaveStyle('opacity', 0.5)
  })

  describe.each<Orientation>(['horizontal', 'vertical'])('on %p orientation', (orientation) => {
    const parallelDimension = orientation === 'horizontal' ? 'width' : 'height'

    const perpendicularDimension = orientation === 'horizontal' ? 'height' : 'width'

    it('should render the sizing styles', () => {
      fc.assert(
        fc.property(fc.float(), (v) => {
          const wrapper = mountMethod(<Slider length={v} orientation={orientation} />)

          const sizingWrapper = wrapper.find('SizingWrapper').last()

          expect(sizingWrapper).toHaveStyle({
            [parallelDimension]: v,
            [perpendicularDimension]: '3rem',
          })
        }),
      )
    })

    it('should render the transform styles', () => {
      fc.assert(
        fc.property(
          fc.oneof<string | number>(fc.string().filter((s) => !s.includes(';')), fc.float().filter((v) => v !== 0)),
          (v) => {
            const wrapper = mountMethod(<Slider length={v} orientation={orientation} />)

            const transformWrapper = wrapper.find('TransformWrapper')

            expect(transformWrapper).toHaveStyle({
              [parallelDimension]: v,
              [perpendicularDimension]: '100%',
              transform:
                orientation === 'horizontal'
                  ? undefined
                  : `rotate(-90deg) translateX(calc(${typeof v! === 'number' ? `${v}px` : v} * -1))`,
            })
          },
        ),
      )
    })
  })
})
