<template>
	<el-dialog
		class="super-flexible-dialog"
		:title="isDetail ? title.detail : !dataForm.id ? title.add : title.edit"
		:visible.sync="visible"
		@close="handleClose"
		:distory-on-close="true"
		:close-on-click-modal="false">
		<div style="max-height: 60vh; overflow-y: scroll; overflow-x: hidden">
			<el-form ref="dataForm" :model="dataForm" :rules="dataFormRules">
				<!-- 如果需要更精细一点的布局，可以根据配置项实现地再复杂一点，但此处暂时全部采用一行两列布局  -->
				<el-row v-for="n in rows" :key="n" :gutter="20">
					<el-col v-for="c in COLUMN_PER_ROW" :key="`${n}+'col'+${c}`" :span="getSpan(n, c)">
						<!-- <el-col v-for="c in COLUMN_PER_ROW" :key="`${n}+'col'+${c}`" :span="24 / COLUMN_PER_ROW"> -->
						<!-- :class="{ 'hidden-input': configs.fields[(n - 1) * COLUMN_PER_ROW + (c - 1)].hidden }" -->
						<el-form-item
							v-if="configs.fields[(n - 1) * COLUMN_PER_ROW + (c - 1)]"
							:prop="configs.fields[(n - 1) * COLUMN_PER_ROW + (c - 1)].name"
							:key="`${n}-col-${c}-item`"
							:label="getLabel(n, c)">
							<!-- 暂时先不实现部分输入方式 -->
							<el-input
								v-if="getType(n, c) === 'input'"
								:placeholder="getPlaceholder(n, c)"
								v-model="dataForm[configs.fields[(n - 1) * COLUMN_PER_ROW + (c - 1)].name]"
								clearable
								:disabled="isDetail" />
							<el-radio v-if="getType(n, c) === 'radio'" v-model="dataForm[configs.fields[(n - 1) * COLUMN_PER_ROW + (c - 1)].name]" :disabled="isDetail" />
							<el-checkbox v-if="getType(n, c) === 'check'" v-model="dataForm[configs.fields[(n - 1) * COLUMN_PER_ROW + (c - 1)].name]" :disabled="isDetail" />
							<el-select
								v-if="getType(n, c) === 'select'"
								:placeholder="getPlaceholder(n, c)"
								v-model="dataForm[configs.fields[(n - 1) * COLUMN_PER_ROW + (c - 1)].name]"
								clearable
								:disabled="isDetail"
								@change="emitSelectChange(configs.fields[(n - 1) * COLUMN_PER_ROW + (c - 1)].name, $event)">
								<el-option v-for="opt in configs.fields[(n - 1) * COLUMN_PER_ROW + (c - 1)].options" :key="opt.label + Math.random()" :label="opt.label" :value="opt.value" />
							</el-select>
							<el-switch v-if="getType(n, c) === 'switch'" v-model="dataForm[configs.fields[(n - 1) * COLUMN_PER_ROW + (c - 1)].name]" :disabled="isDetail" />
							<el-cascader
								v-if="getType(n, c) === 'cascader'"
								v-model="dataForm[configs.fields[(n - 1) * COLUMN_PER_ROW + (c - 1)].name]"
								:options="configs.fields[(n - 1) * COLUMN_PER_ROW + (c - 1)].options"
								:props="configs.fields[(n - 1) * COLUMN_PER_ROW + (c - 1)].props"
								:disabled="isDetail"
								clearable />
							<el-time-select v-if="getType(n, c) === 'time'" v-model="dataForm[configs.fields[(n - 1) * COLUMN_PER_ROW + (c - 1)].name]" :disabled="isDetail" />
							<el-date-picker
								v-if="getType(n, c) === 'date'"
								v-bind="configs.fields[(n - 1) * COLUMN_PER_ROW + (c - 1)].props"
								:placeholder="getPlaceholder(n, c)"
								v-model="dataForm[configs.fields[(n - 1) * COLUMN_PER_ROW + (c - 1)].name]"
								:disabled="isDetail" />
						</el-form-item>
					</el-col>
				</el-row>

				<!-- extra components , like Markdown or RichEdit -->
				<template v-if="configs.extraComponents && configs.extraComponents.length > 0">
					<el-form-item v-for="(ec, index) in configs.extraComponents" :key="ec.name + index" :label="ec.label" class="extra-components">
						<component
							style="margin-top: 40px"
							v-if="ec.hasModel"
							:is="ec.component"
							v-bind="ec.props"
							v-model="dataForm[ec.name]"
							@ready="handleEditorReady"
							:read-only="isDetail" />
						<!-- <component v-if="ec.hasModel" :is="ec.component" v-bind="ec.props" v-model="dataForm[ec.name]" /> -->
						<component
							v-else
							:is="ec.component"
							v-bind="ec.props"
							@uploader-update-filelist="handleUploadListUpdate($event, ec.props.extraParams.typeCode)"
							:uploader-inject-file-list="/*用于设备分流的*/ fileList[ec.props.extraParams.typeCode]"
							:read-only="isDetail" />
					</el-form-item>
				</template>
			</el-form>

			<template v-if="dataForm.id && configs.subtable">
				<attr-form :related-id="dataForm.id" v-bind="configs.subtable" :is-detail="isDetail" />
			</template>
		</div>
		<span slot="footer" class="dialog-footer">
			<template v-for="(operate, index) in configs.operations">
				<!-- {{ operate.name | btnNameFilter }} -->
				<el-button
					v-if="
						!isDetail &&
						(operate.showAlways ||
							(((dataForm.id && operate.showOnEdit) || (!dataForm.id && !operate.showOnEdit)) && (operate.permission ? $hasPermission(operate.permission) : true)))
					"
					:key="`operate-${index}`"
					:style="{
						backgroundColor: btnType[operate.name],
						color: btnColor[operate.name]
					}"
					@click="handleClick(operate)"
					>{{ btnName[operate.name] }}</el-button
				>
			</template>
			<el-button v-if="isDetail" @click="handleClick({ name: 'cancel' })">{{ $t('cancel') }}</el-button>
		</span>
	</el-dialog>
