import {
  getAlignmentPosition,
  getAnchorPosition,
  getEdgePosition,
} from '../getAnchorPosition'

// TEST UTILS
// ==========

const getBox = (shape, position = { left: 0, top: 0 }) => ({
  ...position,
  ...shape,
  right: shape.width + position.left,
  bottom: shape.height + position.top,
})

const Dimensions = {
  target: { width: 100, height: 100 },
  overlay: { width: 400, height: 400 },
  container: { width: 1000, height: 1000 },
}

const Positions = {
  topLeft: { left: 200, top: 200 },
  bottomLeft: { left: 200, top: 800 },
  bottomRight: { left: 800, top: 800 },
  topRight: { left: 800, top: 200 },
}

const Targets = {
  topLeft: getBox(Dimensions.target, Positions.topLeft),
  topRight: getBox(Dimensions.target, Positions.topRight),
  bottomRight: getBox(Dimensions.target, Positions.bottomRight),
  bottomLeft: getBox(Dimensions.target, Positions.bottomLeft),
}

describe('getAnchorPosition', () => {
  const container = getBox(Dimensions.container)
  const overlay = getBox(Dimensions.overlay)

  it('places an overlay around a contained target', () => {
    const target = Targets.topLeft
    const position = getAnchorPosition(
      'bottom-left',
      0,
      container,
      target,
      overlay
    )
    expect(position.left).toBe(target.left)
    expect(position.top).toBe(target.bottom)
  })

  it('flips placement components as needed', () => {
    const target = Targets.bottomRight
    const position = getAnchorPosition(
      'bottom-left',
      0,
      container,
      target,
      overlay
    )
    expect(position.left).toBe(target.right - overlay.width)
    expect(position.top).toBe(target.top - overlay.height)
  })

  describe('Adjusts position according to padding', () => {
    const target = Targets.bottomLeft
    const edgePadding = 10
    const position = getAnchorPosition(
      'top-left',
      edgePadding,
      container,
      target,
      overlay
    )
    it('adds edge padding', () => {
      expect(position.top).toBe(target.top - overlay.height - edgePadding)
    })
    it('does NOT add alignment padding', () => {
      expect(position.left).toBe(target.left)
    })
  })

  describe('anchors to side or flip if necessary', () => {
    it('anchors left', () => {
      const target = Targets.topRight
      const position = getEdgePosition({
        container,
        target,
        overlay,
        placement: 'left',
      })
      expect(position.left).toBe(target.left - overlay.width)
    })
    it('it anchors right when it should flip(left)', () => {
      const target = Targets.topLeft
      const position = getEdgePosition({
        container,
        target,
        overlay,
        placement: 'left',
      })
      expect(position.left).toBe(target.right)
    })
    it('anchors right', () => {
      const target = Targets.topLeft
      const position = getEdgePosition({
        container,
        target,
        overlay,
        placement: 'right',
      })
      expect(position.left).toBe(target.right)
    })
    it('it anchors left when it should flip(right)', () => {
      const target = Targets.topRight
      const position = getEdgePosition({
        container,
        target,
        overlay,
        placement: 'right',
      })
      expect(position.left).toBe(target.left - overlay.width)
    })
    it('anchors top', () => {
      const target = Targets.bottomLeft
      const position = getEdgePosition({
        container,
        target,
        overlay,
        placement: 'top',
      })
      expect(position.top).toBe(target.top - overlay.height)
    })
    it('it anchors bottom when it should flip(top)', () => {
      const target = Targets.topLeft
      const position = getEdgePosition({
        container,
        target,
        overlay,
        placement: 'top',
      })
      expect(position.top).toBe(target.bottom)
    })
    it('anchors bottom', () => {
      const target = Targets.topRight
      const position = getEdgePosition({
        container,
        target,
        overlay,
        placement: 'bottom',
      })
      expect(position.top).toBe(target.bottom)
    })
    it('it anchors top when it should flip(bottom)', () => {
      const target = Targets.bottomLeft
      const position = getEdgePosition({
        container,
        target,
        overlay,
        placement: 'bottom',
      })
      expect(position.top).toBe(target.top - overlay.height)
    })
  })
  describe('align horizontally/vertically or flip if necessary', () => {
    it('aligns left', () => {
      const target = Targets.topLeft
      const position = getAlignmentPosition({
        container,
        target,
        overlay,
        placement: 'left',
      })
      expect(position.left).toBe(target.left)
    })
    it('it aligns right when it should flip(left)', () => {
      const target = Targets.topRight
      const position = getAlignmentPosition({
        container,
        target,
        overlay,
        placement: 'left',
      })
      expect(position.left + overlay.width).toBe(target.right)
    })
    it('aligns right', () => {
      const target = Targets.topRight
      const position = getAlignmentPosition({
        container,
        target,
        overlay,
        placement: 'right',
      })
      expect(position.left + overlay.width).toBe(target.right)
    })
    it('it aligns left when it should flip(right)', () => {
      const target = Targets.topLeft
      const position = getAlignmentPosition({
        container,
        target,
        overlay,
        placement: 'right',
      })
      expect(position.left).toBe(target.left)
    })

    it('aligns top', () => {
      const target = Targets.topLeft
      const position = getAlignmentPosition({
        container,
        target,
        overlay,
        placement: 'top',
      })
      expect(position.top).toBe(target.top)
    })
    it('it aligns bottom when it should flip(top)', () => {
      const target = Targets.bottomLeft
      const position = getAlignmentPosition({
        container,
        target,
        overlay,
        placement: 'top',
      })
      expect(position.top + overlay.height).toBe(target.bottom)
    })
    it('aligns bottom', () => {
      const target = Targets.bottomLeft
      const position = getAlignmentPosition({
        container,
        target,
        overlay,
        placement: 'bottom',
      })
      expect(position.top + overlay.height).toBe(target.bottom)
    })
    it('it aligns top when it should flip(bottom)', () => {
      const target = Targets.topRight
      const position = getAlignmentPosition({
        container,
        target,
        overlay,
        placement: 'bottom',
      })
      expect(position.top).toBe(target.top)
    })
  })
})
