import type React from "react";
import { useRef, useState } from "react";
import { createPortal } from "react-dom";

import { trimText } from "@ax/helpers";

import * as S from "./style";

const PortalTooltip = (props: {
	elementsRows: string[][];
	defaultColor?: string;
	colors?: any;
	prefix: string;
	rounded: boolean;
	size: "S" | "M";
	tooltipRef: React.RefObject<HTMLDivElement>;
	isVisible: boolean;
	elementRect: DOMRect | null;
}) => {
	const { elementsRows, defaultColor, colors, prefix, rounded, size, tooltipRef, isVisible, elementRect } = props;

	if (!isVisible || !elementRect) return null;

	const top = elementRect.top - 8;
	const left = elementRect.left + elementRect.width / 2;

	return createPortal(
		<S.PortalTooltip data-testid="portal-tooltip" style={{ top, left }} ref={tooltipRef}>
			{elementsRows.map((row, idx) => {
				return (
					<S.Row data-testid="row-element" key={idx}>
						{row.map((element, idx) => {
							const color = defaultColor || colors?.[element];
							return (
								<S.Element data-testid="div-element" key={idx} color={color} rounded={rounded} size={size}>
									{prefix}
									{element}
								</S.Element>
							);
						})}
					</S.Row>
				);
			})}
		</S.PortalTooltip>,
		document.body,
	);
};

const ElementsTooltip = (props: IElementsTooltipProps): JSX.Element => {
	const {
		elements,
		maxChar,
		defaultElements = 1,
		colors,
		rounded = false,
		elementsPerRow = 1,
		defaultColor,
		prefix = "",
		size = "S",
	} = props;

	const tooltipRef = useRef<HTMLDivElement>(null);
	const elementRef = useRef<HTMLDivElement>(null);
	const [isTooltipVisible, setIsTooltipVisible] = useState(false);
	const [elementRect, setElementRect] = useState<DOMRect | null>(null);

	if (!elements) return <></>;

	const filteredElements = elements.filter((element) => element !== null && element !== "");

	if (filteredElements.length === 0) return <></>;

	const visibleElements = filteredElements.slice(0, defaultElements);
	const remainingElements = filteredElements.length - defaultElements;

	const elementsRows: string[][] = [];
	filteredElements.forEach((element, idx) => {
		const row = Math.floor(idx / elementsPerRow);
		const isNewRow = idx % elementsPerRow === 0;
		elementsRows[row] = isNewRow ? [element] : [...elementsRows[row], element];
	});

	const handleMouseEnter = () => {
		if (elementRef.current) {
			setElementRect(elementRef.current.getBoundingClientRect());
		}
		setIsTooltipVisible(true);
	};

	const handleMouseLeave = () => {
		setIsTooltipVisible(false);
	};

	return (
		<>
			<S.Wrapper data-testid="elements-wrapper">
				{visibleElements.map((fullElement, idx) => {
					const element = maxChar ? trimText(fullElement, maxChar) : fullElement;
					const color = defaultColor || colors?.[element];

					return (
						<S.Element data-testid="element" key={idx} color={color} rounded={rounded} size={size}>
							{prefix}
							{element}
						</S.Element>
					);
				})}
				{remainingElements > 0 && (
					<S.Element
						data-testid="remaining-element"
						rounded={rounded}
						size={size}
						ref={elementRef}
						onMouseEnter={handleMouseEnter}
						onMouseLeave={handleMouseLeave}
					>
						+{remainingElements}
					</S.Element>
				)}
			</S.Wrapper>
			<PortalTooltip
				elementsRows={elementsRows}
				defaultColor={defaultColor}
				colors={colors}
				prefix={prefix}
				rounded={rounded}
				size={size}
				tooltipRef={tooltipRef}
				isVisible={isTooltipVisible}
				elementRect={elementRect}
			/>
		</>
	);
};

export interface IElementsTooltipProps {
	elements?: string[];
	defaultElements?: number;
	maxChar?: number;
	colors?: any;
	rounded?: boolean;
	elementsPerRow?: number;
	defaultColor?: string;
	prefix?: string;
	size?: "S" | "M";
}

export default ElementsTooltip;
