<!--
 * @Author: liuJie
 * @Date: 2026-01-25 22:08:04
 * @LastEditors: liuJie
 * @LastEditTime: 2026-01-25 22:24:34
 * @Describe: http设置器
-->
<script lang="ts" setup>
import { watch, ref } from 'vue'
import { Input, IconButton } from '@repo/ui'
import { clone, isEqual } from 'lodash-es'

const props = withDefaults(
	defineProps<{
		data: any
	}>(),
	{
		data: {}
	}
)

const emit = defineEmits<{
	update: [data: unknown]
}>()

const DEFAULT_DATA: Record<string, any> = {
	method: 'GET',
	url: '',
	headers: [],
	params: [],
	bodyType: 'json',
	body: '',
	verifySSL: true,
	timeoutConfig: {
		connect: 8,
		read: 6,
		write: 1
	},
	output: {
		body: '',
		status_code: 200,
		headers: [],
		files: []
	},
	errorConfig: {
		retry: true,
		max_retry: 3,
		retry_delay: 100
	},
	exception: 'none',
	exceptionDefaultValue: {
		body: '',
		status_code: 0,
		headers: '{}'
	}
}

const formData = ref<Record<string, any>>(clone(DEFAULT_DATA))
const formDataItem = { key: '', value: '', type: 'text' }
const defaultItem = { key: '', value: '' }
const headers = ref([{ key: '', value: '' }])
const params = ref([{ key: '', value: '' }])
const body = ref<string | Record<string, any>[]>('')

const normalizeBodyValue = (body: any, bodyType: string) => {
	if (body == null) return ''

	if (typeof body === 'string' || Array.isArray(body)) {
		return body
	}

	if (typeof body === 'object' && 'type' in body && 'data' in body) {
		const sourceType = body.type || bodyType
		const sourceData = Array.isArray(body.data) ? body.data : []

		if (['form-data', 'x-www-form-urlencoded'].includes(sourceType)) {
			return sourceData.map((item: any) => ({
				key: item?.key ?? '',
				value: item?.value ?? '',
				type: item?.type ?? 'text'
			}))
		}

		if (sourceType === 'json' || sourceType === 'raw' || sourceType === 'binary') {
			const value = sourceData?.[0]?.value
			if (typeof value === 'string') {
				return value
			}
			return value != null ? String(value) : ''
		}

		return ''
	}

	try {
		return JSON.stringify(body, null, 2)
	} catch {
		return ''
	}
}

const normalizeIncomingData = (raw: any) => {
	const merged = {
		...clone(DEFAULT_DATA),
		...(raw || {})
	}

	const bodyType = merged.bodyType || raw?.body?.type || 'json'
	const bodyValue = normalizeBodyValue(raw?.body ?? merged.body, bodyType)

	return {
		...merged,
		method: (raw?.method || merged.method || 'GET').toUpperCase(),
		bodyType,
		body: bodyValue,
		headers: raw?.headers || raw?.heads || merged.headers || [],
		verifySSL: raw?.verifySSL ?? raw?.ssl_verify ?? merged.verifySSL,
		timeoutConfig: {
			connect: raw?.timeoutConfig?.connect ?? raw?.timeout_config?.max_connect_timeout ?? 8,
			read: raw?.timeoutConfig?.read ?? raw?.timeout_config?.max_read_timeout ?? 6,
			write: raw?.timeoutConfig?.write ?? raw?.timeout_config?.max_write_timeout ?? 1
		},
		errorConfig: {
			retry: raw?.errorConfig?.retry ?? raw?.retry_config?.retry_enabled ?? true,
			max_retry: raw?.errorConfig?.max_retry ?? raw?.retry_config?.max_retries ?? 3,
			retry_delay: raw?.errorConfig?.retry_delay ?? raw?.retry_config?.retry_interval ?? 100
		}
	}
}

