import DepositDocumentIcon from "@Assets/Icons/deposit-document.svg";
import PlusIcon from "@Assets/Icons/plus.svg";
import CrossIcon from "@Assets/Icons/cross.svg";
import DocumentCheckIcon from "@Assets/Icons/document-check.svg";
import Image from "next/image";
import React from "react";

import Button, { EButtonstyletype, EButtonVariant } from "../Button";
import Tooltip from "../ToolTip";
import Typography, { ETypo, ETypoColor } from "../Typography";
import classes from "./classes.module.scss";
import { Document, DocumentHistory, File as FileCustomer } from "le-coffre-resources/dist/Customer";
import Files from "@Front/Api/LeCoffreApi/Customer/Files/Files";
import { EDocumentStatus } from "le-coffre-resources/dist/Customer/Document";
import classNames from "classnames";
import Confirm from "../OldModal/Confirm";
import Alert from "../OldModal/Alert";
import GreenCheckIcon from "@Assets/Icons/green-check.svg";
import Loader from "../Loader";
import TextAreaField from "../Form/TextareaField";
import { toast } from "react-toastify";

type IProps = {
	defaultFiles?: FileCustomer[];
	onChange?: (files: File[]) => void;
	document: Document;
};

type IFile = {
	index: number;
	file: File;
	uid: string;
	archived: Date | null;
	fileName: string;
};

type IState = {
	files: IFile[];
	isDragOver: boolean;
	currentFiles?: FileCustomer[];
	refusedReason?: string;
	isShowRefusedReasonModalVisible: boolean;
	showFailedUploaded: string | null;
	loading: boolean;
};

type fileAccepted = {
	extension: string;
	size: number;
};

const filesAccepted: { [key: string]: fileAccepted } = {
	"application/pdf": {
		extension: "pdf",
		size: 41943040,
	},
	"image/jpeg": {
		extension: "jpeg",
		size: 41943040,
	},
	"image/png": {
		extension: "png",
		size: 41943040,
	},
	"image/jpg": {
		extension: "jpg",
		size: 41943040,
	},
};

export default class DepositDocument extends React.Component<IProps, IState> {
	private inputRef = React.createRef<HTMLInputElement>();
	private index = 0;

	public constructor(props: IProps) {
		super(props);

		this.state = {
			files: [],
			isDragOver: false,
			currentFiles: this.props.defaultFiles,
			refusedReason: "",
			isShowRefusedReasonModalVisible: false,
			showFailedUploaded: null,
			loading: false,
		};

		this.addDocument = this.addDocument.bind(this);
		this.onFileChange = this.onFileChange.bind(this);
		this.addFile = this.addFile.bind(this);
		this.removeFile = this.removeFile.bind(this);
		this.onDragOver = this.onDragOver.bind(this);
		this.onDragDrop = this.onDragDrop.bind(this);
		this.onDragLeave = this.onDragLeave.bind(this);
		this.onCloseModalShowRefusedReason = this.onCloseModalShowRefusedReason.bind(this);
		this.onOpenModalShowRefusedReason = this.onOpenModalShowRefusedReason.bind(this);
		this.showRefusedReason = this.showRefusedReason.bind(this);
		this.onCloseAlertUpload = this.onCloseAlertUpload.bind(this);
	}

