import ChevronIcon from "@Assets/Icons/chevron.svg";
import WindowStore from "@Front/Stores/WindowStore";
import classNames from "classnames";
import Image from "next/image";
import React, { FormEvent, ReactNode } from "react";

import Typography, { ITypo } from "../Typography";
import classes from "./classes.module.scss";

type IProps = {
	selectedOption?: IOption;
	onChange: (selectedOption: IOption) => void;
	options: IOption[];
	hasBorderRightCollapsed?: boolean;
	placeholder?: string;
	className?: string;
};

export type IOption = {
	value: unknown;
	label: string;
	icon?: ReactNode;
};

type IState = {
	isOpen: boolean;
	listWidth: number;
	listHeight: number;
	selectedOption: IOption | null;
};

export default class Select extends React.Component<IProps, IState> {
	private contentRef = React.createRef<HTMLUListElement>();
	private rootRef = React.createRef<HTMLDivElement>();
	private removeOnresize = () => {};

	constructor(props: IProps) {
		super(props);
		this.state = {
			isOpen: false,
			listHeight: 0,
			listWidth: 0,
			selectedOption: null,
		};
		this.toggle = this.toggle.bind(this);
		this.onSelect = this.onSelect.bind(this);
	}

	public override render(): JSX.Element {
		const selectedOption = this.state.selectedOption ?? this.props.selectedOption;
		return (
			<div className={classNames(classes["root"], this.props.className)} ref={this.rootRef}>
				<label
					className={classNames(classes["container-label"])}
					data-open={this.state.isOpen}
					onClick={this.toggle}
					data-border-right-collapsed={this.props.hasBorderRightCollapsed}>
					<div className={classNames(classes["container-input"])}>
						{selectedOption && (
							<>
								<span className={classNames(classes["icon"], classes["token-icon"])}>{selectedOption?.icon}</span>
								<Typography typo={ITypo.P_18}>
									<span className={classes["text"]}>{selectedOption?.label}</span>
								</Typography>
							</>
						)}
						{!selectedOption && (
							<div className={classes["placeholder"]} data-open={(selectedOption ? true : false).toString()}>
								<Typography typo={ITypo.NAV_INPUT_16}>
									<span className={classes["text"]}>{this.props.placeholder ?? ""}</span>
								</Typography>
							</div>
						)}
					</div>
					<Image className={classes["chevron-icon"]} data-open={this.state.isOpen} src={ChevronIcon} alt="chevron icon" />
				</label>

				<ul
					className={classes["container-ul"]}
					data-open={this.state.isOpen}
					ref={this.contentRef}
					style={{
						height: this.state.listHeight + "px",
					}}>
					{this.props.options.map((option, index) => (
						<li key={`${index}-${option.value}`} className={classes["container-li"]} onClick={(e) => this.onSelect(option, e)}>
							<div className={classes["token-icon"]}>{option.icon}</div>
							<Typography typo={ITypo.P_18}>{option.label}</Typography>
						</li>
					))}
				</ul>

				{this.state.isOpen && <div className={classes["backdrop"]} onClick={this.toggle} />}
			</div>
		);
	}

	static getDerivedStateFromProps(props: IProps, state: IState) {
		if (props.selectedOption?.value) {
			return {
				value: props.selectedOption?.value,
			};
		}
		return null;
	}

	public override componentDidMount(): void {
		this.onResize();
		this.removeOnresize = WindowStore.getInstance().onResize(() => this.onResize());
	}

	public override componentWillUnmount() {
		this.removeOnresize();
	}

	private onResize() {
		let listHeight = 0;
		let listWidth = 0;
		listWidth = this.rootRef.current?.scrollWidth ?? 0;
		if (this.state.listHeight) {
			listHeight = this.contentRef.current?.scrollHeight ?? 0;
		}
		this.setState({ listHeight, listWidth });
	}

	private toggle(e: FormEvent) {
		e.preventDefault();
		let listHeight = 0;
		let listWidth = this.rootRef.current?.scrollWidth ?? 0;

		if (!this.state.listHeight) {
			listHeight = this.contentRef.current?.scrollHeight ?? 0;
		}

		this.setState((state) => {
			return { isOpen: !state.isOpen, listHeight, listWidth };
		});
	}

	private onSelect(option: IOption, e: React.MouseEvent<HTMLLIElement, MouseEvent>) {
		this.props.onChange && this.props.onChange(option);
		this.setState({
			selectedOption: option,
		});
		this.toggle(e);
	}
}
