import React from "react";
import { FormContext, IFormContext } from ".";
import { ValidationError } from "class-validator";
import Typography, { ITypo, ITypoColor } from "../Typography";

export type IProps = {
	value?: string;
	onChange?: (event: React.ChangeEvent<HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement>) => void;
	name: string;
	required?: boolean;
	placeholder?: string;
	readonly?: boolean;
	className?: string;
	defaultValue?: string;
	disableValidation?: boolean;
	validationError?: ValidationError;
	disabled?: boolean;
};

type IState = {
	value: string;
	validationError: ValidationError | null;
};

export default abstract class BaseField<P extends IProps, S extends IState = IState> extends React.Component<P, S> {
	public static override contextType = FormContext;
	public override context: IFormContext | null = null;
	public fieldRef: React.RefObject<any> = React.createRef();

	static defaultProps: Partial<IProps> = {
		disableValidation: false,
		required: true,
	};

	constructor(props: P) {
		super(props);
		this.onChange = this.onChange.bind(this);
		this.onFocus = this.onFocus.bind(this);
		this.onBlur = this.onBlur.bind(this);
		this.hasError = this.hasError.bind(this);
		this.renderErrors = this.renderErrors.bind(this);
	}

	public override componentDidMount() {
		this.context?.setField(this.props.name, this);
		this.setState({
			value: this.props.defaultValue ?? "",
		});
	}

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

		if (this.props.defaultValue !== prevProps.defaultValue) {
			this.setState({
				value: this.props.defaultValue ?? "",
			});
		}

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

	public override componentWillUnmount() {
		this.context?.unSetField(this.props.name);
	}

	protected getDefaultState(): IState {
		return {
			value: this.props.value ?? "",
			validationError: this.props.validationError ?? null,
		};
	}

	protected onFocus(event: React.FocusEvent<HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement>) {
		this.context?.onFieldFocusChange(this.props.name, this, true);
	}

	protected onBlur(event: React.FocusEvent<HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement>) {
		this.context?.onFieldFocusChange(this.props.name, this, false);
	}

	protected onChange(event: React.ChangeEvent<HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement>) {
		this.context?.onFieldChange(this.props.name, this);
		this.setState({ value: event.currentTarget.value, validationError: null });
		if (this.props.onChange) {
			this.props.onChange(event);
		}
	}

	protected hasError(): boolean {
		return this.state.validationError !== null;
		// if(!this.context) return false;
		// if(!this.context.hasOneFocusedInput() && this.state.validationError !== null) return true;
		// return this.state.validationError !== null && this.context.isInputFocused(this.props.name);
	}

	protected renderErrors(): JSX.Element[] | null {
		if (!this.state.validationError || !this.state.validationError.constraints) return null;
		let errors: JSX.Element[] = [];
		Object.entries(this.state.validationError.constraints).forEach(([key, value]) => {
			errors.push(
				<Typography key={key} typo={ITypo.TEXT_SM_REGULAR} color={ITypoColor.COLOR_ERROR_600}>
					{value}
				</Typography>,
			);
		});
		return errors;
	}
}
