<template>
	<a-form-item :label="props.label" :name="props.name" :rules="props.rules">
		<!-- ----------------------------------------------------- -->

		<!--自动完成框-->
		<!--		:value="props.value" -->
		<a-auto-complete
			v-if="props.type === 'auto-complete'"
			v-model:value="modelValue"
			:filterOption="(input, option) => filterOption(input, option, item?.fieldNames)"
			:placeholder="props.placeholder || '请输入' + props.label"
			v-bind="props.typeValue"
			@select="emitAutoCompleteProps"
		/>

		<!-- ----------------------------------------------------- -->

		<!--级联选择器-->
		<a-cascader
			v-else-if="props.type === 'cascader'"
			v-model:value="modelValue"
			:placeholder="props.placeholder || '请选择' + props.label"
			v-bind="props.typeValue"
			@change="emitCascaderProps"
		/>

		<!-- ----------------------------------------------------- -->

		<!--复选框-->
		<a-checkbox v-else-if="props.type === 'checkbox'" v-model:checked="modelValue">
			{{ props?.typeValue?.label }}
		</a-checkbox>

		<!--复选框组-->
		<a-checkbox-group v-else-if="props.type === 'checkbox-group'" v-model:value="modelValue" v-bind="props.typeValue" />

		<!--单选框-->
		<a-radio v-else-if="props.type === 'radio'" v-model:checked="modelValue">
			{{ props?.typeValue?.label }}
		</a-radio>

		<!--单选按钮-->
		<a-radio-button v-else-if="props.type === 'radio-button'" v-model:checked="modelValue">
			{{ props?.typeValue?.label }}
		</a-radio-button>

		<!--单选框组-->
		<a-radio-group v-else-if="props.type === 'radio-group'" v-model:value="modelValue" v-bind="props.typeValue" />

		<!-- ----------------------------------------------------- -->

		<!-- 日期选择框-->
		<a-date-picker
			v-else-if="props.type === 'date-picker'"
			v-model:value="modelValue"
			:placeholder="props.placeholder || '请选择' + props.label"
			:valueFormat="props.typeValue?.valueFormat || 'YYYY-MM-DD'"
			style="width: 100%"
			v-bind="props.typeValue"
		/>

		<!--时间段选择-->
		<a-range-picker
			v-else-if="props.type === 'range-picker'"
			v-model:value="modelValue"
			:placeholder="props.placeholder || '请选择' + props.label"
			:valueFormat="props.typeValue?.valueFormat || 'YYYY-MM-DD'"
			v-bind="props.typeValue"
		/>

		<!-- ----------------------------------------------------- -->

		<!--输入框-->
		<a-input
			v-else-if="props.type === 'input'"
			v-model:value="modelValue"
			:placeholder="props.placeholder || '请输入' + props.label"
			v-bind="props.typeValue"
		/>

		<!-- 数字输入框-->
		<a-input-number
			v-else-if="props.type === 'input-number'"
			v-model:value="modelValue"
			:placeholder="props.placeholder || '请输入' + props.label"
			style="width: 100%"
			v-bind="props.typeValue"
		/>

		<!--文本域-->
		<a-textarea
			v-else-if="props.type === 'textarea'"
			v-model:value="modelValue"
			:placeholder="props.placeholder || '请输入' + props.label"
			v-bind="props.typeValue"
		/>

		<!-- ----------------------------------------------------- -->

		<!--评分选择器-->
		<a-rate
			v-else-if="props.type === 'rate'"
			v-model:value="modelValue"
			:placeholder="props.placeholder || '请选择' + props.label"
			v-bind="props.typeValue"
		/>

		<!-- ----------------------------------------------------- -->

		<!--选择框-->
		<a-select
			v-else-if="props.type === 'select'"
			v-model:value="modelValue"
			:placeholder="props.placeholder || '请选择' + props.label"
			:filterOption="(input, option) => filterOption(input, option, item?.fieldNames)"
			v-bind="props.typeValue"
			@change="emitSelectProps"
		/>

		<!-- ----------------------------------------------------- -->

		<!--选择框-->
		<a-slider
			v-else-if="props.type === 'slider'"
			v-model:value="modelValue"
			:placeholder="props.placeholder || '请选择' + props.label"
			v-bind="props.typeValue"
		/>

		<!-- ----------------------------------------------------- -->

		<!--开关-->
		<a-switch
			v-else-if="props.type === 'switch'"
			v-model:checked="modelValue"
			:placeholder="props.placeholder || '请选择' + props.label"
			v-bind="props.typeValue"
		/>

		<!-- ----------------------------------------------------- -->

		<!-- 时间选择框-->
		<a-time-picker
			v-else-if="props.type === 'time-picker'"
			v-model:value="modelValue"
			:placeholder="props.placeholder || '请选择' + props.label"
			:valueFormat="props.typeValue?.valueFormat || 'HH:mm:ss'"
			v-bind="props.typeValue"
		/>

		<!--日期选择-->
		<a-time-range-picker
			v-else-if="props.type === 'time-range-picker'"
			v-model:value="modelValue"
			:placeholder="props.placeholder || '请选择' + props.label"
			:valueFormat="props.typeValue?.valueFormat || 'HH:mm:ss'"
			v-bind="props.typeValue"
		/>

		<!-- ----------------------------------------------------- -->

		<!--上传-->
		<!--		<base-upload-->
		<!--			v-else-if="props.type === 'upload'"-->
		<!--			:btnText="props.placeholder"-->
		<!--			:placeholder="props.placeholder"-->
		<!--			:uploadAccept="props.typeValue?.accept"-->
		<!--			:uploadList="props.typeValue?.fileList"-->
		<!--			:uploadMaxSize="props.typeValue?.count"-->
		<!--			@removeSuccess="uploadSuccess"-->
		<!--			@uploadSuccess="uploadSuccess"-->
		<!--		/>-->

		<a-tree-select
			v-else-if="props.type === 'tree-select'"
			v-model:value="modelValue"
			:placeholder="props.placeholder || '请选择' + props.label"
			v-bind="props.typeValue"
			@change="emitTreeSelectProps"
		/>

		<!-- 这句必须放在最后面-->
		<!--v-model:file-list="fileList"-->
		<a-upload
			v-else-if="props.type === 'upload'"
			:action="action"
			:before-upload="beforeUpload"
			:headers="headers"
			list-type="picture-card"
			v-bind="props.typeValue"
			@change="uploadChange"
			@preview="handlePreview"
			v-model:file-list="fileList"
		>
			<div v-if="fileList.length < (props.typeValue?.maxCount ?? 9)">
				<plus-outlined />
				<div style="margin-top: 8px">{{ props.placeholder || '上传文件' }}</div>
			</div>
		</a-upload>

		<!--富文本-->
		<rich-text v-else-if="props.type === 'rich-text'" v-model:value="modelValue" />

		<!--图片预览-->
		<!--		<a-modal-->
		<!--			v-if="props.type === 'upload'"-->
		<!--			:footer="null"-->
		<!--			:title="preview.title"-->
		<!--			:visible="preview.visible"-->
		<!--			:z-index="99999"-->
		<!--			@cancel="preview.visible = false"-->
		<!--		>-->
		<!--			<img :src="preview.image" alt="preview" style="width: 100%" />-->
		<!--		</a-modal>-->
		<a-image
			v-if="props.type === 'upload'"
			:preview="{
				visible: preview.visible,
				onVisibleChange: visible => {
					preview.visible = visible
				}
			}"
			:src="preview.image"
			:style="{ display: 'none' }"
		/>
	</a-form-item>
