/*
 * @Author: 吴永生 15770852798@163.com
 * @Date: 2022-10-18 16:12:55
 * @LastEditors: 吴永生 15770852798@163.com
 * @LastEditTime: 2022-11-01 16:03:44
 * @FilePath: /bkunyun/src/views/ResourceCenter/UserResources/WorkflowOperator/components/AddOperator/index.tsx
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */
import { useEffect, useState, useCallback, useMemo } from "react";
import classNames from "classnames";
import { observer } from "mobx-react";
import { Base64 } from "js-base64";
import _ from "lodash";
import { toJS } from "mobx";

import MyInput from "@/components/mui/MyInput";
import MySelect from "@/components/mui/MySelect";
import MyButton from "@/components/mui/MyButton";
import SwitchBatchFolw from "@/views/ResourceCenter/components/SwitchBatchFolw";
import Code from "@/components/CommonComponents/Code";
import RadioGroupOfButtonStyle from "@/components/CommonComponents/RadioGroupOfButtonStyle";
import { ITask } from "@/views/Project/ProjectSubmitWork/interface";
import BatchOperatorFlow from "@/views/Project/components/Flow/components/BatchOperatorFlow";
import OperatorList from "@/views/CustomOperator/components/OperatorList";
import FormItemBox from "@/components/mui/FormItemBox";
import { useStores } from "@/store";
import useMyRequest from "@/hooks/useMyRequest";
import {
	getActorEnvOptions,
	getOperatorDetail,
	saveOperator,
} from "@/api/resourceCenter";
import { IOperatorAddFormData } from "../../interface";
import {
	checkFormData,
	checkParamsConfig,
	editDefaultVersion,
	initCode,
	text,
} from "./utils";
import batchOperator from "@/assets/resourceCenter/batchOperator.svg";
import flowOperator from "@/assets/resourceCenter/flowOperator.svg";
import { useMessage } from "@/components/MySnackbar";
import CloseIcon from "@mui/icons-material/Close";
import useCheckOperator from "@/views/CustomOperator/useCheckOperator";
import { saveBatchActor } from "@/api/project_api";
import positionTransform from "@/views/CustomOperator/utils";
import MyTooltip from "@/components/mui/MyTooltip";

import style from "./index.module.css";

interface IAddOperator {
	pageType: string;
	setPageType: (val: string) => void;
	detailsId?: string;
	detailsMaxVersion?: string;
	getList: () => void;
}

type IBuildType = "ENVIRONMENT" | "OPERATOR";