	public override render(): JSX.Element {
		return (
			<div className={classes["container"]}>
				<div
					className={classNames(
						classes["root"],
						this.props.document.document_status === EDocumentStatus.VALIDATED && classes["validated"],
					)}
					onDragOver={this.onDragOver}
					onDrop={this.onDragDrop}
					onDragLeave={this.onDragLeave}
					data-drag-over={this.state.isDragOver.toString()}>
					<input
						type="file"
						ref={this.inputRef}
						hidden
						onChange={this.onFileChange}
						accept={Object.keys(filesAccepted).join(",")}
					/>
					<div className={classes["top-container"]}>
						<div className={classes["left"]}>
							<Image src={DepositDocumentIcon} alt="Deposit document" />
						</div>
						<div className={classes["separator"]} />
						<div className={classes["right"]}>
							<Typography typo={ETypo.TEXT_MD_SEMIBOLD} color={ETypoColor.COLOR_GENERIC_BLACK} className={classes["title"]}>
								<div
									className={
										this.props.document.document_status === EDocumentStatus.VALIDATED ? classes["validated"] : ""
									}>
									{this.props.document.document_type?.name}
								</div>
								{this.props.document.document_type?.public_description !== " " &&
									this.props.document.document_type?.public_description !== "" &&
									this.props.document.document_status !== EDocumentStatus.VALIDATED && (
										<Tooltip text={this.props.document.document_type?.public_description || ""} />
									)}
								{this.props.document.document_status === EDocumentStatus.VALIDATED && (
									<Image src={GreenCheckIcon} alt="Document check" />
								)}
							</Typography>
							{this.props.document.document_status !== EDocumentStatus.VALIDATED && (
								<Typography color={ETypoColor.COLOR_NEUTRAL_500} typo={ETypo.TEXT_SM_REGULAR}>
									Sélectionnez des documents .jpg, .pdf ou .png
								</Typography>
							)}
							{this.props.document.document_history?.map((history) => (
								<div key={history.uid}>{this.renderDocumentHistory(history)}</div>
							))}
						</div>
					</div>
					<div className={classes["documents-container"]}>
						{this.state.files.map((file) => {
							const fileObj = file.file;
							if (file.archived) return;
							return (
								<div className={classes["file-container"]} key={fileObj.name + file.index}>
									<div className={classes["left-part"]}>
										<Image src={DocumentCheckIcon} alt="Document check" />
										<Typography
											typo={ETypo.TEXT_MD_REGULAR}
											color={ETypoColor.COLOR_NEUTRAL_500}
											title={file.fileName ?? fileObj.name}>
											{this.shortName(file.fileName || fileObj.name)}
										</Typography>
									</div>
									<Image
										src={CrossIcon}
										alt="Cross icon"
										className={classes["cross"]}
										onClick={this.removeFile}
										data-file={file.index}
									/>
								</div>
							);
						})}
						{this.state.loading && (
							<div className={classes["file-container"]}>
								<div className={classes["left-part"]}>
									<div className={classes["loader"]}>
										<Loader />
									</div>
									<Typography typo={ETypo.TEXT_MD_REGULAR} color={ETypoColor.COLOR_NEUTRAL_500}>
										Chargement...
									</Typography>
								</div>
								<div />
							</div>
						)}
					</div>
					{this.props.document.document_status !== EDocumentStatus.VALIDATED && (
						<div className={classes["bottom-container"]}>
							<Button
								variant={EButtonVariant.PRIMARY}
								styletype={EButtonstyletype.TEXT}
								className={classes["add-button"]}
								onClick={this.addDocument}>
								<Typography
									typo={ETypo.TEXT_MD_SEMIBOLD}
									color={ETypoColor.COLOR_SECONDARY_500}
									className={classes["add-document"]}>
									Ajouter un document <Image src={PlusIcon} alt="Plus icon" />
								</Typography>
							</Button>
						</div>
					)}
					<Confirm
						isOpen={this.state.isShowRefusedReasonModalVisible}
						onClose={this.onCloseModalShowRefusedReason}
						showCancelButton={false}
						onAccept={this.onCloseModalShowRefusedReason}
						closeBtn
						header={"Motif du refus"}
						confirmText={"J'ai compris"}>
						<div className={classes["modal-content"]}>
							<Typography typo={ETypo.TEXT_MD_REGULAR} className={classes["text"]}>
								Votre document a été refusé pour la raison suivante :
							</Typography>
							<TextAreaField placeholder="Description" defaultValue={this.state.refusedReason} readonly />
						</div>
					</Confirm>
				</div>
				{this.props.document.document_status === EDocumentStatus.REFUSED && (
					<Typography typo={ETypo.TEXT_SM_REGULAR} className={classes["error-message"]}>
						Ce document n'est pas conforme. Veuillez le déposer à nouveau.
					</Typography>
				)}
				{this.state.showFailedUploaded && (
					<Alert onClose={this.onCloseAlertUpload} header={"Fichier non autorisé"} isOpen={!!this.state.showFailedUploaded}>
						<div className={classes["modal-content"]}>
							<Typography typo={ETypo.TEXT_MD_REGULAR} className={classes["text"]}>
								{this.state.showFailedUploaded}
							</Typography>
						</div>
					</Alert>
				)}
			</div>
		);
	}

	public override componentDidMount(): void {
		if (this.props.defaultFiles) {
			this.setState({
				files: this.props.defaultFiles.map((file) => ({
					index: this.index++,
					file: new File([""], file.file_path ?? "", {}),
					uid: file.uid!,
					fileName: file.file_name,
					archived: file.archived_at ? new Date(file.archived_at) : null,
				})),
			});
		}
	}

	private openSuccessToast() {
		toast.success("Document envoyé avec succès");
	}

	private onCloseModalShowRefusedReason() {
		this.setState({
			isShowRefusedReasonModalVisible: false,
		});
	}

	private onOpenModalShowRefusedReason() {
		this.setState({
			isShowRefusedReasonModalVisible: true,
		});
	}

