import styled from '@emotion/styled';
import React, { useCallback, useEffect, useRef } from 'react';

interface ExpandableWrapperProps {
  expanded: boolean;
  children: React.ReactNode;
  collapsible?: boolean;
  disabled?: boolean;
  className?: string;
  style?: React.CSSProperties;
}

const ContentOuter = styled.div<{ expanded: boolean }>`
  position: relative;
  flex-grow: 1;
  overflow: visible;
  transition:
    height 0.3s ease-in-out,
    opacity 0.3s ease-in-out;
  display: flex;
  flex-direction: column;
  height: ${({ expanded }) => (expanded ? '100%' : '0px')};
  opacity: ${({ expanded }) => (expanded ? 1 : 0)};
  pointer-events: ${({ expanded }) => (expanded ? 'auto' : 'none')};
`;

const ContentInner = styled.div`
  flex-grow: 1;
`;

export const ExpandableWrapper: React.FC<ExpandableWrapperProps> = ({
  expanded,
  children,
  collapsible = true,
  disabled = false,
  className,
  style,
}) => {
  const finalExpanded = expanded && !disabled;
  const contentRef = useRef<HTMLDivElement>(null);
  const outerRef = useRef<HTMLDivElement>(null);
  const isTransitioning = useRef(false);
  // Set height for animation, then auto after expand
  const setHeightForAnimation = useCallback(() => {
    const outer = outerRef.current;
    const inner = contentRef.current;
    if (!outer || !inner) return;
    if (!collapsible) {
      outer.style.height = 'auto';
      return;
    }
    if (finalExpanded) {
      // EXPAND: set to px, then auto after transition
      const scrollHeight = inner.scrollHeight;
      outer.style.height = scrollHeight + 'px';
      isTransitioning.current = true;
    } else {
      outer.style.pointerEvents = 'none';
      // COLLAPSE: set to px, then to 0
      const scrollHeight = inner.scrollHeight;
      outer.style.height = scrollHeight + 'px';
      // Force reflow for transition
      void outer.offsetHeight;
      outer.style.height = '0px';
      isTransitioning.current = true;
    }
  }, [finalExpanded, collapsible]);

  // when expanded/content changes
  const lastExpandedRef = useRef(finalExpanded);
  const hasMountedRef = useRef(false);
  useEffect(() => {
    if (lastExpandedRef.current !== finalExpanded) {
      setHeightForAnimation();
      lastExpandedRef.current = finalExpanded;
    }
    if (!hasMountedRef.current) {
      hasMountedRef.current = true;
      if (!finalExpanded) setHeightForAnimation();
    }
  }, [finalExpanded, collapsible, setHeightForAnimation]);

  // After expand, set height to auto for dynamic content
  useEffect(() => {
    const outer = outerRef.current;
    if (!outer) return;
    const handleTransitionEnd = (e: TransitionEvent) => {
      if (e.target !== outer || e.propertyName !== 'height') return;
      if (!collapsible) {
        outer.style.height = 'auto';
        outer.style.pointerEvents = 'auto';
        return;
      }
      if (finalExpanded) {
        // After expand, allow dynamic height
        outer.style.height = 'auto';
        outer.style.pointerEvents = 'auto';
      }
      isTransitioning.current = false;
    };
    outer.addEventListener('transitionend', handleTransitionEnd);
    return () => {
      outer.removeEventListener('transitionend', handleTransitionEnd);
    };
  }, [finalExpanded, collapsible]);

  // If content changes while expanded and height is auto, no action needed.
  // But if height is not auto (e.g., after quick content change), force to auto.
  useEffect(() => {
    const outer = outerRef.current;
    if (!outer) return;
    if (!collapsible || finalExpanded) {
      if (!isTransitioning.current) {
        outer.style.height = 'auto';
      }
    }
  }, [children, finalExpanded, collapsible]);

  return (
    <ContentOuter
      ref={outerRef}
      aria-hidden={collapsible ? !finalExpanded : false}
      expanded={finalExpanded}
      className={className}
      style={style}
    >
      <ContentInner ref={contentRef}>{children}</ContentInner>
    </ContentOuter>
  );
};

export default ExpandableWrapper;