watch(
	() => props.data,
	(newVal) => {
		const normalizedData = normalizeIncomingData(newVal)
		if (!isEqual(normalizedData, formData.value)) {
			formData.value = normalizedData

			headers.value = formData.value.headers?.length
				? [...formData.value.headers, { key: '', value: '' }]
				: [{ key: '', value: '' }]

			params.value = formData.value.params?.length
				? [...formData.value.params, { key: '', value: '' }]
				: [{ key: '', value: '' }]

			if (['form-data', 'x-www-form-urlencoded'].includes(formData.value.bodyType)) {
				const bodyArray = Array.isArray(formData.value.body) ? formData.value.body : []
				const item = formData.value.bodyType === 'form-data' ? formDataItem : defaultItem
				body.value = bodyArray.length ? [...bodyArray, { ...item }] : [{ ...item }]
			} else {
				body.value = typeof formData.value.body === 'string' ? formData.value.body : ''
			}
		}
	},
	{
		deep: true,
		immediate: true
	}
)

const methodOptions = [
	{ label: 'GET', value: 'GET' },
	{ label: 'POST', value: 'POST' },
	{ label: 'PUT', value: 'PUT' },
	{ label: 'DELETE', value: 'DELETE' },
	{ label: 'PATCH', value: 'PATCH' }
]

const bodyTypeOptions = [
	{ label: 'none', value: 'none' },
	{ label: 'form-data', value: 'form-data' },
	{ label: 'x-www-form-urlencoded', value: 'x-www-form-urlencoded' },
	{ label: 'raw', value: 'raw' },
	{ label: 'json', value: 'json' },
	{ label: 'binary', value: 'binary' }
]

const exceptionOptions = [
	{ label: '无', value: 'none' },
	{ label: '默认值', value: 'default_value' },
	{ label: '异常分支', value: 'exception_branch' }
]

watch(
	() => formData.value,
	(value) => {
		emit('update', value)
	},
	{ deep: true }
)

watch(
	() => headers.value,
	(val) => {
		formData.value.headers = val.filter((item) => item.key && item.value)
	}
)

watch(
	() => params.value,
	(val) => {
		formData.value.params = val.filter((item) => item.key && item.value)
	}
)

watch(
	() => body.value,
	(val) => {
		if (typeof val === 'object') {
			val = val.filter((item) => item.key)
		}
		formData.value.body = val
	}
)

const handleAddHeader = (index: number) => {
	if (index === headers.value.length - 1) {
		headers.value.push({ key: '', value: '' })
	}
}

const handleAddParam = (index: number) => {
	if (index === params.value.length - 1) {
		params.value.push({ key: '', value: '' })
	}
}

const handleDeleteHeader = (index: number) => {
	headers.value.splice(index, 1)
	if (headers.value.length === 0) {
		headers.value.push({ key: '', value: '' })
	}
}
const handleDeleteParam = (index: number) => {
	params.value.splice(index, 1)
	if (params.value.length === 0) {
		params.value.push({ key: '', value: '' })
	}
}

const handleChangeBodyType = (type: string) => {
	if (['form-data', 'x-www-form-urlencoded'].includes(type)) {
		const item = type === 'form-data' ? formDataItem : defaultItem

		body.value = [{ ...item }]
		formData.value.body = [{ ...item }]
	} else {
		body.value = ''
		formData.value.body = ''
	}
}

const handleAddBody = (index: number) => {
	if (index !== body.value.length - 1) return
	const item = formData.value.bodyType === 'form-data' ? formDataItem : defaultItem
	if (typeof body.value === 'string') return

	body.value = [...body.value, { ...item }]
}
const handleDeleteBody = (index: number) => {
	if (typeof body.value === 'string') return

	body.value.splice(index, 1)
	if (body.value.length === 0) {
		const item = formData.value.bodyType === 'form-data' ? formDataItem : defaultItem
		body.value = [{ ...item }]
	}
}
</script>