</template>

<script lang="ts" setup>
import { PlusOutlined } from '@ant-design/icons-vue'
import {
	AutoCompleteExtraProps,
	AutoCompleteProps,
	CascaderExtraProps,
	CascaderProps,
	CheckboxGroupProps,
	ExtraProps,
	ExtraTypeProps,
	FieldType,
	OptionKeys,
	OptionProps,
	RulesProps,
	SelectExtraProps,
	SelectProps,
	TreeSelectCheckExtraProps,
	TreeSelectExtraProps,
	TreeSelectProps,
	TypeValue,
	UploadExtraProps,
	UploadFile,
	UploadProps
} from './field-props'
import { computed, defineAsyncComponent, reactive, ref, watch } from 'vue'
import { BaseUtil } from '../../utils/base-util'
import { LogFile } from '../../entity/system-log/log-file'
import { useSystemStore } from '../../store/system'
import { UploadChangeParam } from 'ant-design-vue'
import { ResultModel } from '../../http/result-model'
import { messageMethod } from '../../utils/message-util'

const RichText = defineAsyncComponent(() => import('../rich-text/RichText.vue'))

/**
 * 字段
 */
interface Props {
	name?: string
	type?: FieldType
	typeValue?: TypeValue
	label?: string
	placeholder?: string | Array<string>
	rules?: Array<RulesProps> | RulesProps
	value?: string | number | Array<string> | Array<number> | boolean
	extraNames?: ExtraTypeProps
}

