// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-nocheck
import React from 'react'
import { render, screen, fireEvent } from '@testing-library/react'
jest.mock('../../client/utils', () => ({
  throttle: (fn) => fn,
}))
import BackToTopClient from '../../client'

describe('Back To Top', () => {
  describe('when client-side', () => {
    it('renders hidden by default', () => {
      const tree = render(<BackToTopClient />)
      expect(screen.findByText('Back to top')).toBeTruthy() // Assuming the button is directly rendered
      expect(tree.container.children[0].style.display).toBe('none')
    })

    it('renders a button with attributes', () => {
      render(<BackToTopClient attributes={{ 'data-tracking': 'backtotop' }} />)
      const button = screen.getByRole('button', { hidden: true })
      expect(button.getAttribute('data-tracking')).toBe('backtotop')
    })

    it('becomes visible on scroll up', async () => {
      const tree = render(<BackToTopClient />)

      // Simulate scrolldown event and scrollup to test the display block
      await fireEvent.scroll(window, { target: { scrollY: 300 } })
      await fireEvent.scroll(window, { target: { scrollY: 100 } })

      expect(tree.container.children[0].style.display).toBe('block')
    })

    it('renders the button and hides it again when user scrolls down', async () => {
      const tree = render(<BackToTopClient />)

      // Simulate scrolldown event and scrollup to test the display block
      await fireEvent.scroll(window, { target: { scrollY: 300 } })
      await fireEvent.scroll(window, { target: { scrollY: 100 } })

      expect(tree.container.children[0].style.display).toBe('block')

      // Simulate scrolldown after the last scrollup which should hide the button
      await fireEvent.scroll(window, { target: { scrollY: 200 } })
      expect(tree.container.children[0].style.display).toBe('none')
    })

    it('scrolls to the top when clicked on the button', async () => {
      render(<BackToTopClient />)

      // Simulate scrolldown event and scrollup to test the display block
      await fireEvent.scroll(window, { target: { scrollY: 300 } })
      await fireEvent.scroll(window, { target: { scrollY: 100 } })
      const button = screen.getByRole('button')

      window.scrollTo = jest.fn()

      // Simulate scrolldown after the last scrollup which should hide the button
      await fireEvent.click(button)
      // Check is scrollTo is called with the correct arguments
      expect(window.scrollTo).toHaveBeenCalledWith({
        top: 0,
        left: 0,
        behavior: 'smooth',
      })
    })
    it('the button hides if we scroll up to the top', async () => {
      render(<BackToTopClient />)

      // Simulate scrolldown and scrollup event to test the display block
      await fireEvent.scroll(window, { target: { scrollY: 300 } })
      await fireEvent.scroll(window, { target: { scrollY: 100 } })
      const button = screen.getByRole('button')
      // Check the button is visible
      expect(button).toBeTruthy()
      await fireEvent.scroll(window, { target: { scrollY: 0 } })
      // Check the button is hidden , so getByRole should throw an error
      expect(() => {
        screen.getByRole('button')
      }).toThrow()
    })

    it('renders the button after pass the element selected with startSelector', async () => {
      const tree = render(
        <div>
          <section
            id="head"
            width={'100vw'}
            height={500}
            style={{ width: '100vw', height: 500 }}
          >
            <h1>Head</h1>
          </section>
          <section
            id="body"
            width={'100vw'}
            height={500}
            style={{ width: '100vw', height: 500 }}
          >
            <p> Here goes the content</p>
          </section>
          <BackToTopClient startSelector="#head" />
        </div>
      )
      const head = tree.container.querySelector('#head')
      // Mock that the head element is visible and we haven't passed it
      jest.spyOn(head, 'getBoundingClientRect').mockReturnValue({
        width: 500,
        height: 500,
        top: 0,
        left: 0,
        right: 500,
        bottom: 500,
      })
      // Shouldn't be visible as we haven't passed the head element
      await fireEvent.scroll(window, { target: { scrollY: 300 } })
      await fireEvent.scroll(window, { target: { scrollY: 100 } })
      expect(() => {
        screen.getByRole('button')
      }).toThrow()

      //Mock that the head element is up on the scroll and not visible on the page which means we have passed it
      jest.spyOn(head, 'getBoundingClientRect').mockReturnValue({
        width: 500,
        height: 500,
        top: 0,
        left: 0,
        right: 500,
        bottom: -200,
      })
      await fireEvent.scroll(window, { target: { scrollY: 700 } })
      expect(() => {
        screen.getByRole('button')
      }).toThrow()

      //Scrolled up and had passed the element that startSelector selects so it should be visible
      await fireEvent.scroll(window, { target: { scrollY: 650 } })
      expect(screen.getByRole('button')).toBeTruthy()

      // The button should be visible if we scroll up and the head is visible after having shown it before
      jest.spyOn(head, 'getBoundingClientRect').mockReturnValue({
        width: 500,
        height: 500,
        top: 0,
        left: 0,
        right: 500,
        bottom: 400,
      })
      await fireEvent.scroll(window, { target: { scrollY: 100 } })
      expect(screen.getByRole('button')).toBeTruthy()
    })

    describe('If a `scrollableElement` is passed', () => {
      it('renders the button after pass the element selected with startSelector', async () => {
        const container = document.createElement('div')
        container.id = 'scrollable-element'
        container.style.display = 'block'
        container.style.overflowY = 'scroll'
        container.style.height = '500px'
        document.body.appendChild(container)

        const tree = render(
          <div>
            <section
              id="head"
              width={'100vw'}
              height={500}
              style={{ width: '100vw', height: 500 }}
            >
              <h1>Head</h1>
            </section>
            <section
              id="body"
              width={'100vw'}
              height={500}
              style={{ width: '100vw', height: 500, overflowY: 'scroll' }}
            >
              <p> Here goes the content</p>
            </section>
            <BackToTopClient
              startSelector="#head"
              scrollableElement={container}
            />
          </div>,
          { container }
        )
        const head = tree.container.querySelector('#head')
        // Mock that the head element is visible and we haven't passed it
        jest.spyOn(head, 'getBoundingClientRect').mockReturnValue({
          width: 500,
          height: 500,
          top: 0,
          left: 0,
          right: 500,
          bottom: 500,
        })
        // Shouldn't be visible as we haven't passed the head element
        await fireEvent.scroll(container, { target: { scrollTop: 300 } })
        await fireEvent.scroll(container, { target: { scrollTop: 100 } })
        expect(() => {
          screen.getByRole('button')
        }).toThrow()

        //Mock that the head element is up on the scroll and not visible on the page which means we have passed it
        jest.spyOn(head, 'getBoundingClientRect').mockReturnValue({
          width: 500,
          height: 500,
          top: 0,
          left: 0,
          right: 500,
          bottom: -200,
        })
        await fireEvent.scroll(container, { target: { scrollTop: 700 } })
        expect(() => {
          screen.getByRole('button')
        }).toThrow()

        //Scrolled up and had passed the element that startSelector selects so it should be visible
        await fireEvent.scroll(container, { target: { scrollTop: 650 } })
        expect(screen.getByRole('button')).toBeTruthy()

        // The button should be visible if we scroll up and the head is visible after having shown it before
        jest.spyOn(head, 'getBoundingClientRect').mockReturnValue({
          width: 500,
          height: 500,
          top: 0,
          left: 0,
          right: 500,
          bottom: 400,
        })
        await fireEvent.scroll(container, { target: { scrollTop: 100 } })
        expect(screen.getByRole('button')).toBeTruthy()
      })
    })
  })
})
