import { BizImportProps, BizValueType, ButtonAccess } from '@/components';
import useStyle from '@/components/Biz/style.style';
import { useIntl } from '@@/exports';
import {
	ClearOutlined,
	CopyOutlined,
	DownloadOutlined,
	ExclamationCircleOutlined,
	ImportOutlined,
	QuestionCircleOutlined,
} from '@ant-design/icons';
import {
	DrawerForm,
	EditableFormInstance,
	EditableProTable,
	ModalForm,
	ProCard,
	ProFormDependency,
	ProFormTextArea,
} from '@ant-design/pro-components';
import {
	Alert,
	Button,
	Modal,
	Popconfirm,
	Space,
	Tour,
	TourProps,
	Typography,
} from 'antd';
import dayjs from 'dayjs';
import { useRef, useState } from 'react';
import * as XLSX from 'xlsx';

export default function BizImport<
	BizVO extends Record<string, any>,
	BizCreateCmd extends Record<string, any>,
	Func extends Record<string, any>,
>(props: BizImportProps<BizVO, BizCreateCmd, Func>) {
	const {
		permission,
		intlPrefix,
		formType,
		methodUpper,
		func,
		onFinish,
		initValues,
		columns,
		transformData,
		trigger,
		fieldProps,
		isMobile = false,
		tips,
	} = props;
	const { styles } = useStyle();
	const [open, setOpen] = useState(false);

	const editableFormRef = useRef<EditableFormInstance>();

	const ref1 = useRef(null);
	const ref2 = useRef(null);
	const ref3 = useRef(null);

	const [openTour, setOpenTour] = useState<boolean>(false);

	const steps: TourProps['steps'] = [
		{
			title: '下载模板',
			description: '点击下载导入模板',
			target: () => ref1.current,
		},
		{
			title: '准备数据',
			description:
				'在Excel中编辑好数据后，点击粘贴Excel数据按钮，粘贴Excel数据',
			target: () => ref2.current,
		},
		{
			title: '导入数据',
			description: '点击按钮进行导入',
			target: () => ref3.current,
		},
	];

	const intl = useIntl();
	let rest = {
		title: intl.formatMessage({
			id: intlPrefix + '.modal.import.title',
		}),
		autoFocusFirstInput: true,
		submitTimeout: 2000,
		open: fieldProps?.open || open,
		onOpenChange: fieldProps?.onOpenChange || setOpen,
		request: async () =>
			Promise.resolve({
				...initValues,
			} as any),
	};

	const handleExport = () => {
		// 创建数据
		// @ts-ignore
		const data = [columns.map((item) => item.header)];
		// 创建工作簿
		const ws = XLSX.utils.aoa_to_sheet(data);
		const wb = XLSX.utils.book_new();
		XLSX.utils.book_append_sheet(wb, ws, 'Sheet1');

		// 生成Excel文件并触发下载
		XLSX.writeFile(wb, '导入模板' + dayjs().format('YYYYMMDDHHmmss') + '.xlsx');
	};

	const downloadResultExport = (dataList: any[]) => {
		console.log('dataList', dataList);
		// 创建数据
		const data = [
			[
				'导入状态',
				'导入结果',
				// @ts-ignore
				...columns.map((item) => item.header),
			],
			...dataList.map((item) => {
				return [
					item.state === 1 ? '导入成功' : '导入失败',
					item.message,
					...columns.map((column) => {
						if (!column.dataIndex) return '';

						if (Array.isArray(column.dataIndex)) {
							return column.dataIndex.reduce((obj, key, index) => {
								if (obj === null || obj === undefined) return '';
								// @ts-ignore
								return index === column.dataIndex?.length - 1
									? obj[key]
									: obj[key];
							}, item);
						}

						return item[column.dataIndex] || '';
					}),
				];
			}),
		];
		console.log('data', data);
		// 创建工作簿
		const ws = XLSX.utils.aoa_to_sheet(data);
		const wb = XLSX.utils.book_new();
		XLSX.utils.book_append_sheet(wb, ws, 'Sheet1');

		// 生成Excel文件并触发下载
		XLSX.writeFile(wb, '导入结果' + dayjs().format('YYYYMMDDHHmmss') + '.xlsx');
	};

	const rendContext = () => {
		return (
			<ProFormDependency
				key={'importData'}
				name={['importData', 'importResult', 'loading', 'state']}
			>
				{({ importData, loading, state }, form) => {
					return [
						<ProCard
							bordered={true}
							headerBordered={true}
							title={'1、下载模板'}
							subTitle={
								<a
									onClick={() => {
										setOpenTour(true);
									}}
								>
									操作指引
								</a>
							}
							key={'message'}
							extra={
								<Button
									ref={ref1}
									key={'downloadTemplate'}
									icon={<DownloadOutlined />}
									onClick={() => {
										handleExport();
									}}
								>
									下载导入模板
								</Button>
							}
						>
							<Alert
								key={'message'}
								message={
									<pre>
										建议初次使用时，先导入少量数据进行尝试
										<br />
										EXCEL表中的数据按表头顺序排列
										<br />带{' '}
										<span style={{ color: 'red', marginLeft: 4 }}>*</span>{' '}
										号的字段为必填
										<br />
										带 <QuestionCircleOutlined /> 号的字段,请查看填写要求!
										<br />
										单元格的内容不能有换行
										<br />
										首列单元格不能为空
										<br />
										所有的日期格式为：yyyy-mm-dd
										<br />
										所有的时间格式为：yyyy-mm-dd hh:mm
										<br />
										{tips}
									</pre>
								}
							/>
						</ProCard>,
						<ProCard
							bordered={true}
							headerBordered={true}
							style={{ marginBlockStart: 24 }}
							title={'2、数据导入'}
							subTitle={
								'准备数据并粘贴后，会预览导入数据，然后点击导入按钮进行导入'
							}
							key={'data'}
							extra={
								<Space>
									<ModalForm
										title={'粘贴导入数据'}
										modalProps={{
											destroyOnHidden: true,
										}}
										key={'copyImportData'}
										trigger={
											<Button ref={ref2} icon={<CopyOutlined />}>
												粘贴Excel数据
											</Button>
										}
										onFinish={async (formData) => {
											/**
											 * {context:"1\t\t3\t4\t5\t6\t7\t8\t1\n1\t2\t3\t4\t5\t6\t7\t8\t1\n1\t2\t3\t4\t5\t6\t7\t8\t1\n"}
											 * \n 换行
											 * \t 制表
											 */
											let context = formData.context;
											// 如果最后一个是换行的情况下不要换行
											if (context.endsWith('\n')) {
												context = context.substring(0, context.length - 1);
											}

											if (context) {
												const data = context.split('\n');
												let result = [];
												for (let i = 0; i < data.length; i++) {
													const item = data[i];
													const temp = item.split('\t');
													let obj = {
														id: (Math.random() * 1000000).toFixed(0),
														state: 0,
													};
													for (let j = 0; j < temp.length; j++) {
														const dataIndex = columns[j]?.dataIndex;
														// 支持一个数字，[a,b] 会转化为 obj.a.b
														if (Array.isArray(dataIndex)) {
															let objTemp = obj;
															for (let k = 0; k < dataIndex.length; k++) {
																const key = dataIndex[k];
																if (k === dataIndex.length - 1) {
																	// @ts-ignore
																	objTemp[key] = temp[j];
																} else {
																	// @ts-ignore
																	if (!objTemp[key]) {
																		// @ts-ignore
																		objTemp[key] = {};
																	}
																	// @ts-ignore
																	objTemp = objTemp[key];
																}
															}
														} else {
															// @ts-ignore
															obj[dataIndex] = temp[j];
														}
													}

													result.push(obj);
												}

												form.setFieldsValue({
													state: 1,
													importData: result,
												});
											}
											return true;
										}}
									>
										<ProFormTextArea
											name={'context'}
											required={true}
											label={'粘贴导入数据'}
											placeholder={
												'请在Excel中的数据复制后，粘贴在这里，然后点击确定'
											}
											rules={[
												{
													required: true,
													message: '请输入复制的数据',
												},
												{
													validator: (_: any, value: string) => {
														if (value && value.indexOf('\t') !== -1) {
															return Promise.resolve();
														} else {
															return Promise.reject(
																'请粘贴复制的数据，并且粘贴的数据必须是Excel中的数据',
															);
														}
													},
												},
											]}
											fieldProps={{
												autoSize: {
													minRows: 20,
													maxRows: 20,
												},
											}}
										/>
									</ModalForm>

									<Button
										ref={ref3}
										key={'import'}
										loading={loading}
										type={'primary'}
										disabled={
											!(state === 1) || !(importData && importData.length > 0)
										}
										icon={<ImportOutlined />}
										onClick={() => {
											Modal.confirm({
												title: '确认导入',
												icon: <ExclamationCircleOutlined />,
												content: `预计导入${importData.length}条数据，请耐心等待`,
												okText: '确认',
												cancelText: '取消',
												onOk: async () => {
													form.setFieldsValue({
														loading: true,
													});

													for (let i = 0; i < importData.length; i++) {
														const importData1 = importData[i];
														try {
															const newImportData =
																await transformData(importData1);
															if (newImportData.errMessage) {
																editableFormRef?.current?.setRowData?.(
																	importData1.id,
																	{
																		...importData1,
																		state: 2,
																		message: newImportData.errMessage,
																	},
																);
																continue;
															}
															const { data } =
																await func?.[`create${methodUpper}`](
																	newImportData,
																);

															// 100 ms 执行一次
															await new Promise((resolve) => {
																setTimeout(resolve, 100);
															});
															editableFormRef?.current?.setRowData?.(
																importData1.id,
																{
																	...importData1,
																	state: 1,
																	message: data?.errMessage,
																},
															);
														} catch (error) {
															console.log(error);
															editableFormRef?.current?.setRowData?.(
																importData1.id,
																{
																	...importData1,
																	state: 2,
																	// @ts-ignore
																	message: error?.info?.errMessage,
																},
															);
														}
													}

													form.setFieldsValue({
														loading: false,
													});

													form.setFieldsValue({
														state: 2,
													});

													onFinish?.();
												},
											});
										}}
									>
										{loading ? '导入中' : '开始导入'}
									</Button>

									{state === 2 &&
										importData.some((item: any) => item.state === 2) && (
											<Button
												key={'result'}
												icon={<DownloadOutlined />}
												onClick={() => {
													downloadResultExport(importData);
												}}
											>
												结果导出
											</Button>
										)}

									{importData && importData.length > 0 && (
										<Popconfirm
											title="确认清空"
											description="清空后数据将不保留"
											onConfirm={() => {
												form.setFieldsValue({ importData: [], state: 0 });
											}}
											okText="确认"
											cancelText="取消"
										>
											<Button
												key={'clear'}
												danger={true}
												icon={<ClearOutlined />}
											>
												清空数据
											</Button>
										</Popconfirm>
									)}
								</Space>
							}
						>
							{importData && (
								<Typography.Title level={5}>
									{`预计导入 ${importData.length} 条数据，待导入 ${importData.filter((item: any) => item.state === 0).length} 条数据，导入成功 ${importData.filter((item: any) => item.state === 1).length} 条数据，导入失败 ${importData.filter((item: any) => item.state === 2).length} 条数据`}
								</Typography.Title>
							)}

							<EditableProTable<any, any, BizValueType>
								scroll={{ x: 'max-content' }}
								rowKey={'id'}
								key={'importData'}
								name={'importData'}
								options={false}
								ghost={true}
								value={importData}
								editableFormRef={editableFormRef}
								onChange={(importData) => {
									form.setFieldsValue({
										importData,
									});
								}}
								columns={[
									{
										dataIndex: 'state',
										title: '导入状态',
										valueType: 'select',
										valueEnum: {
											0: {
												text: '待导入',
												status: 'default',
											},
											1: {
												text: '导入成功',
												status: 'success',
											},
											2: {
												text: '导入失败',
												status: 'error',
											},
										},
									},
									{
										dataIndex: 'message',
										title: '导入结果',
										valueType: 'text',
									},
									...(columns || []),
								]}
								recordCreatorProps={false}
								editable={{
									type: 'multiple',
									// editableKeys: importData?.map(
									// 	(item: { id: string }) => item.id,
									// ),
									actionRender: (row, config, defaultDoms) => {
										return [defaultDoms.delete];
									},
									onValuesChange: (record, recordList) => {
										form.setFieldsValue({
											recordList,
										});
									},
								}}
							/>
						</ProCard>,
					];
				}}
			</ProFormDependency>
		);
	};

	const renderForm = () => {
		if (formType === 'drawer') {
			return (
				<DrawerForm<BizCreateCmd>
					width={isMobile ? '100%' : '85%'}
					drawerProps={{
						destroyOnHidden: true,
					}}
					submitter={{
						searchConfig: {
							resetText: '关闭',
						},
						submitButtonProps: {
							style: {
								display: 'none',
							},
						},
					}}
					{...rest}
					{...fieldProps}
					className={styles.drawer}
				>
					{rendContext()}
				</DrawerForm>
			);
		}

		if (formType === 'modal') {
			return (
				<ModalForm<BizCreateCmd>
					modalProps={{
						destroyOnHidden: true,
					}}
					submitter={{
						searchConfig: {
							resetText: '关闭',
						},
						submitButtonProps: {
							style: {
								display: 'none',
							},
						},
					}}
					{...rest}
					{...fieldProps}
				>
					{rendContext()}
				</ModalForm>
			);
		}
	};
	const renderTrigger = () => {
		if (trigger) {
			return (
				<div
					onClick={() => {
						setOpen(true);
					}}
				>
					{trigger?.()}
				</div>
			);
		}

		return (
			<ButtonAccess
				className={'biz-import'}
				permission={permission + '-create'}
				key="create"
				icon={<ImportOutlined />}
				type="default"
				size={'middle'}
				onClick={async () => {
					setOpen(true);
				}}
			>
				{!isMobile &&
					intl.formatMessage({
						id: intlPrefix + '.modal.import.button',
					})}
			</ButtonAccess>
		);
	};

	return (
		<>
			{renderTrigger()}
			{renderForm()}
			<Tour open={openTour} onClose={() => setOpenTour(false)} steps={steps} />
		</>
	);
}
