import Customers from "@Front/Api/LeCoffreApi/Notary/Customers/Customers";
import Folders from "@Front/Api/LeCoffreApi/Notary/Folders/Folders";
import Button, { EButtonStyleType, EButtonVariant } from "@Front/Components/DesignSystem/Button";
import Form from "@Front/Components/DesignSystem/Form";
import { IOption } from "@Front/Components/DesignSystem/Form/SelectField";
import MultiSelect from "@Front/Components/DesignSystem/MultiSelect";
import RadioBox from "@Front/Components/DesignSystem/RadioBox";
import Typography, { ITypo } from "@Front/Components/DesignSystem/Typography";
import BackArrow from "@Front/Components/Elements/BackArrow";
import DefaultNotaryDashboard from "@Front/Components/LayoutTemplates/DefaultNotaryDashboard";
import Module from "@Front/Config/Module";
import { ECivility } from "le-coffre-resources/dist/Customer/Contact";
import { Contact, Customer, OfficeFolder } from "le-coffre-resources/dist/Notary";
import Link from "next/link";
import { NextRouter, useRouter } from "next/router";

import BasePage from "../../Base";
import classes from "./classes.module.scss";
import TextField from "@Front/Components/DesignSystem/Form/TextField";
import { ValidationError } from "class-validator";

enum ESelectedOption {
	EXISTING_CUSTOMER = "existing_customer",
	NEW_CUSTOMER = "new_customer",
}
type IProps = {};
type IState = {
	selectedOption: ESelectedOption;
	availableCustomers: Customer[];
	selectedCustomers: readonly IOption[];
	existingCustomers: IOption[];
	isLoaded: boolean;
	validationError: ValidationError[];
};

type IPropsClass = IProps & {
	selectedFolderUid: string;
	router: NextRouter;
};
class AddClientToFolderClass extends BasePage<IPropsClass, IState> {
	constructor(props: IPropsClass) {
		super(props);
		this.state = {
			selectedOption: ESelectedOption.EXISTING_CUSTOMER,
			availableCustomers: [],
			selectedCustomers: [],
			existingCustomers: [],
			isLoaded: false,
			validationError: [],
		};
		this.onExistingClientSelected = this.onExistingClientSelected.bind(this);
		this.onNewClientSelected = this.onNewClientSelected.bind(this);
		this.onMutiSelectChange = this.onMutiSelectChange.bind(this);
		this.onFormSubmit = this.onFormSubmit.bind(this);
	}
	public override render(): JSX.Element {
		const selectOptions: IOption[] = this.getSelectedOptions();

		const backwardPath = Module.getInstance()
			.get()
			.modules.pages.Folder.pages.FolderInformation.props.path.replace("[folderUid]", this.props.selectedFolderUid);
		return (
			<DefaultNotaryDashboard title={"Ajouter client(s)"}>
				<div className={classes["root"]}>
					<div className={classes["back-arrow"]}>
						<BackArrow url={backwardPath} />
					</div>
					<Typography typo={ITypo.TITLE_H1}>Associer un ou plusieurs client(s)</Typography>
					{this.state.isLoaded && (
						<>
							<div className={classes["radiobox-container"]}>
								{this.state.availableCustomers.length !== 0 && (
									<RadioBox
										name="client"
										onChange={this.onExistingClientSelected}
										checked={this.state.selectedOption === "existing_customer"}
										value={"existing client"}>
										<Typography typo={ITypo.TEXT_LG_REGULAR}>Client existant</Typography>
									</RadioBox>
								)}

								<RadioBox
									name="client"
									onChange={this.onNewClientSelected}
									checked={this.state.selectedOption === "new_customer"}
									value={"new client"}>
									<Typography typo={ITypo.TEXT_LG_REGULAR}>Nouveau client</Typography>
								</RadioBox>
							</div>

							<Form className={classes["form"]} onSubmit={this.onFormSubmit}>
								{this.state.selectedOption === "existing_customer" && (
									<div className={classes["existing-client"]}>
										<MultiSelect
											options={selectOptions}
											placeholder="Clients"
											onChange={this.onMutiSelectChange}
											defaultValue={this.state.selectedCustomers}
										/>
										<div className={classes["button-container"]}>
											<Link href={backwardPath} className={classes["cancel-button"]}>
												<Button variant={EButtonVariant.PRIMARY} styleType={EButtonStyleType.OUTLINED}>
													Annuler
												</Button>
											</Link>
											<Button type="submit">Associer au dossier</Button>
										</div>
									</div>
								)}

								{this.state.selectedOption === "new_customer" && (
									<div className={classes["new-client"]}>
										<TextField
											name="last_name"
											placeholder="Nom"
											validationError={this.state.validationError.find((error) => error.property === "last_name")}
										/>
										<TextField
											name="first_name"
											placeholder="Prénom"
											validationError={this.state.validationError.find((error) => error.property === "first_name")}
										/>
										<TextField
											name="email"
											placeholder="E-mail"
											validationError={this.state.validationError.find((error) => error.property === "email")}
										/>
										<TextField
											name="cell_phone_number"
											placeholder="Numéro de téléphone"
											validationError={this.state.validationError.find(
												(error) => error.property === "cell_phone_number",
											)}
										/>
										<div className={classes["button-container"]}>
											<Link href={backwardPath} className={classes["cancel-button"]}>
												<Button variant={EButtonVariant.PRIMARY} styleType={EButtonStyleType.OUTLINED}>
													Annuler
												</Button>
											</Link>
											<Button type="submit">Associer au dossier</Button>
										</div>
									</div>
								)}
							</Form>
						</>
					)}
				</div>
			</DefaultNotaryDashboard>
		);
	}

