import { useCallback, useEffect, useRef, useState } from "react";
import classes from "./classes.module.scss";
import HorizontalTab, { ITab } from "./HorizontalTab";
import VerticalTabs from "./VerticalTabs";
import Typography, { ETypo, ETypoColor } from "@Front/Components/DesignSystem/Typography";
import { useWindowSize } from "@uidotdev/usehooks";
import useOpenable from "@Front/Hooks/useOpenable";

export type ITabValue<T> = T & {
	id: unknown;
}

type ITabInternal<T> = ITab & {
	key?: string;
	value: ITabValue<T>;
};

type IProps<T> = {
	tabs: ITabInternal<T>[];
	onSelect: (value: T) => void;
};

export default function Tabs<T>({ onSelect, tabs: propsTabs }: IProps<T>) {
	const tabs = useRef(propsTabs);

	const shadowElementRef = useRef<HTMLDivElement>(null);
	const [visibleElements, setVisibleElements] = useState<ITabInternal<T>[]>([]);
	const [overflowedElements, setOverflowedElements] = useState<ITabInternal<T>[]>([]);

	const [selectedTab, setSelectedTab] = useState<ITabValue<T>>(tabs.current[0]!.value);

	const { close, isOpen, toggle } = useOpenable();

	const windowSize = useWindowSize();

	const calculateVisibleElements = useCallback(() => {
		const shadowElement = shadowElementRef.current;
		if (!shadowElement) return;

		const shadowElementWidth = shadowElement.offsetWidth;
		// The first element is the show more element, it needs to be ignored in the calculation
		let totalWidth = (shadowElement.children[0]! as HTMLElement).offsetWidth;

		let visibleCount = 0;
		for (let i = 1; i < shadowElement.children.length; i++) {
			totalWidth += (shadowElement.children[i]! as HTMLElement).offsetWidth;
			if (totalWidth > shadowElementWidth) {
				break;
			}
			visibleCount++;
		}

		setVisibleElements(tabs.current.slice(0, visibleCount));
		setOverflowedElements(tabs.current.slice(visibleCount));
	}, []);

	useEffect(() => {
		tabs.current = propsTabs;
	}, [propsTabs]);

	useEffect(() => {
		calculateVisibleElements();
	}, [calculateVisibleElements, windowSize]);

	const handleSelect = useCallback(
		(value: ITabValue<T>) => {
			setSelectedTab(value);
			onSelect(value);
			close();
			calculateVisibleElements();
		},
		[close, onSelect, calculateVisibleElements],
	);

	const handleVerticalSelect = useCallback(
		(value: ITabValue<T>) => {
			const index = tabs.current.findIndex((tab) => tab.value.id === value.id);
			const newTabs = [...tabs.current];
			newTabs.splice(index, 1);
			newTabs.unshift(tabs.current[index]!);
			tabs.current = newTabs;
			console.log("Updated values ; ", tabs.current);
			handleSelect(value);
		},
		[handleSelect],
	);

	return (
		<div className={classes["root"]}>
			<div className={classes["mirror-shadow-element"]} ref={shadowElementRef}>
				<div className={classes["show-more"]}>
					<Typography typo={ETypo.TEXT_MD_REGULAR} color={ETypoColor.COLOR_NEUTRAL_500}>
						{overflowedElements.length}&nbsp;de&nbsp;plus...
					</Typography>
				</div>
				{tabs.current.map((element, index) => (
					<HorizontalTab<T>
						label={element.label}
						key={element.key ?? index}
						value={element.value}
						onSelect={handleSelect}
						isSelected={element.value.id === selectedTab.id}
					/>
				))}
			</div>
			<div className={classes["horizontal-container"]}>
				<div className={classes["horizontal-tab"]}>
					{visibleElements.map((element, index) => (
						<HorizontalTab<T>
							label={element.label}
							key={element.key ?? index}
							value={element.value}
							onSelect={handleSelect}
							isSelected={element.value.id === selectedTab.id}
						/>
					))}
				</div>
				{overflowedElements.length > 0 && (
					<div className={classes["show-more-container"]}>
						<div className={classes["show-more"]} onClick={toggle}>
							<Typography typo={ETypo.TEXT_MD_REGULAR} color={ETypoColor.COLOR_NEUTRAL_500}>
								{overflowedElements.length}&nbsp;de&nbsp;plus...
							</Typography>
						</div>
						<div className={classes["vertical-container"]} data-visible={isOpen}>
							{overflowedElements.length > 0 &&
								overflowedElements.map((element, index) => (
									<VerticalTabs<T>
										label={element.label}
										key={element.key ?? index}
										value={element.value}
										onSelect={handleVerticalSelect}
										isSelected={selectedTab === element.value}
									/>
								))}
						</div>
					</div>
				)}
			</div>
		</div>
	);
}