</template>

<script>
import CKEditor from 'ckeditor4-vue'
import AttrForm from '../AttrForm'
import { pick } from 'lodash/object'
import { pick as __pick } from '@/utils/filters'
import i18n from '@/i18n'
// 标题 for i18n
const title = {
	detail: i18n.t('detail'),
	add: i18n.t('add'),
	edit: i18n.t('edit')
}

// 或者也可以改造成自定义颜色：
const btnType = {
	add :'#0b58ff',
	save: '#000',
	update: '#0b58ff',
	reset: ''
	// cancel: 'text'
	// add more...
}
const btnColor = {
	save: '#fff',
	update: '#fff',
	reset: ''
	// cancel: 'text'
	// add more...
}

const btnName = {
	// for i18n
	save: i18n.t('save'),
	update: i18n.t('update'),
	reset: i18n.t('reset'),
	cancel: i18n.t('cancel')
	// add more...
}

// 每行的列数
const COLUMN_PER_ROW = 2

export default {
	name: 'AddOrUpdateDialog',
	components: { AttrForm },
	props: {
		configs: {
			type: Object,
			default: () => ({}) // 此处省去类型检查，使用者自行注意就好
		}
	},
	filters: {
		nameFilter: function (name) {
			if (!name) return null
			// for i18n
			const defaultNames = {
				name: i18n.t('name'),
				code: i18n.t('code'),
				remark: i18n.t('remark'),
				description: i18n.t('desc'),
				specifications: i18n.t('prod.spec')
				// add more...
			}

			return defaultNames[name]
		}
	},
	// provide() {
	// 	return {
	// 		_df: this.dataForm
	// 	}
	// },
	data() {
		return {
			COLUMN_PER_ROW,
			title,
			/** 按钮相关属性 */
			btnName,
			btnType,
			btnColor,
			defaultNames: {
				name: i18n.t('name'),
				code: i18n.t('code'),
				remark: i18n.t('remark'),
				description: i18n.t('desc'),
				specifications: i18n.t('prod.spec')
				// add more...
			},
			defaultPlaceholders: {}, // 自动根据 defaultNames 计算得来
			/** 表单相关属性 */
			visible: false,
			isEdit: false,
			isDetail: false,
			dataForm: {},
			dataFormRules: {},
			tempForm: [], // 临时保存自动生成的code，或其他数据
			shouldWait: null,
			fileForm: {}, // 文件上传分流用、合并用的表单，根据 typeCode 进行分流，在请求时合并
			fileList: {} // 文件加载时分流，依据 typeCode
		}
	},
	computed: {
		rows() {
			// 本组件只实现了'一行两列'的表单布局
			return Math.ceil(this.configs.fields.length / COLUMN_PER_ROW)
		}
	},
	created() {
		/** load lang */
		// CKEditor.load()
		// console.log('lang', CKEditor.component.props.config.defaultLanguage = 'en' )
	},
	mounted() {
		/** 计算 defaultPlaceholders */
		const prefix = i18n.t('hints.input')
		Object.entries(this.defaultNames).map(([key, value]) => {
			this.defaultPlaceholders[key] = prefix + value
		})

		/** 转换 configs.fields 的结构，把纯字符串转为对象 */
		this.$nextTick(() => {
			this.configs.fields = this.configs.fields.map((item) => {
				if (typeof item === 'string') {
					return { name: item }
				}
				return item
			})

			/** 动态设置dataForm字段 */
			this.configs.fields.forEach((item) => {
				this.$set(this.dataForm, [item.name], '')

				/** select 的默认值设置 */
				if (item.type === 'select') {
					const opts = item.options || []
					const dft = opts.find((item) => item.default || false)
					if (dft) {
						this.$set(this.dataForm, [item.name], dft.value)
					}
				}

				if (item.api) {
					/** 自动请求并填充 */
					// or this.shouldWaitPool = []
					this.shouldWait = this.$http({
						url: this.$http.adornUrl(item.api),
						method: 'POST' // 也可以改成动态决定
					}).then(({ data: res }) => {
						if (res && res.code === 0) {
							// this.dataForm[item.name] = res.data // <=== 此处需要对接口
							this.tempForm.push({ name: item.name, data: res.data })
						}
					})
				} // end if (item.api)

				// 如果有 relatedField，就需要在当前item的数据加载后，刷新 relatedField 的列表
				if (item.relatedField) {
					this.$watch(
						function () {
							return this.dataForm[item.name]
						},
						function (val, old) {
							if (val && val !== old) {
								this.$emit('select-change', { name: item.name, id: val })
							}
						},
						{ deep: true, immediate: true }
					)
				}

				if (item.required) {
					const requiredRule = {
						required: true,
						message: i18n.t('validate.required'),
						// trigger: 'change'
						trigger: 'blur'
					}
					/** 检查是否已经存在该字段的规则 */
					const exists = this.dataFormRules[item.name] || null
					/** 设置验证规则  */
					if (exists) {
						const unset = true
						for (const rule of exists) {
							if (rule.required) unset = false
						}
						if (unset) {
							exists.push(requiredRule)
						}
					} else {
						/** 不存在已有规则 */
						this.$set(this.dataFormRules, [item.name], [requiredRule])
					}
				} // end if (item.required)

				if (item.rules) {
					const exists = this.dataFormRules[item.name] || null
					if (exists) {
						// 浅拷贝过去
						exists.push(...item.rules)
					} else {
						this.$set(this.dataFormRules, [item.name], [...item.rules])
					}
				} // end if (item.rules)
			})

			/** 计算默认值 */
			function calDefault(type) {
				switch (type) {
					case 'array':
						return []
					// more case...
					default:
						return ''
				}
			}
			/** 检查是否需要额外的组件 */
			this.configs.extraComponents &&
				this.configs.extraComponents.forEach((item) => {
					// if (Object.hasOwn(this.dataForm, [item.name])) {
					if (this.dataForm.hasOwnProperty(item.name)) {
						return
					} else {
						this.$set(this.dataForm, [item.name], calDefault(item.fieldType))
					}
				})

			/** 单独设置 id */
			this.$set(this.dataForm, 'id', null)
		})
	},

	methods: {
		getSpan(n, c) {
			const opt = this.configs.fields[(n - 1) * COLUMN_PER_ROW + (c - 1)]
			return opt && opt.span ? opt.span : 24 / COLUMN_PER_ROW
		},

		getLabel(n, c) {
			const opt = this.configs.fields[(n - 1) * COLUMN_PER_ROW + (c - 1)]
			if (opt) {
				// if opt is valid
				return opt.label ? opt.label : this.defaultNames[opt.name]
			}
		},

		getPlaceholder(n, c) {
			if (this.isDetail) {
				/** 如果是详情，就不展示 提示文本 */
				return ''
			}

			const opt = this.configs.fields[(n - 1) * COLUMN_PER_ROW + (c - 1)]
			if (opt) {
				// if opt is valid
				return opt.placeholder
					? opt.placeholder
					: this.defaultPlaceholders[opt.name]
					? this.defaultPlaceholders[opt.name]
					: opt.label
					? (opt.type === 'select' ? i18n.t('choose') : i18n.t('hints.input')) + opt.label
					: null

				// : opt.type === 'select'
				// ? i18n.t('choose')
				// : '请输入'
			}
		},

		getType(n, c) {
			const opt = this.configs.fields[(n - 1) * COLUMN_PER_ROW + (c - 1)]
			if (opt) {
				if (!opt.type || ['input', 'number' /** add more.. */].includes(opt.type)) {
					return 'input'
				} else if (['select' /** add more.. */].includes(opt.type)) {
					return 'select'
				} else if (['cascader'].includes(opt.type)) {
					return 'cascader'
				} else if (['date'].includes(opt.type)) {
					return 'date'
				}
				// add more...
			} else {
				return 'input'
			}
		},

		init(id, isdetail = false) {
			this.isDetail = isdetail
			this.visible = true
			this.$nextTick(() => {
				this.$refs['dataForm'].resetFields()
				this.dataForm.id = id || null
				if (this.dataForm.id) {
					this.$http({
						url: this.$http.adornUrl(`${this.configs.infoUrl}/${this.dataForm.id}`),
						method: 'get'
					}).then(({ data: res }) => {
						if (res && res.code === 0) {
							const dataFormKeys = Object.keys(this.dataForm)
							console.log('keys ===> ', dataFormKeys)
							// console.log('data form keys: ', dataFormKeys, pick(res.data, dataFormKeys))
							this.dataForm = __pick(res.data, dataFormKeys)
							console.log('pick(res.data, dataFormKeys) ===> ', __pick(res.data, dataFormKeys))
							// LABEL: FILE_RELATED
							/** 对文件下载进行分流 */
							this.fileList = {}
							if (this.dataForm.files) {
								// console.log('files: ', this.dataForm.files)
								this.dataForm.files.forEach((file) => {
									// const fileName = file.fileUrl.split('/').pop()
									/** [1] 处理 fileList */
									// if (Object.hasOwn(this.fileList, file.typeCode)) {
									if (this.fileList.hasOwnProperty(file.typeCode)) {
										/** 已存在 */
										// this.fileList[file.typeCode].push({ id: file.id, name: fileName, typeCode: file.typeCode })
										this.fileList[file.typeCode].push(file)
									} else {
										// this.fileList[file.typeCode] = [{ id: file.id, name: fileName, typeCode: file.typeCode }]
										this.fileList[file.typeCode] = [file]
									}

									/** [2] 处理 fileForm */
									// if (Object.hasOwn(this.fileForm, file.typeCode)) {
									if (this.fileForm.hasOwnProperty(file.typeCode)) {
										this.fileForm[file.typeCode].push(file.id)
									} else {
										this.fileForm[file.typeCode] = [file.id]
									}
								})
							}
						}
					})
				} else {
					/** 如果不是编辑，就填充自动生成的数据 */
					if (this.shouldWait)
						this.shouldWait.then(() => {
							if (this.tempForm.length) {
								// console.log('create new, tempform', JSON.stringify(this.tempForm.length))
								this.tempForm.forEach((item) => {
									// console.log('item data', item.data)
									this.dataForm[item.name] = item.data
								})
								// console.log('create new, dataform', JSON.stringify(this.dataForm))
							}
							this.shouldWait = null
						})
				}
			})
		},

		emitSelectChange(name, id) {
			const currentField = this.configs.fields.find((item) => item.name === name)
			if (currentField.relatedField) {
				this.dataForm[currentField.relatedField] = null
			}
			this.$emit('select-change', { name, id })
		},

		handleEditorReady(val) {},

		handleClick(btn) {
			/** 提取url */
			const urls = {}
			this.configs.operations.map((item) => {
				urls[item.name] = {}
				urls[item.name].url = item.url
				urls[item.name].extraFields = item.extraFields || {}
			})
			/** 操作 */
			switch (btn.name) {
				case 'save':
				case 'update':
					/** 需要验证表单的操作 */
					this.$refs['dataForm'].validate((valid) => {
						if (valid) {
							/** 对于文件上传的单独处理（合并处理） */
							if (Object.keys(this.fileForm).length) {
								// LABEL: FILE_RELATED
								let fileIds = []
								for (const [key, item] of Object.entries(this.fileForm)) {
									if (Array.isArray(item)) {
										fileIds = fileIds.concat(item)
									} else {
										console.error('handleClick(): 上传文件数组类型不正确')
									}
								}
								this.$set(this.dataForm, 'fileIds', fileIds)
							}

							console.log('before send: ', this.dataForm)

							this.$http({
								url: this.$http.adornUrl(urls[btn.name].url),
								method: btn.name === 'save' ? 'POST' : 'PUT',
								data: { ...this.dataForm, ...urls[btn.name].extraFields }
							})
								.then(({ data: res }) => {
									if (res && res.code === 0) {
										this.$message({
											message: i18n.t('prompt.success'),
											// message: btn.name === 'save' ? i18n.t('prompt.success') : '更新成功!',
											type: 'success',
											duration: 1500,
											onClose: () => {
												this.$emit('refreshDataList')
												this.visible = false
											}
										})
									} else {
										this.$message.error(res.msg)
									}
								})
								.catch((err) => {
									this.$message({
										message: err,
										type: 'error',
										duration: 2000
									})
								})
						}
					})
					return
				case 'reset':
					for (const key of Object.keys(this.dataForm)) {
						if (typeof this.dataForm[key] === 'string') {
							this.dataForm[key] = ''
						} else if (this.dataForm[key] instanceof Array) {
							this.dataForm[key].splice(0)
						} else {
							this.dataForm[key] = null
						}
					}
					break
				case 'cancel':
					this.handleClose()
				// add more..
			}
		},

		// LABEL: FILE_RELATED
		handleUploadListUpdate(filelist, typeCode = 'DefaultTypeCode') {
			// console.log('before handleUploadListUpdate(): ', JSON.parse(JSON.stringify(this.fileForm)))
			// 设备类型 typeCode: EquipmentTypeFile
			// 设备信息 typeCode: EquipmentInfoFile | EquipmentInfoImage

			// 原先写法：直接更新 dataForm 对象，不适用于有多个上传组件的需求
			// this.$set(
			// 	this.dataForm,
			// 	'fileIds',
			// 	filelist.map(item => item.id)
			// )
			// console.log('handleUploadListUpdate(): ', this.dataForm)
			// 现更改为分流写法
			this.$set(
				this.fileForm,
				typeCode,
				filelist.map((item) => item.id)
			)
			// console.log('after handleUploadListUpdate(): ', this.fileForm)
		},

		handleClose() {
			this.$emit('destory-dialog')
			this.visible = false
		}
	}
}
</script>

<style scoped>
.super-flexible-dialog >>> .el-select,
.super-flexible-dialog >>> .el-cascader {
	width: 100%;
}

.super-flexible-dialog >>> ::-webkit-scrollbar {
	width: 4px;
	border-radius: 4px;
	background: #fff;
}

.super-flexible-dialog >>> ::-webkit-scrollbar-thumb {
	width: 4px;
	border-radius: 4px;
	background: #ccc;
}

.super-flexible-dialog >>> .hidden-input {
	display: none;
}
</style>