	private renderDocumentHistory(history: DocumentHistory): JSX.Element | null {
		switch (history.document_status) {
			case EDocumentStatus.ASKED:
				return (
					<Typography color={ETypoColor.COLOR_NEUTRAL_500} typo={ETypo.TEXT_SM_REGULAR}>
						Demandé par votre notaire le {this.formatDate(history.created_at!)}
					</Typography>
				);
			case EDocumentStatus.VALIDATED:
				return (
					<Typography color={ETypoColor.COLOR_NEUTRAL_500} typo={ETypo.TEXT_SM_REGULAR}>
						Validé par votre notaire le {this.formatDate(history.created_at!)}
					</Typography>
				);
			case EDocumentStatus.DEPOSITED:
				return (
					<Typography color={ETypoColor.COLOR_NEUTRAL_500} typo={ETypo.TEXT_SM_REGULAR}>
						Déposé le {this.formatDate(history.created_at!)}
					</Typography>
				);

			case EDocumentStatus.REFUSED:
				return (
					<Typography typo={ETypo.TEXT_SM_REGULAR} color={ETypoColor.COLOR_ERROR_800}>
						Document non conforme
						{history.refused_reason && history.refused_reason.length > 0 && (
							<Button
								variant={EButtonVariant.PRIMARY}
								styletype={EButtonstyletype.TEXT}
								className={classes["refused-button"]}
								onClick={() => this.showRefusedReason(history.refused_reason ?? "")}>
								Voir le motif de refus
							</Button>
						)}
					</Typography>
				);
		}
		return null;
	}

	private shortName(name: string): string {
		const maxLength = 20;
		if (name.length > maxLength) {
			return name.substring(0, maxLength / 2) + "..." + name.substring(name.length - maxLength / 2, name.length);
		}
		return name;
	}

	private onDragOver(event: React.DragEvent<HTMLDivElement>) {
		if (!this.state.isDragOver) {
			this.setState({
				isDragOver: true,
			});
		}
		event.preventDefault();
	}

	private showRefusedReason(refusedReason: string) {
		this.setState({
			refusedReason,
		});
		this.onOpenModalShowRefusedReason();
	}

	private onDragLeave(event: React.DragEvent<HTMLDivElement>) {
		this.setState({
			isDragOver: false,
		});
		event.preventDefault();
	}

	private async onDragDrop(event: React.DragEvent<HTMLDivElement>) {
		event.preventDefault();
		this.setState({
			isDragOver: false,
		});
		const file = event.dataTransfer.files[0];
		if (file) this.addFile(file);
	}

	private async addFile(file: File) {
		const fileAccepted = filesAccepted[file.type];
		if (!fileAccepted) {
			alert("Le fichier déposé doit être au format .jpg .pdf .jpeg ou .png");
			return false;
		}
		if (file.size > fileAccepted.size) {
			alert("Le fichier est trop volumineux et ne doit pas dépasser 32mo");
			return false;
		}
		this.setState({
			loading: true,
		});

		const formData = new FormData();
		formData.append("file", file, file.name);
		const query = JSON.stringify({ document: { uid: this.props.document.uid } });
		formData.append("q", query);

		let newFile: FileCustomer;
		try {
			newFile = await Files.getInstance().post(formData);
		} catch (e) {
			this.setState({ showFailedUploaded: "Le fichier ne correspond pas aux critères demandés", loading: false });
			return false;
		}
		const files = this.state.currentFiles ? [...this.state.currentFiles, newFile] : [newFile];

		const newFileList = [
			...this.state.files,
			{
				index: this.index++,
				file: file,
				uid: newFile.uid!,
				archived: null,
				fileName: newFile?.file_name ?? "",
			},
		];
		this.openSuccessToast();
		this.setState(
			{
				currentFiles: files,
				loading: false,
				files: newFileList,
			},
			() => {
				if (this.props.onChange) this.props.onChange(newFileList.map((file) => file.file));
			},
		);

		return true;
	}

	private async removeFile(e: any) {
		const image = e.target as HTMLElement;
		const indexToRemove = image.getAttribute("data-file");
		if (!indexToRemove) return;
		const file = this.state.files.find((file) => file.index === parseInt(indexToRemove));
		if (!file) return;
		this.setState({
			files: this.state.files.filter((file) => file.index !== parseInt(indexToRemove)),
		});

		if (this.props.onChange) this.props.onChange(this.state.files.map((file) => file.file));
		await Files.getInstance().delete(file.uid);
	}

	private async onFileChange() {
		if (!this.inputRef.current) return;
		const files = this.inputRef.current.files;
		if (!files) {
			this.setState({ loading: false });
			return;
		}
		const file = files[0];

		try {
			if (file) {
				await this.setState({ loading: true }, () => {
					this.addFile(file);
				});
			}
		} catch (e) {
			this.setState({ loading: false });
		}
	}

	private onCloseAlertUpload() {
		this.setState({ showFailedUploaded: null });
	}

	private addDocument() {
		if (!this.inputRef.current) return;
		this.inputRef.current.value = "";
		this.inputRef.current.click();
	}

	private formatDate(date: Date) {
		const dateToConvert = new Date(date);
		return dateToConvert.toLocaleDateString("fr-FR");
	}
}