<template>
	<el-scrollbar class="w-full box-border p-12px">
		<el-form label-width="50px">
			<el-form-item label="API" label-position="top">
				<div class="w-full flex gap-8px">
					<el-select
						style="width: 100px"
						:options="methodOptions"
						v-model="formData.method"
						placeholder="请选择"
					>
					</el-select>
					<el-input class="flex-1" v-model="formData.url" placeholder="URL..."></el-input>
				</div>
			</el-form-item>

			<el-form-item label="HEADERS" label-position="top">
				<el-table :data="headers" border>
					<el-table-column align="center" prop="key" label="键">
						<template #default="{ row }">
							<Input v-model="row.key" variant="borderless" placeholder="请输入" />
						</template>
					</el-table-column>
					<el-table-column align="center" prop="value" label="值">
						<template #default="{ row, $index }">
							<div class="relative">
								<Input
									v-model="row.value"
									variant="borderless"
									placeholder="请输入"
									@focus="handleAddHeader($index)"
								/>
								<IconButton
									class="absolute right-0 top-5px"
									icon="ep:delete"
									link
									@click="handleDeleteHeader($index)"
								/>
							</div>
						</template>
					</el-table-column>
				</el-table>
			</el-form-item>

			<el-form-item label="PARAMS" label-position="top">
				<el-table :data="params" border>
					<el-table-column align="center" prop="key" label="键">
						<template #default="{ row }">
							<Input v-model="row.key" variant="borderless" placeholder="请输入" />
						</template>
					</el-table-column>
					<el-table-column align="center" prop="value" label="值">
						<template #default="{ row, $index }">
							<div class="relative">
								<Input
									v-model="row.value"
									variant="borderless"
									placeholder="请输入"
									@focus="handleAddParam($index)"
								/>
								<IconButton
									class="absolute right-0 top-5px"
									icon="ep:delete"
									link
									@click="handleDeleteParam($index)"
								/>
							</div>
						</template>
					</el-table-column>
				</el-table>
			</el-form-item>

			<el-form-item label="BODY" label-position="top">
				<el-radio-group v-model="formData.bodyType" @change="handleChangeBodyType">
					<el-radio v-for="type in bodyTypeOptions" :key="type.value" :value="type.value">{{
						type.label
					}}</el-radio>
				</el-radio-group>
			</el-form-item>

			<div
				v-if="formData.bodyType === 'form-data' || formData.bodyType === 'x-www-form-urlencoded'"
				class="mb-12px"
			>
				<el-table :data="body" border>
					<el-table-column align="center" prop="key" label="键">
						<template #default="{ row }">
							<Input v-model="row.key" variant="borderless" placeholder="请输入" />
						</template>
					</el-table-column>
					<el-table-column
						v-if="formData.bodyType === 'form-data'"
						align="center"
						prop="type"
						label="类型"
					>
						<template #default="{ row }">
							<el-select
								v-model="row.type"
								placeholder="请选择"
								:options="[
									{ label: 'text', value: 'text' },
									{ label: 'file', value: 'file' }
								]"
							/>
						</template>
					</el-table-column>
					<el-table-column align="center" prop="value" label="值">
						<template #default="{ row, $index }">
							<div class="relative">
								<Input
									v-model="row.value"
									variant="borderless"
									placeholder="请输入"
									@focus="handleAddBody($index)"
								/>
								<IconButton
									class="absolute right-0 top-5px"
									icon="ep:delete"
									link
									@click="handleDeleteBody($index)"
								/>
							</div>
						</template>
					</el-table-column>
				</el-table>
			</div>

			<div v-if="['json', 'raw', 'binary'].includes(formData.bodyType)" class="mb-12px">
				<el-input
					v-model="formData.body"
					:type="formData.bodyType != 'binary' ? 'textarea' : ''"
					:placeholder="formData.bodyType != 'binary' ? '请输入' : '请输入变量'"
					:autosize="{ minRows: 5, maxRows: 10 }"
				/>
			</div>

			<el-form-item label="验证SSL证书" label-width="120px" label-position="left">
				<div class="w-full text-right">
					<el-switch v-model="formData.verifySSL"></el-switch>
				</div>
			</el-form-item>

			<el-collapse>
				<el-collapse-item title="超时设置" name="1">
					<el-form-item label="连接超时" label-width="120px" label-position="top">
						<el-input-number
							v-model="formData.timeoutConfig.connect"
							:min="1"
							:max="10"
							controls-position="right"
							style="width: 100%"
							suffix="s"
							placeholder="请输入连接超时"
						></el-input-number>
					</el-form-item>
					<el-form-item label="读取超时" label-width="120px" label-position="top">
						<el-input-number
							v-model="formData.timeoutConfig.read"
							:min="1"
							:max="10"
							controls-position="right"
							style="width: 100%"
							suffix="s"
							placeholder="请输入连接超时"
						></el-input-number>
					</el-form-item>
					<el-form-item label="写入超时" label-width="120px" label-position="top">
						<el-input-number
							v-model="formData.timeoutConfig.write"
							:min="1"
							:max="10"
							controls-position="right"
							style="width: 100%"
							suffix="s"
							placeholder="请输入连接超时"
						></el-input-number>
					</el-form-item>
				</el-collapse-item>
				<el-collapse-item title="输出变量" name="2">
					<ul>
						<li>
							<div>
								<span class="text-#333">body</span>
								<span class="text-#999 ml-8px">string</span>
							</div>
							<div class="text-#666">响应内容</div>
						</li>
						<li>
							<div>
								<span class="text-#333">status_code</span>
								<span class="text-#999 ml-8px">number</span>
							</div>
							<div class="text-#666">响应状态码</div>
						</li>
						<li>
							<div>
								<span class="text-#333">headers</span>
								<span class="text-#999 ml-8px">object</span>
							</div>
							<div class="text-#666">响应头列表JSON</div>
						</li>
						<li>
							<div>
								<span class="text-#333">files</span>
								<span class="text-#999 ml-8px">Array[File]</span>
							</div>
							<div class="text-#666">文件列表</div>
						</li>
					</ul>
				</el-collapse-item>
			</el-collapse>

			<el-form-item label="失败时重试" label-width="120px" label-position="left">
				<div class="w-full text-right">
					<el-switch v-model="formData.errorConfig.retry"></el-switch>
				</div>
			</el-form-item>
			<div v-if="formData.errorConfig.retry" class="flex items-center mb-12px">
				<div class="w-150px text-12px text-gray-500">最大重试次数</div>
				<div class="flex-1 flex items-center gap-8px">
					<el-slider
						v-model="formData.errorConfig.max_retry"
						:max="10"
						:min="1"
						:step="1"
						style="flex: 1"
					></el-slider>
					<el-input-number
						v-model="formData.errorConfig.max_retry"
						:min="1"
						:max="10"
						controls-position="right"
						style="flex: 1"
					></el-input-number>
				</div>
			</div>
			<div v-if="formData.errorConfig.retry" class="flex items-center mb-12px">
				<div class="w-150px text-12px text-gray-500">重试次数间隔时间(ms)</div>
				<div class="flex-1 flex items-center gap-8px">
					<el-slider
						v-model="formData.errorConfig.retry_delay"
						:max="5000"
						:min="100"
						:step="1"
						style="flex: 1"
					></el-slider>
					<el-input-number
						v-model="formData.errorConfig.retry_delay"
						:max="5000"
						:min="100"
						controls-position="right"
						style="flex: 1"
					></el-input-number>
				</div>
			</div>
			<el-form-item label="异常处理" label-width="90px" label-position="left">
				<div class="w-full text-right">
					<el-select
						v-model="formData.exception"
						:options="exceptionOptions"
						style="width: 120px"
					/>
				</div>
			</el-form-item>
			<div v-if="formData.exception === 'default_value'">
				<div class="text-12px text-gray-500">当发生异常时，指定默认数据输出</div>
				<el-form-item label="body" label-position="top">
					<el-input v-model="formData.exceptionDefaultValue.body" type="textarea" rows="3" />
				</el-form-item>
				<el-form-item label="status_code" label-position="top">
					<el-input-number
						controls-position="right"
						v-model="formData.exceptionDefaultValue.status_code"
					/>
				</el-form-item>
				<el-form-item label="headers" label-position="top">
					<el-input v-model="formData.exceptionDefaultValue.headers" type="textarea" rows="5" />
				</el-form-item>
			</div>
			<div v-if="formData.exception === 'exception_branch'">
				<div class="text-12px text-gray-500">请在画布定义异常处理逻辑！</div>
			</div>
		</el-form>
	</el-scrollbar>
</template>
