import React from 'react'
import styled from 'styled-components'
import { shadow } from '@planview/pv-utilities'
import { useGridContext, useGridSelector } from '../context/grid-context'

const StickyLeft = styled.div<{ $showShadow: boolean }>`
    width: 36px;
    pointer-events: none;
    position: absolute;
    top: 0;
    overflow: hidden;
    z-index: 20;

    &::before {
        content: '';
        width: 36px;
        position: absolute;
        top: 0;
        bottom: 0;
        left: -36px;
        ${shadow.small};
        display: ${(props) => (props.$showShadow ? 'block' : 'none')};
    }
`

const StickyRight = styled.div<{ $showShadow: boolean }>`
    width: 36px;
    pointer-events: none;
    position: absolute;
    top: 0;
    overflow: hidden;
    z-index: 20;

    &::before {
        content: '';
        width: 36px;
        position: absolute;
        top: 0;
        bottom: 0;
        left: 36px;
        ${shadow.small};
        display: ${(props) => (props.$showShadow ? 'block' : 'none')};
    }
`

export type GridStickyOverlayProps = {
    totalWidth: number
    totalHeight: number
    scrollingRef: React.RefObject<HTMLDivElement | null>
}

type StickyOverlayState = {
    horizontal: number
    vertical: number
}

type StickyScrollState = {
    fullyLeft: boolean
    fullyRight: boolean
}

export const GridStickyOverlay = React.memo(function StickyOverlay({
    totalWidth,
    totalHeight,
    scrollingRef,
}: GridStickyOverlayProps) {
    const grid = useGridContext()

    const stickyColumnDetails = useGridSelector(
        grid.selectors.selectStickyColumnDetails
    )
    const leftWidth = stickyColumnDetails.left.width
    const rightWidth = stickyColumnDetails.right.width

    const [scrollbarOffsets, setScrollbarOffsets] =
        React.useState<StickyOverlayState>({ horizontal: 0, vertical: 0 })

    const [scrollState, setScrollState] = React.useState<StickyScrollState>({
        fullyLeft: true,
        fullyRight: true,
    })

    const updateScrollbarOffsets = React.useCallback(() => {
        const scroller = scrollingRef.current
        if (scroller) {
            const horizontal = scroller.offsetHeight - scroller.clientHeight
            const vertical = scroller.offsetWidth - scroller.clientWidth
            setScrollbarOffsets({ horizontal, vertical })
            grid.events.emit('onScrollbarVisibilityChange', {
                horizontalHeight: horizontal,
                verticalWidth: vertical,
            })
        }
    }, [grid.events, scrollingRef])

    React.useEffect(() => {
        const scroller = scrollingRef.current
        if (scroller) {
            updateScrollbarOffsets()
            const observer = new IntersectionObserver(
                (entries) => {
                    let fullyLeft: boolean
                    let fullyRight: boolean
                    entries.forEach((entry) => {
                        const position = (entry.target as HTMLDivElement)
                            .dataset.pvdsGridSignal
                        if (position === 'left') {
                            fullyLeft = entry.isIntersecting
                        } else if (position === 'right') {
                            fullyRight = entry.isIntersecting
                        }
                    })
                    setScrollState((s) => ({
                        fullyLeft: fullyLeft ?? s.fullyLeft,
                        fullyRight: fullyRight ?? s.fullyRight,
                    }))
                },
                { root: scroller }
            )

            const signals = scroller.querySelectorAll<HTMLDivElement>(
                '[data-pvds-grid-signal]'
            )
            signals.forEach((s) => observer.observe(s))

            return () => {
                observer.disconnect()
            }
        } else {
            console.error("Couldn't wire up scroll handlers")
        }
    }, [scrollingRef, updateScrollbarOffsets])

    React.useEffect(() => {
        updateScrollbarOffsets()
    }, [updateScrollbarOffsets, scrollState, totalWidth, totalHeight])

    return (
        <>
            {leftWidth > 0 && (
                <StickyLeft
                    $showShadow={!scrollState.fullyLeft}
                    style={{
                        left: leftWidth,
                        bottom: scrollbarOffsets.horizontal,
                    }}
                />
            )}
            {rightWidth > 0 && (
                <StickyRight
                    $showShadow={!scrollState.fullyRight}
                    style={{
                        right: rightWidth + scrollbarOffsets.vertical,
                        bottom: scrollbarOffsets.horizontal,
                    }}
                />
            )}
        </>
    )
})