/**
 * 定义属性
 */
const props = withDefaults(defineProps<Props>(), {})

/**
 * 定义事件,v-model语法糖
 */
const emit = defineEmits<{
	(e: 'update:value', change: string | number | Array<string> | Array<number> | boolean | undefined): void
	(e: 'update:extraValue', name: string, extra: ExtraProps): void
}>()

/**
 * 实际使用的值
 */
const modelValue = computed({
	get: () => props.value,
	set: value => {
		emit('update:value', value)
	}
})

/**
 * 过滤选项
 * @param input
 * @param option
 * @param item
 */
function filterOption(input: string, option: OptionProps, item?: OptionKeys) {
	let labelField = item?.label ?? 'label'
	let optionElement = option[labelField]

	return (optionElement as string).includes(input)
}

//------------------------------ 文件上传部分 ---------------------------------------
/**
 * 上传文件部分
 */
const action = import.meta.env.VITE_APP_API_OSS || '/api/logFile/upload'
// 请求头
const systemStore = useSystemStore()
const headers = reactive({
	authToken: systemStore.token,
	submitKey: BaseUtil.uuid()
})

const fileList = ref<Array<UploadFile>>([])
watch(
	() => (props.typeValue as UploadProps)?.fileList,
	() => {
		if (props.type != 'upload') return

		const propsList = (props.typeValue as UploadProps)?.fileList
		fileList.value = propsFile2FileList(propsList)
	},
	{ deep: true, immediate: true }
)
/**
 * 观察文件列表，用于回值
 */
watch(
	fileList,
	() => {
		if (props.type != 'upload') return
		const typeValue = props.typeValue as UploadProps
		// 获取需要文件类型
		const type = typeValue?.type

		let doneFile = fileList.value.filter(value => value.status == 'done').map(value => value.response?.data)

		// 要返回的数据
		let ids = doneFile.map(value => value?.id).join(',')
		let urls = doneFile.map(value => value?.uploadPath || value?.filePath).join(',')

		if (type == 'url') {
			emit('update:value', urls)
		} else {
			emit('update:value', ids)
		}

		let extraNames = (typeValue?.extraNames || props.extraNames) as UploadExtraProps

		let extra: { [key: string]: string | OptionProps | Array<OptionProps> } = {}
		// 获取额外字段key,按需添加
		if (extraNames) {
			if (extraNames?.id) {
				extra[extraNames?.id] = ids
			}
			if (extraNames?.url) {
				extra[extraNames?.url] = urls
			}
		} else {
			extra.id = ids
			extra.url = urls
		}
		emit('update:extraValue', props.name ?? '', extra)
	},
	{ immediate: true }
)

/**
 * 实体类转化， 统一使用antdv的上传格式
 * @param fileList
 */
