import React, { useEffect, useRef, useState } from 'react'

import Button from '../Button/Button'
import Image from '../Image/Image'
import LabelAndData from '../LabelAndData/LabelAndData'
import Tag from '../Tag/Tag'
import TrimText from '../TrimText/TrimText'
import { useMediaQuery } from '../../hooks/responsiveHooks'
import { type LabelAndDataProps } from '../LabelAndData/LabelAndData'
import { type TagProps } from '../Tag/Tag'
import ScrollingContainer from '../ScrollingContainer/ScrollingContainer'
import styles from './_information-pane.module.scss'

type Header = {
  /** The header label and data that appears in the left side of the header */
  labelAndData?: Omit<
    LabelAndDataProps,
    'children' | 'customClass' | 'labelClass'
  >
  /** The tag that appears in the right side of the header */
  tag?: TagProps
  /** The edit function to be passed into the edit icon in the right side of the header */
  edit?: () => void
}

export type InformationPaneProps = {
  /** InformationPane will accept any children elements. It is recommended to use the components defined in this file - ImageAndName, Section, CustomSection, and Divider - to achieve the desired design. */
  children: React.ReactNode
  /** The header that will be displayed when `simple` is not defined. This will always be displayed in the desktop view, even if `simple` is defined. */
  header?: Header
  /** Optional prop to simplify the mobile view for this component. */
  simple?: SimpleProps
  /** Indicates if the page has a PageFooter component, which affects container height calculations */
  includePageFooterHeight?: boolean
  /** Optionally hide gradient overlays in the scrolling container */
  hideGradients?: boolean
  /** Optional prop to add a test id to the InformationPane for QA testing */
  qaTestId?: string
}

const InformationPane = ({
  header,
  children,
  simple,
  includePageFooterHeight = false,
  hideGradients = false,
  qaTestId = 'information-pane',
}: InformationPaneProps): React.JSX.Element => {
  const mobileView = useMediaQuery({ type: 'max', breakpoint: 'sm' })
  return simple && mobileView ? (
    <Simple {...simple} qaTestId={qaTestId} />
  ) : (
    <div
      className={`${styles.container} ${includePageFooterHeight ? styles.hasPageFooter : ''}`}
      qa-test-id={qaTestId}
    >
      <HeaderComponent {...header} />
      <ScrollingContainer height='100%' hideGradients={hideGradients}>
        {children}
      </ScrollingContainer>
    </div>
  )
}

type HeaderProps = InformationPaneProps['header']

const HeaderComponent = ({ labelAndData, tag, edit }: HeaderProps = {}) => {
  return (
    <div className={styles.header}>
      <div className={styles.topSection}>
        {labelAndData ? <LabelAndData {...labelAndData} /> : null}
        {tag && !edit ? <Tag {...tag} /> : null}
        {edit ? <Button icon='pencil' onClick={edit} /> : null}
      </div>
      {tag && edit ? <Tag {...tag} /> : null}
    </div>
  )
}

type ImageAndNameProps = {
  /** The url of the product image */
  imgUrl?: string
  /** The product name and associated marketplace url */
  product: { name: string; url?: string }
}

const ImageAndName = ({
  imgUrl,
  product,
}: ImageAndNameProps): React.JSX.Element => {
  return (
    <div className={styles.imageAndNameContainer}>
      <Image
        url={imgUrl}
        alt={product.name}
        style={{ width: 'auto', height: 'auto' }}
        iconSize='72px'
        imgStyle={{ maxWidth: '100%', maxHeight: '128px' }}
      />
      <span className={styles.productName}>
        {product.url ? (
          <a
            href={product.url}
            target='_blank'
            rel='noreferrer'
            className={styles.link}
          >
            {product.name}
          </a>
        ) : (
          <span>{product.name}</span>
        )}
      </span>
    </div>
  )
}

type SectionProps = {
  /** Array of LabelAndData props that will populate in this section */
  data: Omit<LabelAndDataProps, 'customClass' | 'labelClass'>[]
  /** Boolean used to style the section into 1 or 2 columns. 1 column is the default. */
  isTwoColumns?: boolean
}

