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

import Typography, { ITypo, ITypoColor } from "../../Typography";
import classes from "./classes.module.scss";
import { NextRouter, useRouter } from "next/router";

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

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

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

type IPropsClass = IProps & {
	router: NextRouter;
};

class SelectFieldClass extends React.Component<IPropsClass, IState> {
	private contentRef = React.createRef<HTMLUListElement>();
	private rootRef = React.createRef<HTMLDivElement>();
	private removeOnresize = () => {};

	static defaultProps = {
		disabled: false,
	};

	constructor(props: IPropsClass) {
		super(props);
		this.state = {
			isOpen: false,
			listHeight: 0,
			listWidth: 0,
			selectedOption: null,
			errors: this.props.errors ?? 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={classes["container"]}>
				<div
					className={classNames(classes["root"], this.props.className)}
					ref={this.rootRef}
					data-disabled={this.props.disabled?.toString()}
					data-errored={(this.state.errors !== null).toString()}>
					{selectedOption && <input type="text" defaultValue={selectedOption.value as string} name={this.props.name} hidden />}
					<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.TEXT_LG_REGULAR}>
										<span className={classes["text"]}>{selectedOption?.label}</span>
									</Typography>
								</>
							)}
							{!selectedOption && (
								<div className={classes["placeholder"]} data-open={(selectedOption ? true : false).toString()}>
									<Typography typo={ITypo.TEXT_MD_REGULAR}>
										<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.TEXT_LG_REGULAR}>{option.label}</Typography>
							</li>
						))}
					</ul>

					{this.state.isOpen && <div className={classes["backdrop"]} onClick={this.toggle} />}
				</div>
				{this.state.errors !== null && <div className={classes["errors-container"]}>{this.renderErrors()}</div>}
			</div>
		);
	}
	public override componentDidMount(): void {
		this.onResize();
		this.removeOnresize = WindowStore.getInstance().onResize(() => this.onResize());

		this.props.router.events.on("routeChangeStart", () => {
			this.setState({
				isOpen: false,
				selectedOption: null,
				listHeight: 0,
				listWidth: 0,
			});
		});
	}

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

	public override componentDidUpdate(prevProps: IProps) {
		if (this.props.errors !== prevProps.errors) {
			this.setState({
				errors: this.props.errors ?? null,
			});
		}

		if (this.props.selectedOption !== prevProps.selectedOption) {
			this.setState({
				selectedOption: this.props.selectedOption ?? null,
			});
		}
	}

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

	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) {
		if (this.props.disabled) return;
		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>) {
		if (this.props.disabled) return;
		this.props.onChange && this.props.onChange(option);
		this.setState({
			selectedOption: option,
		});
		this.toggle(e);
	}

	private renderErrors(): JSX.Element | null {
		if (!this.state.errors) return null;
		return (
			<Typography typo={ITypo.TEXT_SM_REGULAR} color={ITypoColor.COLOR_ERROR_600}>
				{this.props.placeholder} ne peut pas être vide
			</Typography>
		);
	}
}

export default function SelectField(props: IProps) {
	const router = useRouter();
	return <SelectFieldClass {...props} router={router} />;
}