function propsFile2FileList(fileList?: Array<LogFile>): Array<UploadFile> {
	if (fileList && fileList.length >= 0)
		// 构建file list 数据
		return fileList.map(value => {
			const uploadData = <UploadFile>{ uid: value.id, status: 'done' }
			uploadData.url = BaseUtil.getUploadPath(value.uploadPath || value.filePath || value.url)
			uploadData.response = { data: value, code: '00000', message: '', t: '' }
			return uploadData
		})
	else return []
}

// 预览需要的字段
interface PreviewProps {
	image?: string
	visible?: boolean
	title?: string
}

//预览
const preview = ref<PreviewProps>({})

async function handlePreview(file: UploadFile) {
	preview.value.image = file.url || BaseUtil.getUploadPath(file.response?.data?.uploadPath)
	preview.value.title = file.name || file.response?.data?.oldFileName || file.url?.substring(file.url.lastIndexOf('/') + 1)
	preview.value.visible = !!preview.value.image && true

	if (!preview.value.image) {
		messageMethod.error('图片预览失败，请检查图片是否存在')
	}
}

/**
 *
 * @param file
 */
async function beforeUpload(file: UploadFile): Promise<boolean> {
	const typeValue = props.typeValue as UploadProps
	let maxSize = typeValue?.maxSize ?? 10 * 1024 * 1024
	if (file.size > maxSize) {
		let tipSizeM = BaseUtil.getFileSize(maxSize)
		messageMethod.error(`文件大小不能超过${tipSizeM}`)
		file.status = 'error'
		return false
	}

	return true
}

/**
 * 文件上传状态改变， 在这里回传数据
 * @param file 当前文件对象
 * @param newFileList 文件列表对象
 */
const uploadChange = ({ file, fileList }: UploadChangeParam<UploadFile>) => {
	switch (file.status) {
		case 'done':
			if (file.response?.data) {
				file.uid = file.response?.data.id || file.uid
				file.url = BaseUtil.getUploadPath(file.response?.data?.uploadPath)
			} else {
				file.status = 'error'
			}

			break
		case 'error':
			// 更新错误信息，否则移上去会显示html code
			file.error = ''
			file.response = <ResultModel<LogFile>>{ code: '' }
			break
	}
}
//------------------------------ 文件上传部分结束 ---------------------------------------

//------------------------------ 额外回显字段处理 ---------------------------------------
/**
 * 自动完成框回显
 * @param value
 * @param option
 */
function emitAutoCompleteProps(value: string, option: OptionProps) {
	// 自动完成
	let typeValue = props.typeValue as AutoCompleteProps
	option = option as OptionProps

	let extraNames = (typeValue?.extraNames || props.extraNames) as AutoCompleteExtraProps
	const field = typeValue?.fieldNames
	const fieldLabel = field?.label || 'label'
	const fieldValue = field?.value || 'value'

	let extra: { [key: string]: string | OptionProps | Array<OptionProps> } = {}
	// 获取额外字段key,按需添加
	if (extraNames) {
		if (extraNames?.label) {
			extra[extraNames?.label] = option[fieldLabel] as string
		}
		if (extraNames?.value) {
			extra[extraNames?.value] = option[fieldValue] as string
		}
		if (extraNames?.option) {
			extra[extraNames?.option] = option
		}
	} else {
		extra.label = option[fieldLabel] as string
		extra.value = option[fieldValue] as string
		extra.option = option
	}
	emit('update:extraValue', props.name ?? '', extra)
}

/**
 * 级联数据回显
 * @param value
 * @param optionProps
 */