const AddOperator = observer((props: IAddOperator) => {
	const { pageType, setPageType, detailsId, detailsMaxVersion, getList } =
		props;
	const Message = useMessage();

	/** 创建类型 BATCH - 批算子;  FLOW - 流算子*/
	const [taskType, setTaskType] = useState<"BATCH" | "FLOW">("BATCH");
	/** 创建类型 ENVIRONMENT - 基于环境;  OPERATOR - 基于算子*/
	const [batchBuildType, setBatchBuildType] =
		useState<IBuildType>("ENVIRONMENT");
	/** 算子数组 */
	const [operatorList, setOperatorList] = useState<ITask[]>([]);
	/** 流程编排 算子是否选中 */
	const [inputActive, setInputActive] = useState(false);
	/** 产品store */
	const { productListStore } = useStores();
	/** 产品第一项  默认所属产品值 */
	const defaultProduct = toJS(productListStore?.productList)?.length
		? toJS(productListStore?.productList[0])?.value
		: undefined;
	/** 应用环境下拉 */
	const [actorEnvOptions, setActorEnvOptions] = useState([]);
	/** 参数配置 */
	const [code, setCode] = useState(JSON.stringify(initCode, null, "\t"));
	/** 参数配置 错误提示 */
	const [parametersError, setParametersError] = useState<string>("");
	/** 流程编排错误提示 */
	const [flowParametersError, setFlowParametersError] = useState<string>("");

	/** 运行脚本 */
	const [command, setCommand] = useState<string>("");

	/** 表单数据 */
	const [formData, setFormData] = useState<IOperatorAddFormData>({
		version: "1.0.0",
		productId: defaultProduct,
	});
	/** 表单数据修改 */
	const [formErrors, setFormErrors] = useState<IOperatorAddFormData>({});
	/** 是否打开帮助手册 */
	const [tipsOpen, setTipsOpen] = useState<boolean>(false);
	/** 详情数据 */
	const [detailInfo, setDetailInfo] = useState<any>();

	const { handleCheck } = useCheckOperator(
		operatorList,
		() => {},
		"流程编排不能为空"
	);

	const buildTypeList = useMemo(() => {
		return [
			{ value: "ENVIRONMENT", label: "基于应用环境" },
			{ value: "OPERATOR", label: "基于流式算子" },
		];
	}, []);

	/** 表单数据 */
	const changeFormData = useCallback(
		(val: IOperatorAddFormData) => {
			setFormData({ ...formData, ...val });
		},
		[formData]
	);

	/** 获取算子详情 */
	const { run: fetchOperatorDetail } = useMyRequest(getOperatorDetail, {
		onSuccess: (res: any) => {
			if (res.message === "success") {
				/** 批算子数据 */
				const batchData = res?.data?.filter((item: any) => {
					return item.type === "BATCH";
				});
				/** 流算子数据 */
				const flowData = res?.data?.filter((item: any) => {
					return item.type === "FLOW";
				});

				/** 确定的算子详情 */
				let determineInfo;
				if (batchData?.length) {
					/** 设置详情信息 */
					determineInfo = batchData[0];
				} else {
					/** 设置详情信息 */
					determineInfo = res?.data?.length ? res.data[0] : {};
				}

				const {
					title = "",
					type = "BATCH",
					version = "",
					productId = "",
					description = "",
					envId = "",
					command: newCommand,
				} = determineInfo;

				const newVersion = editDefaultVersion(detailsMaxVersion || version);
				/** 设置表单数据 */
				setFormData({
					title,
					type,
					version: newVersion,
					productId,
					description,
					envId,
				});
				setCommand(Base64.decode(newCommand || ""));

				/** 有envId 就是基于应用环境创建的 */
				if (type === "BATCH") {
					setBatchBuildType(envId ? "ENVIRONMENT" : "OPERATOR");
				}
				/** 有envId 就是基于应用环境创建的 */
				setTaskType(type || "BATCH");
				/** 设置参数配置 */
				if (type === "BATCH" && !envId) {
					setOperatorList(flowData || []);
				} else {
					setCode(JSON.stringify(determineInfo?.parameters, null, "\t"));
				}
				setDetailInfo(determineInfo);
			}
		},
	});

	// 调用详情数据
	useEffect(() => {
		if (!detailsId) return;
		fetchOperatorDetail(detailsId);
	}, [detailsId, fetchOperatorDetail]);

	/** 保存修改算子 */
	const { run: runSaveOperator } = useMyRequest(saveOperator, {
		onSuccess: (res: any) => {
			if (res?.message === "success") {
				Message.success("构建成功");
				setPageType("");
				getList();
			}
		},
	});

	// 基于流算子构建批算子
	const { run: saveBatchActorRun } = useMyRequest(saveBatchActor, {
		onSuccess: (res) => {
			Message.success("构建成功");
			setPageType("");
			getList();
		},
	});

	// 参数配置失焦校验
	const paramsConfigBlur = useCallback(() => {
		let result, resultError;
		if (batchBuildType === "OPERATOR") return;
		if (code === "") {
			resultError = "请输入参数配置！";
		}
		try {
			result = JSON.stringify(JSON.parse(code), null, "\t");
			if (typeof result === "string") {
				setCode(result);
				const checkErrorArr = checkParamsConfig(result);
				if (checkErrorArr.length) {
					resultError = "参数配置不正确！";
					const codeDom = document.getElementById("paramsConfig");
					const all = codeDom?.getElementsByClassName("cm-line");
					const allArr = Array.prototype.slice.call(all);
					for (let x = 0; x < allArr?.length; x++) {
						const a = `${allArr[x]?.innerHTML}`
							.replace(/"/g, "")
							.replace(/,/g, "")
							.replace(/\t/g, "");
						if (checkErrorArr.includes(a)) {
							setTimeout(() => {
								allArr[x].style =
									"text-decoration: wavy underline; text-decoration-color: #ff4e4e;";
							}, 200);
						}
					}
				}
			}
		} catch (error) {
			resultError = "JSON格式不正确！";
			console.log("JSON格式不正确！");
		}
		setParametersError(resultError || "");
		return resultError;
	}, [batchBuildType, code]);

	/** 获取应用环境下拉 */
	const { run: fetchActorEnvOptions } = useMyRequest(getActorEnvOptions, {
		onSuccess: (res: any) => {
			if (res.message === "success") {
				const newActorEnvOptions =
					res?.data?.map((item: any) => {
						return { label: item.title, value: item.id };
					}) || [];
				setActorEnvOptions(newActorEnvOptions);
			}
		},
	});

	useEffect(() => {
		fetchActorEnvOptions({ type: taskType });
	}, [fetchActorEnvOptions, taskType]);

	/** 切换类型 */
	const handleRadio = (val: IBuildType) => {
		setBatchBuildType(val);
	};

	/** 构建环境提交 */
	const handleSubmit = useCallback(() => {
		const resultErrors = checkFormData(
			formData,
			batchBuildType,
			detailInfo?.maxVersion || "0.99.99"
		);
		const paramsResultError = paramsConfigBlur();
		setFormErrors(resultErrors);

		let checkStatus = "";
		if (taskType === "BATCH" && batchBuildType === "OPERATOR") {
			checkStatus = handleCheck();
			setFlowParametersError(checkStatus);
		}
		if (
			Object.getOwnPropertyNames(resultErrors)?.length ||
			checkStatus ||
			paramsResultError
		)
			return;
		let newParameters = [];
		try {
			newParameters = JSON.parse(code);
		} catch (err) {
			console.log(err);
		}

		const params = {
			...(detailsId ? detailInfo : {}),
			...formData,
			...(batchBuildType === "ENVIRONMENT" && taskType === "BATCH"
				? { command: Base64.encode(command) }
				: {}),
			parameters:
				batchBuildType === "OPERATOR" && taskType === "BATCH"
					? operatorList
					: newParameters,
			type: taskType,
		};

		console.log(operatorList, "operatorList");
		/** 基于流算子没有应用环境字段 */
		if (batchBuildType === "OPERATOR") {
			delete params.envId;
			saveBatchActorRun({
				query: {
					productId: params?.productId as string,
					batchName: params?.title,
					batchVersion: params?.version,
					description: params?.description,
				},
				body: positionTransform(params?.parameters || []),
			});
		} else {
			runSaveOperator(params);
		}
	}, [
		batchBuildType,
		code,
		command,
		detailInfo,
		detailsId,
		formData,
		handleCheck,
		operatorList,
		paramsConfigBlur,
		runSaveOperator,
		saveBatchActorRun,
		taskType,
	]);

	const scriptHelp = useMemo(() => {
		let newText = "";
		try {
			const newData = JSON.parse(code);
			const nameArr = newData?.map((item: any) => {
				return `${item.title}: ~{$actorName$.${item.name}}`;
			});
			newText = nameArr?.join("\n");
		} catch (err) {
			console.log(err);
		}
		console.log(newText, "newText");

		return <pre>{newText}</pre>;
	}, [code]);

	return (
		<div className={style.addOperatorBox}>
			<div className={style.left}>
				<SwitchBatchFolw
					type={pageType !== "add" ? "edit" : undefined}
					bottomImg={flowOperator}
					topImg={batchOperator}
					active={taskType}
					setActive={(e: "BATCH" | "FLOW") => {
						setBatchBuildType("ENVIRONMENT");
						setTaskType(e);
					}}
					goBack={() => setPageType("")}
				/>
			</div>
			<div className={style.right}>
				<div className={style.title}>
					{taskType === "BATCH" ? "批式算子信息" : "流式算子信息"}
				</div>
				{taskType === "BATCH" && pageType !== "edit" ? (
					<div
						style={{
							paddingBottom: batchBuildType === "ENVIRONMENT" ? "20px" : "2px",
						}}
					>
						<RadioGroupOfButtonStyle
							RadiosBoxStyle={{ width: 236 }}
							value={batchBuildType}
							radioOptions={buildTypeList}
							handleRadio={handleRadio}
						/>
					</div>
				) : null}
				<div className={style.content}>
					<div
						className={classNames({
							[style.form]: batchBuildType === "ENVIRONMENT",
							[style.newForm]: batchBuildType !== "ENVIRONMENT",
							[style.formOpen]: batchBuildType !== "OPERATOR" && tipsOpen,
							[style.formClose]: !tipsOpen,
						})}
					>
						<FormItemBox
							label="算子名称"
							labelClassName={style.labelClassName}
							className={classNames({
								[style.operatorFormItem]: formErrors?.title,
							})}
							itemFlex="column"
							errorMessage={formErrors?.title || ""}
							require
						>
							<MyInput
								helperText={
									formErrors?.title ? "" : "15字符以内，仅限字母、数字、中文"
								}
								disabled={!!detailsId}
								placeholder="请输入算子名称"
								value={formData?.title}
								onChange={(e) => {
									changeFormData({ title: e.target.value });
								}}
							/>
						</FormItemBox>
						<FormItemBox
							label="算子版本"
							labelClassName={style.labelClassName}
							className={style.operatorFormItem}
							itemFlex="column"
							errorMessage={formErrors?.version || ""}
							require
						>
							<MyInput
								helperText={formErrors?.version ? "" : detailsMaxVersion}
								value={formData?.version}
								onChange={(e) => {
									changeFormData({ version: e.target.value });
								}}
							/>
						</FormItemBox>

						<FormItemBox
							label="所属产品"
							labelClassName={style.labelClassName}
							errorMessage={formErrors?.productId || ""}
							className={classNames({
								[style.operatorFormItem]: batchBuildType === "ENVIRONMENT",
							})}
							itemFlex="column"
							require
						>
							<MySelect
								fullWidth
								disabled={!!detailsId}
								options={productListStore?.productList || []}
								value={formData?.productId}
								onChange={(e) => {
									changeFormData({ productId: e });
								}}
							/>
						</FormItemBox>
						{batchBuildType === "ENVIRONMENT" ? (
							<FormItemBox
								label="应用环境"
								labelClassName={style.labelClassName}
								className={style.operatorFormItem}
								errorMessage={formErrors?.envId || ""}
								itemFlex="column"
								require
							>
								<MySelect
									fullWidth
									options={actorEnvOptions || []}
									value={formData?.envId}
									onChange={(e) => {
										changeFormData({ envId: e });
									}}
								/>
							</FormItemBox>
						) : null}
						{batchBuildType === "ENVIRONMENT" ? (
							<FormItemBox
								label="描述"
								labelClassName={style.labelClassName}
								itemFlex="column"
								errorMessage={formErrors?.description || ""}
							>
								<MyInput
									multiline
									rows={4}
									placeholder="请输入算子描述"
									value={formData?.description}
									onChange={(e) => {
										if (e.target.value?.length > 300) return;
										changeFormData({ description: e.target.value });
									}}
								/>
								<span
									style={{
										position: "absolute",
										fontSize: "14px",
										top: "96px",
										right: "12px",
										color:
											Number(formData?.description?.length) >= 300
												? "#d32f2f"
												: "#C2C6CC",
									}}
								>
									{formData?.description?.length || 0}/300
								</span>
							</FormItemBox>
						) : null}
					</div>

					{batchBuildType === "ENVIRONMENT" ? (
						<div className={style.codeBox}>
							<div className={style.codeTitle}>
								<span>参数配置</span>
								<span
									onClick={() => setTipsOpen(!tipsOpen)}
									style={{ color: "#1370FF", cursor: "pointer" }}
								>
									帮助手册
								</span>
							</div>
							<div className={style.code}>
								<Code
									id="paramsConfig"
									value={code}
									onChange={(e: string) => {
										setCode(e);
									}}
									onBlur={paramsConfigBlur}
									height={parametersError ? "486px" : "518px"}
									width="600"
									style={{ flex: 1 }}
								/>
								{parametersError ? (
									<p className={style.codeErrorBox}>{parametersError}</p>
								) : null}
							</div>
						</div>
					) : (
						<div className={style.descBox}>
							<FormItemBox
								label="描述"
								labelClassName={style.labelClassName}
								className={style.operatorFormItem}
								itemFlex="column"
								errorMessage={formErrors?.description || ""}
							>
								<MyInput
									style={{ width: "420px" }}
									multiline
									rows={10}
									placeholder="请输入算子描述"
									value={formData?.description}
									onChange={(e) => {
										if (e.target.value?.length > 300) return;
										changeFormData({ description: e.target.value });
									}}
								/>
								<span
									style={{
										position: "absolute",
										fontSize: "14px",
										top: "216px",
										right: "12px",
										color:
											Number(formData?.description?.length) >= 300
												? "#d32f2f"
												: "#C2C6CC",
									}}
								>
									{formData?.description?.length || 0}/300
								</span>
							</FormItemBox>
						</div>
					)}
					{batchBuildType !== "OPERATOR" && (
						<div
							className={classNames({
								[style.helpBox]: true,
								[style.helpOpen]: tipsOpen,
								[style.helpClose]: !tipsOpen,
							})}
						>
							<div className={style.codeTitle}>
								<span>帮助手册</span>
								<CloseIcon
									onClick={() => setTipsOpen(false)}
									sx={{
										fontSize: "16px",
										color: "#C2C6CC",
										cursor: "pointer",
										":hover": {
											background: "#f0f2f5",
											borderRadius: "2px",
										},
									}}
								/>
							</div>
							<pre
								className={classNames({
									[style.preBox]: true,
								})}
							>
								{text}
							</pre>
						</div>
					)}
				</div>

				{taskType === "FLOW" ? null : (
					<div
						className={style.parameterConfigBox}
						style={{ marginBottom: flowParametersError ? "56px" : "24px" }}
					>
						<div className={style.codeTitle}>
							<span>
								{batchBuildType === "ENVIRONMENT" ? "运行脚本" : "流程编排"}
							</span>
							{batchBuildType === "ENVIRONMENT" ? (
								<MyTooltip title={scriptHelp}>
									<span style={{ color: "#1370FF", cursor: "pointer" }}>
										帮助手册
									</span>
								</MyTooltip>
							) : null}
						</div>
						{batchBuildType === "ENVIRONMENT" ? (
							<div className={style.code}>
								<Code
									value={command}
									onChange={(e: string) => setCommand(e)}
									height="350px"
								/>
							</div>
						) : (
							<div
								id="customOperatorFlow"
								className="reactFlowBox"
								style={{
									position: "relative",
									height: 400,
								}}
							>
								<OperatorList
									operatorList={operatorList}
									setOperatorList={setOperatorList}
									setInputActive={setInputActive}
									productId={formData.productId || ""}
								/>
								<BatchOperatorFlow
									tasks={operatorList}
									setTasks={setOperatorList}
									type="edit"
									// onFlowNodeClick={handleNodeClick}
									flowNodeDraggable={true}
									ListenState={!inputActive}
									showVersion={true}
									showControls={false}
								/>
								{flowParametersError ? (
									<p className={style.codeErrorBox}>{flowParametersError}</p>
								) : null}
							</div>
						)}
					</div>
				)}

				<div className={style.buttonBox}>
					<MyButton
						text={detailsId ? "更新完成" : "开始构建"}
						onClick={handleSubmit}
					/>
				</div>
			</div>
		</div>
	);
});
export default AddOperator;
