import { useEffect, useState, useCallback } from "react";
import MyInput from "@/components/mui/MyInput";
import MySelect from "@/components/mui/MySelect";
import MyButton from "@/components/mui/MyButton";
import style from "./index.module.css";
import useMyRequest from "@/hooks/useMyRequest";
import { urlToken } from "@/api/fileserver/raysyncApi";
import * as tus from "tus-js-client";
import { useDropzone } from "react-dropzone";
import SwitchBatchFolw from "@/views/ResourceCenter/components/SwitchBatchFolw";
import { getLoaclStorageOfKey } from "@/api/fileserver/utils";
import Code from "@/components/CommonComponents/Code";
import { useMessage } from "@/components/MySnackbar";
import * as Base64 from "js-base64";
import CloseIcon from "@mui/icons-material/Close";
import { getDataFileToken, hpczone } from "@/api/project_api";
import { checkIsNumberLetterChinese } from "@/utils/util";
import uploaderIcon from "@/assets/project/uploaderIcon.svg";
import zip from "@/assets/resourceCenter/zip.svg";
import {
	getPublicEnv,
	getPublicProject,
	addActorenvBuildenv,
} from "@/api/resourceCenter";
import classNames from "classnames";
import { getTokenInfo } from "@/utils/util";

type IAddEnvironmentProps = {
	setAddopen: any;
};