	public override async componentDidMount() {
		const query = {};
		const availableCustomers = await Customers.getInstance().get(query);
		let preExistingCustomers: IOption[] | undefined = await this.getFolderPreSelectedCustomers(this.props.selectedFolderUid);
		const existingCustomers = preExistingCustomers ?? [];

		existingCustomers.forEach((customer) => {
			const index = availableCustomers.findIndex((availableCustomer) => availableCustomer.uid === customer.value);
			if (index !== -1) availableCustomers.splice(index, 1);
		});

		let selectedOption = ESelectedOption.EXISTING_CUSTOMER;
		if (availableCustomers.length === 0) {
			selectedOption = ESelectedOption.NEW_CUSTOMER;
		}

		this.setState({ availableCustomers, existingCustomers, isLoaded: true, selectedOption });
	}

	private async getFolderPreSelectedCustomers(folderUid: string): Promise<IOption[] | undefined> {
		const query = {
			q: {
				customers: {
					include: {
						contact: true,
					},
				},
			},
		};
		let preExistingCustomers: IOption[] = [];
		try {
			const folder = await Folders.getInstance().getByUid(folderUid, query);
			preExistingCustomers = folder.customers!.map((customer) => {
				return {
					label: customer.contact?.first_name + " " + customer.contact?.last_name,
					value: customer.uid,
				};
			});
		} catch (error) {
			this.props.router.push(Module.getInstance().get().modules.pages["404"].props.path);
			return;
		}
		return preExistingCustomers;
	}

	private getSelectedOptions(): IOption[] {
		let options = this.state.availableCustomers?.map((customer) => {
			return {
				label: customer.contact?.first_name + " " + customer.contact?.last_name,
				value: customer.uid,
			};
		});
		if (!options) options = [];
		return options;
	}

	private onMutiSelectChange(selectedCustomers: readonly IOption[]): void {
		this.setState({ selectedCustomers });
	}

	private onExistingClientSelected(): void {
		this.setState({ selectedOption: ESelectedOption.EXISTING_CUSTOMER });
	}

	private onNewClientSelected(): void {
		this.setState({ selectedOption: ESelectedOption.NEW_CUSTOMER });
	}

	private async onFormSubmit(
		e: React.FormEvent<HTMLFormElement> | null,
		values: {
			[key: string]: any;
		},
	) {
		values["civility"] = ECivility.MALE; // TODO: should maybe be deleted later or added to the form

		const allCustomersToLink = this.state.selectedCustomers.concat(this.state.existingCustomers);
		let customersToLink: Partial<Customer>[] = allCustomersToLink.map((customer) => {
			return Customer.hydrate<Customer>({ uid: customer.value as string });
		}) as Partial<Customer>[];

		if (this.state.selectedOption === "new_customer") {
			try {
				// remove every space from the phone number
				values["cell_phone_number"] = values["cell_phone_number"].replace(/\s/g, "");
				values["cell_phone_number"] = values["cell_phone_number"].replace(/\./g, "");
				if (values["cell_phone_number"] && values["cell_phone_number"].length === 10) {
					// get the first digit of the phone number
					const firstDigit = values["cell_phone_number"].charAt(0);
					// if the first digit is a 0 replace it by +33
					if (firstDigit === "0") {
						values["cell_phone_number"] = "+33" + values["cell_phone_number"].substring(1);
					}
				}
				const contactToCreate = Contact.hydrate<Customer>(values);
				await contactToCreate.validateOrReject?.({ groups: ["createCustomer"], forbidUnknownValues: false });
			} catch (validationErrors) {
				this.setState({
					validationError: validationErrors as ValidationError[],
				});
				return;
			}

			try {
				const customer: Customer = await Customers.getInstance().post({
					contact: values,
				});
				if (!customer.uid) return;
				customersToLink?.push({ uid: customer.uid } as Partial<Customer>);
			} catch (backError) {
				if (!Array.isArray(backError)) return;
				this.setState({
					validationError: backError as ValidationError[],
				});
				return;
			}
		}

		if (customersToLink) {
			const body = OfficeFolder.hydrate<OfficeFolder>({
				customers: customersToLink.map((customer) => {
					return Customer.hydrate<Customer>(customer);
				}),
			});
			await Folders.getInstance().put(this.props.selectedFolderUid, body);
			this.props.router.push(`/folders/${this.props.selectedFolderUid}`);
		}
	}
}

export default function AddClientToFolder(props: IProps) {
	const router = useRouter();
	let { folderUid } = router.query;
	folderUid = folderUid as string;
	return <AddClientToFolderClass {...props} selectedFolderUid={folderUid} router={router} />;
}