function emitCascaderProps(value: string, optionProps: Array<OptionProps>) {
	// 级联选择
	let typeValue = props.typeValue as CascaderProps
	const field = typeValue?.fieldNames
	const fieldLabel = field?.label || 'label'
	const fieldValue = field?.value || 'value'

	const labels = optionProps.map(item => item[fieldLabel] as string)
	const values = optionProps.map(item => item[fieldValue] as string)

	let extraNames = (typeValue?.extraNames || props.extraNames) as CascaderExtraProps
	let extra: { [key: string]: string | OptionProps | Array<OptionProps> } = {}
	// 获取额外字段key,按需添加
	if (extraNames) {
		if (extraNames?.label) {
			extra[extraNames?.label] = labels?.join('/') ?? ''
		}
		if (extraNames?.value) {
			extra[extraNames?.value] = values?.join(',') ?? ''
		}
		if (extraNames?.option) {
			extra[extraNames?.option] = optionProps.slice(-1)[0] ?? {}
		}
		if (extraNames?.options) {
			extra[extraNames?.options] = optionProps
		}
	} else {
		extra.label = labels?.join('/') ?? ''
		extra.value = values?.join(',') ?? ''
		extra.option = optionProps.slice(-1)[0] ?? {}
		extra.options = optionProps
	}
	emit('update:extraValue', props.name ?? '', extra)
}

/**
 * 选择数据回显
 * @param value
 * @param optionProps
 */
function emitSelectProps(value: string, optionProps: Array<OptionProps> | OptionProps) {
	// 选择
	let typeValue = props.typeValue as SelectProps
	const field = typeValue?.fieldNames
	const fieldLabel = field?.label || 'label'
	const fieldValue = field?.value || 'value'

	if (!(optionProps instanceof Array)) {
		optionProps = [optionProps]
	}

	const labels = optionProps.map(item => item[fieldLabel] as string)
	const values = optionProps.map(item => item[fieldValue] as string)

	let extraNames = (typeValue?.extraNames || props.extraNames) as SelectExtraProps

	let extra: { [key: string]: string | Array<OptionProps> } = {}
	// 获取额外字段key,按需添加
	if (extraNames) {
		if (extraNames?.label) {
			extra[extraNames?.label] = labels?.join(',') ?? ''
		}
		if (extraNames?.value) {
			extra[extraNames?.value] = values?.join(',') ?? ''
		}
		if (extraNames?.options) {
			extra[extraNames?.options] = optionProps
		}
	} else {
		extra.label = labels?.join(',') ?? ''
		extra.value = values?.join(',') ?? ''
		extra.options = optionProps
	}
	emit('update:extraValue', props.name ?? '', extra)
}

/**
 * 树级选择起
 * @param value
 * @param label
 * @param extra
 */
function emitTreeSelectProps(value: string | Array<string>, label: Array<string>, extra: TreeSelectCheckExtraProps) {
	// 选择
	let typeValue = props.typeValue as TreeSelectProps
	const field = typeValue?.fieldNames

	let extraNames = (typeValue?.extraNames || props.extraNames) as TreeSelectExtraProps

	let extraValue: { [key: string]: string | Array<OptionProps> } = {}

	if (!(value instanceof Array)) {
		value = [value]
	}

	// 获取额外字段key,按需添加
	if (extraNames) {
		if (extraNames?.label) {
			extraValue[extraNames?.label] = label?.join(',') ?? ''
		}
		if (extraNames?.value) {
			extraValue[extraNames?.value] = value?.join(',') ?? ''
		}
	} else {
		extraValue.label = label?.join(',') ?? ''
		extraValue.value = value?.join(',') ?? ''
	}

	emit('update:extraValue', props.name ?? '', extraValue)
	// let options = extra.allCheckedNodes?.map(value => ({...value.node?.props, position: value.pos}))
}

/**
 * 回显额外字段
 * upload：【id,url】
 * cascader：【label,value,option,options】
 * @param value
 * @param option
 */
function emitExtraProps(
	value: string | number | Array<string> | Array<number> | boolean | OptionProps | Array<OptionProps> | undefined,
	option?: OptionProps | Array<OptionProps>
) {
	if (props.type == 'checkbox-group') {
		// 选择
		let typeValue = props.typeValue as CheckboxGroupProps
		const options = typeValue?.options
	}
}
</script>

<script lang="ts">
export default {
	name: 'BaseFormItem'
}
</script>

<style scoped></style>