const Section = ({ data, isTwoColumns }: SectionProps): React.JSX.Element => {
  return (
    <div
      className={`${styles.section} ${isTwoColumns ? styles.twoColumns : ''}`}
    >
      {data.map((d, index) => (
        <div
          key={
            (typeof d.label === 'string' ? d.label : 'infoPane_section') + index
          }
          className={
            isTwoColumns && data.length % 2 !== 0 && index === 0
              ? styles.oddNumber
              : ''
          }
        >
          <LabelAndData
            {...d}
            labelClass={styles.labelAndData}
            customClass={styles.labelAndData}
          />
        </div>
      ))}
    </div>
  )
}

type CustomSectionProps = {
  /** The children elements to be passed into the component. */
  children: React.ReactNode
}

const CustomSection = ({ children }: CustomSectionProps) => {
  return <div className={styles.section}>{children}</div>
}

const Divider = (): React.JSX.Element => {
  return <div className={styles.divider} />
}

type SimpleProps = ImageAndNameProps & {
  /** The product identifier */
  identifier: string
  /** Optional prop to add a test id to the Simple for QA testing */
  qaTestId?: string
}
const Simple = ({
  imgUrl,
  product,
  identifier,
  qaTestId,
}: SimpleProps): React.JSX.Element => {
  const [touchY, setTouchY] = useState<number>(0)
  const [direction, setDirection] = useState<'down' | 'up'>('down')
  const ref = useRef<HTMLDivElement>(null)

  useEffect(() => {
    let prevScrollPos = ref.current?.getBoundingClientRect().y || 0
    const scroll = () => {
      const currentScrollPos = ref.current?.getBoundingClientRect().y || 0
      if (ref.current) {
        if (prevScrollPos > currentScrollPos) {
          setDirection('up')
        }

        if (currentScrollPos > prevScrollPos) {
          setDirection('down')
        }

        prevScrollPos = currentScrollPos
      }
    }
    window.addEventListener('wheel', scroll)
    return () => {
      window.removeEventListener('wheel', scroll)
    }
  }, [])

  useEffect(() => {
    const handleTouchMove = (event: TouchEvent) => {
      const newY = event.touches[0].clientY
      if (touchY !== null) {
        const deltaY = newY - touchY
        if (deltaY > 0) {
          setDirection('down')
        } else if (deltaY < 0) {
          setDirection('up')
        }
      }
      setTouchY(newY)
    }
    window.addEventListener('touchmove', handleTouchMove)
    return () => {
      window.removeEventListener('touchmove', handleTouchMove)
    }
  }, [touchY])

  const imageSmallSize = 72 //The image size is set to small when scrolling up for a more compact view
  const imageLargeSize = 175 //The image size is set to large when scrolling down for a more detailed view
  const imageSize = direction === 'up' ? imageSmallSize : imageLargeSize

  const ProductName = ({ className = '' }: { className?: string }) => {
    const classes = `${styles.productName} ${className}`
    return direction === 'up' ? (
      <TrimText text={product.name} limit={50} customClass={classes} />
    ) : (
      <span className={classes}>{product.name}</span>
    )
  }

  return (
    <div
      className={styles.simpleOuterContainer}
      ref={ref}
      qa-test-id={qaTestId}
    >
      <div className={styles.simpleContainer}>
        <Image
          url={imgUrl}
          alt={product.name}
          style={{
            margin: '0px',
            width: imageSize,
            height: imageSize,
          }}
          imgStyle={{
            maxWidth: imageSize,
            maxHeight: imageSize,
            transition: 'all 0.5s ease',
          }}
        />
        <div className={styles.productInfo}>
          {product.url ? (
            <a href={product.url} target='_blank' rel='noreferrer'>
              {ProductName({ className: styles.link })}
            </a>
          ) : (
            ProductName({})
          )}
          <span className={styles.identifier}>{identifier}</span>
        </div>
      </div>
      <Divider />
    </div>
  )
}
InformationPane.ImageAndName = ImageAndName
InformationPane.Section = Section
InformationPane.CustomSection = CustomSection
InformationPane.Divider = Divider
InformationPane.Simple = Simple

export { InformationPane }