const AddEnvironment = (props: IAddEnvironmentProps) => {
	const { setAddopen } = props;
	const Message = useMessage();
	let tokenInfo = getTokenInfo();
	const [hpczoneList, setHpczoneList] = useState<Array<any>>([]); // 计算区列表 通过计算区列表和计算区id拿fileServerEndPoint
	const [publicProjectId, setPublicProjectId] = useState(""); // 公共项目id 环境压缩包临时存放在公共项目下
	const [publicZoneId, setPublicZoneId] = useState(""); // 公共项目计算区id
	const [computeType, setComputeType] = useState(""); // 基础环境是cpu 还是 gpu
	const [fileToken, setFileToken] = useState(""); // 访问公共项目的fileToken
	const [taskType, setTaskType] = useState<"BATCH" | "FLOW">("BATCH"); // 环境类型 批式环境还是流式环境
	const [name, setName] = useState(""); // 环境名称
	const [desc, setDesc] = useState(""); // 环境描述
	const [baseEnvId, setBaseEnvId] = useState(""); // 基础环境id
	const [filePaths, setFilePaths] = useState<Array<string>>([]); // 环境压缩包上传后的路径集合（目前只有一个）
	const [isUploading, setIsUploading] = useState(false); // 保存接口loading
	const [fileName, setFileName] = useState(""); // 环境压缩包文件名
	const [envList, setEnvList] = useState<Array<any>>([]); // 基础环境列表   和taskType环境类型有关
	const [progress, setProgress] = useState("0%"); // 上传压缩包进度
	const [code, setCode] = useState(""); // 脚本内容
	const [codeWidth, setCodeWidth] = useState(0);
	const [upload, setUpload] = useState<any>(() => {}); // 上传压缩包实例   用于暂停（取消上传）upload.abort(true);
	const [nameHelper, setNameHelper] = useState({
		error: false,
		text: "30字符以内，仅限字母、数字、中文",
	});
	const [descHelper, setDescHelper] = useState({
		error: false,
		text: "",
	});
	const [filePathsHelper, setFilePathsHelper] = useState({
		error: false,
		text: "",
	});
	const onDrop = useCallback(
		(acceptedFiles: any) => {
			let origin = "";
			hpczoneList.forEach((item) => {
				if (item.id === publicZoneId) {
					origin = item?.storageConfig?.fileServerEndPoint;
				}
			});
			const fileInfo = acceptedFiles[0];
			const { path } = fileInfo;
			if (path.indexOf(".zip") === -1) {
				Message.error("请上传压缩文件");
				return;
			}
			const userInfo = getLoaclStorageOfKey("userInfo");
			const homeDirectoryMountPoint = userInfo?.homeDirectoryMountPoint;
			const url =
				origin + "/parallelupload/" + urlToken(fileToken, publicProjectId);
			let headers = {
				username: publicProjectId,
				token: tokenInfo?.access_token || "",
				filetoken: fileToken,
				share: false,
				project: true,
			};
			let upload = new tus.Upload(fileInfo, {
				endpoint: url,
				parallelUploads: 1,
				chunkSize: 5 * 1024 * 1024,
				metadata: {
					filepath: "/" + homeDirectoryMountPoint + "/" + path,
				},
				retryDelays: [0, 3000, 5000, 10000, 20000],
				headers: headers,
				onbeforeunload: () => {
					setProgress(`0%`);
				},
				onError: function (error: string) {
					setIsUploading(false);
					console.log("Failed because: " + error);
				},
				onProgress: function (bytesUploaded: number, bytesTotal: number) {
					setProgress(`${(bytesUploaded * 100) / bytesTotal}%`);
				},
				onSuccess: function () {
					setIsUploading(false);
					setFilePaths([`/ProjectData/${homeDirectoryMountPoint}/${path}`]);
					setFileName(path);
				},
			});
			setIsUploading(true);
			upload.start();
			setUpload(upload);
		},
		[
			fileToken,
			publicProjectId,
			tokenInfo?.access_token,
			hpczoneList,
			publicZoneId,
			Message,
		]
	);
	const { getRootProps, getInputProps, isDragActive } = useDropzone({ onDrop });

	const { run: getPublicEnvFn } = useMyRequest(getPublicEnv, {
		onSuccess: (res: any) => {
			let arr = res.data.map((item: any) => {
				return {
					label: item.title,
					value: item.id,
					computeType: item.computeType,
				};
			});
			setEnvList(arr);
			if (arr.length >= 1) {
				setBaseEnvId(arr[0].value);
				setComputeType(arr[0].computeType);
			}
		},
	});

	const { run: getPublicProjectFn } = useMyRequest(getPublicProject, {
		onSuccess: (res: any) => {
			setPublicProjectId(res.data[0].id);
			setPublicZoneId(res.data[0].zoneId);
			getDataFileTokenFn({ id: res.data[0].id });
		},
	});

	const { run: getDataFileTokenFn } = useMyRequest(getDataFileToken, {
		onSuccess: (res: any) => {
			setFileToken(res.data);
		},
	});

	const { run: addActorenvBuildenvFn, loading } = useMyRequest(
		addActorenvBuildenv,
		{
			onSuccess: () => {
				Message.success("开始构建应用环境");
				setAddopen(false);
			},
		}
	);

	useEffect(() => {
		getPublicProjectFn();
	}, [getPublicProjectFn]);

	useEffect(() => {
		getPublicEnvFn({ taskType });
	}, [getPublicEnvFn, taskType]);

	const { run: hpczoneFn } = useMyRequest(hpczone, {
		onSuccess: (res: any) => {
			setHpczoneList(res.data);
		},
	});

	useEffect(() => {
		hpczoneFn();
	}, [hpczoneFn]);

	const handleNameChange = (e: any) => {
		setName(e.target.value);
		checkName(e.target.value);
	};

	const handleDescChange = (e: any) => {
		setDesc(e.target.value);
		checkDesc(e.target.value);
	};
	const handelBaseEnvIdChange = (e: any) => {
		setBaseEnvId(e);
		let index = envList.findIndex((item) => {
			return item.value === e;
		});
		setComputeType(envList[index].computeType);
	};

	const checkName = (name: string) => {
		if (!name) {
			setNameHelper({
				error: true,
				text: "环境名称不能为空",
			});
			return true;
		} else if (name.length > 30) {
			setNameHelper({
				error: true,
				text: "格式不正确，30字符以内，仅限字母、数字、中文",
			});
			return true;
		} else if (!checkIsNumberLetterChinese(name)) {
			setNameHelper({
				error: true,
				text: "格式不正确，30字符以内，仅限字母、数字、中文",
			});
			return true;
		} else {
			setNameHelper({
				error: false,
				text: "30字符以内，仅限字母、数字、中文",
			});
			return false;
		}
	};

	const checkDesc = (desc: string) => {
		if (!desc) {
			setDescHelper({
				error: true,
				text: "环境描述不能为空",
			});
			return true;
		} else if (desc.length > 300) {
			setDescHelper({
				error: true,
				text: "描述限300字",
			});
			return true;
		} else {
			setDescHelper({
				error: false,
				text: "",
			});
			return false;
		}
	};

	const checkFile = (filePaths: any) => {
		if (filePaths.length === 0) {
			setFilePathsHelper({
				error: true,
				text: "请上传环境压缩包",
			});
			return true;
		} else {
			setFilePathsHelper({
				error: false,
				text: "",
			});
			return false;
		}
	};

	const handleSubmit = () => {
		if (
			!checkName(name) &&
			!checkDesc(desc) &&
			!checkFile(filePaths) &&
			baseEnvId &&
			code
		) {
			addActorenvBuildenvFn({
				title: name,
				desc,
				baseEnvId,
				type: taskType,
				filePaths,
				bashScript: Base64.encode(code),
				publicProjectId,
				computeType,
			});
		} else {
			Message.error("请完善环境信息");
		}
	};

	const handleAbort = () => {
		upload.abort(true);
		setIsUploading(false);
		setFilePaths([]);
	};

	const getCodeWidth = () => {
		const addEnvironmentCodeElement =
			document.getElementById("addEnvironmentCode");
		setCodeWidth(addEnvironmentCodeElement?.offsetWidth || 0);
	};

	useEffect(() => {
		getCodeWidth();
	}, []);

	return (
		<div className={style.addEnvironment}>
			<div className={style.left}>
				<SwitchBatchFolw
					active={taskType}
					setActive={setTaskType}
					goBack={() => setAddopen(false)}
				></SwitchBatchFolw>
			</div>
			<div className={style.right}>
				<div className={style.title}>
					{taskType === "BATCH" ? "批式环境信息" : "流式环境信息"}
				</div>
				<div className={style.content}>
					<div className={style.form}>
						<div className={style.label}>
							环境名称<span className={style.required}>*</span>
						</div>
						<div
							className={classNames({
								[style.formItem]: true,
								[style.formItemHaveHelperText]: nameHelper.text,
							})}
						>
							<MyInput
								value={name}
								onChange={handleNameChange}
								error={nameHelper.error}
								helperText={nameHelper.text}
								placeholder="给环境起个名称"
							></MyInput>
						</div>
						<div className={style.label}>
							描述<span className={style.required}>*</span>
						</div>
						<div className={style.formItem}>
							<MyInput
								value={desc}
								id="desc"
								multiline
								rows={4}
								placeholder="请输入项目描述"
								onChange={handleDescChange}
								error={descHelper.error}
								helperText={descHelper.text}
							/>
							<span
								style={{
									position: "absolute",
									fontSize: "14px",
									bottom: "7px",
									right: "12px",
									color: desc.length >= 300 ? "#d32f2f" : "#C2C6CC",
								}}
							>
								{desc.length}/300
							</span>
						</div>
						<div className={style.label}>
							基础环境<span className={style.required}>*</span>
						</div>
						<div className={style.formItem}>
							<MySelect
								options={envList}
								fullWidth
								value={baseEnvId}
								onChange={(e) => handelBaseEnvIdChange(e)}
							></MySelect>
						</div>
						<div className={style.label}>
							上传环境压缩包<span className={style.zipText}>（.zip）</span>
							<span className={style.required}>*</span>
							<span
								className={style.download}
								onClick={() =>
									window.open(
										"https://projectsif.oss-cn-beijing.aliyuncs.com/build_env_template.zip"
									)
								}
							>
								下载模板
							</span>
						</div>
						<div className={style.formItem}>
							{filePaths.length === 0 && !isUploading && (
								<div
									className={classNames({
										[style.uploadBox]: true,
										[style.isDragActive]: isDragActive,
									})}
									{...getRootProps()}
								>
									<input {...getInputProps()} />
									<img
										className={style.uploaderIcon}
										src={uploaderIcon}
										alt=""
									/>
									<span>点击选择环境包或将文件</span>
									<span>拖到此处上传</span>
								</div>
							)}
							{isUploading && (
								<div
									className={classNames({
										[style.uploadBox]: true,
									})}
								>
									<div className={style.progressContent}>
										<div className={style.progressBox}>
											<div
												className={style.progress}
												style={{ width: progress }}
											></div>
										</div>
										<CloseIcon
											onClick={() => handleAbort()}
											sx={{
												fontSize: "16px",
												color: "#C2C6CC",
												cursor: "pointer",
												":hover": {
													background: "#f0f2f5",
													borderRadius: "2px",
												},
											}}
										/>
									</div>
									<span>上传中，请稍等...</span>
								</div>
							)}
							{filePaths.length !== 0 && !isUploading && (
								<div
									className={classNames({
										[style.uploadBox]: true,
									})}
								>
									<img className={style.uploaderIcon} src={zip} alt="" />
									<span>{fileName}</span>
									<span
										onClick={() => setFilePaths([])}
										className={style.uploadAgain}
									>
										重新上传
									</span>
								</div>
							)}
							{filePathsHelper.text && (
								<div className={style.tips}>{filePathsHelper.text}</div>
							)}
						</div>
					</div>
					<div className={style.codeBox}>
						<div className={style.codeTitle}>
							{taskType === "BATCH" ? "Shell脚本" : "Python脚本"}
						</div>
						<div className={style.code} id="addEnvironmentCode">
							<Code
								value={code}
								onChange={(e: string) => setCode(e)}
								height="535px"
								width={`${codeWidth}px`}
							/>
						</div>
					</div>
				</div>
				<div className={style.button}>
					<MyButton
						text="开始构建"
						onClick={() => handleSubmit()}
						loading={loading}
					></MyButton>
				</div>
			</div>
		</div>
	);
};
export default AddEnvironment;
