<script lang="ts" setup>
import { watch, ref } from 'vue'
import { cloneDeep, isEqual } from 'lodash-es'
import { IconButton } from '@repo/ui'
import ErrorHandling from '@/nodes/_base/ErrorHandling.vue'
import RetryConfig from '@/nodes/_base/RetryConfig.vue'
import VarInput from '@/nodes/_base/VarInput.vue'
import { useSetterModel } from '../_shared/useSetterModel'

import type { HttpRequestData } from './index'

const props = defineProps<{
	data: HttpRequestData
}>()

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

const methodOptions = [
	{ label: 'GET', value: 'get' },
	{ label: 'POST', value: 'post' },
	{ label: 'HEAD', value: 'head' },
	{ 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 headers = ref<{ name: string; value: string }[]>([])
const params = ref<{ name: string; value: string }[]>([])
const body = ref<{ key: string; value: string; type: string }[]>([])

const formData = useSetterModel<HttpRequestData>(props, emit)
const dialogVisible = ref(false)

const createEmptyHeader = () => ({ name: '', value: '' })
const createEmptyBody = () => ({ key: '', value: '', type: 'text' })

const isKVBodyType = (type: string) => {
	return type === 'form-data' || type === 'x-www-form-urlencoded'
}

const syncEditorRowsFromFormData = () => {
	const nextHeaders = formData.value.heads.length
		? cloneDeep(formData.value.heads)
		: [createEmptyHeader()]
	if (!isEqual(nextHeaders, headers.value)) {
		headers.value = nextHeaders
	}

	const nextParams = formData.value.params.length
		? cloneDeep(formData.value.params)
		: [createEmptyHeader()]
	if (!isEqual(nextParams, params.value)) {
		params.value = nextParams
	}

	const nextBody =
		formData.value.body.type === 'none'
			? []
			: formData.value.body.data.length
				? cloneDeep(formData.value.body.data)
				: [createEmptyBody()]

	if (!isEqual(nextBody, body.value)) {
		body.value = nextBody
	}
}

watch(
	() => [
		formData.value.heads,
		formData.value.params,
		formData.value.body.type,
		formData.value.body.data
	],
	() => {
		syncEditorRowsFromFormData()
	},
	{
		deep: true,
		immediate: true
	}
)

watch(
	headers,
	(newVal) => {
		const normalized = newVal.filter((item) => item.name || item.value)
		if (!isEqual(normalized, formData.value.heads)) {
			formData.value.heads = normalized
		}
	},
	{ deep: true }
)

watch(
	params,
	(newVal) => {
		const normalized = newVal.filter((item) => item.name || item.value)
		if (!isEqual(normalized, formData.value.params)) {
			formData.value.params = normalized
		}
	},
	{ deep: true }
)

watch(
	body,
	(newVal) => {
		if (formData.value.body.type === 'none') {
			if (formData.value.body.data.length) {
				formData.value.body.data = []
			}
			return
		}

		const normalized = isKVBodyType(formData.value.body.type)
			? newVal.filter((item) => item.key || item.value)
			: [{ key: '', value: newVal[0]?.value || '', type: 'text' }]

		if (!isEqual(normalized, formData.value.body.data)) {
			formData.value.body.data = normalized
		}
	},
	{ deep: true }
)

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

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

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

const handleChangeBodyType = (type: string) => {
	if (type === 'none') {
		body.value = []
	} else {
		body.value = [createEmptyBody()]
	}
}

const handleAddBody = (index: number) => {
	if (index !== body.value.length - 1) return
	body.value.push({ key: '', value: '', type: 'text' })
}
const handleDeleteBody = (index: number) => {
	body.value.splice(index, 1)
	if (body.value.length === 0) {
		body.value.push({ key: '', value: '', type: 'text' })
	}
}

const handleSaveAuthorization = () => {
	dialogVisible.value = false
}
</script>

<template>
	<el-scrollbar class="w-full box-border p-12px">
		<el-form label-width="50px">
			<div class="flex items-center justify-between beautify">
				<label class="text-14px font-bold text-gray-700">API</label>
				<div class="text-10px">
					<IconButton
						link
						icon="lucide:globe-lock"
						class="text-red-500"
						size="small"
						@click="dialogVisible = true"
					>
						<span>鉴权</span>
						<span class="text-gray-700">{{
							formData.authorization.type === 'none' ? '无' : 'API-KEY'
						}}</span>
					</IconButton>
				</div>
			</div>
			<el-form-item label="" label-position="top">
				<div class="w-full flex gap-8px">
					<el-select
						style="width: 100px"
						:options="methodOptions"
						v-model="formData.method"
						placeholder="请选择"
					>
					</el-select>
					<VarInput
						class="flex-1"
						v-model="formData.url"
						placeholder="请输入URL, 输入/选择变量"
					></VarInput>
				</div>
			</el-form-item>

			<div class="flex items-center justify-between beautify">
				<label class="text-14px font-bold text-gray-700">HEADERS</label>
			</div>
			<el-form-item label="" label-position="top">
				<el-table :data="headers" border>
					<el-table-column align="center" prop="name" label="键">
						<template #default="{ row }">
							<VarInput v-model="row.name" variant="borderless" placeholder="输入/时选择变量" />
						</template>
					</el-table-column>
					<el-table-column align="center" prop="value" label="值">
						<template #default="{ row, $index }">
							<div class="relative">
								<VarInput
									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>

			<div class="flex items-center justify-between beautify">
				<label class="text-14px font-bold text-gray-700">PARAMS</label>
			</div>
			<el-form-item label="" label-position="top">
				<el-table :data="params" border>
					<el-table-column align="center" prop="name" label="键">
						<template #default="{ row }">
							<VarInput v-model="row.name" variant="borderless" placeholder="输入/时选择变量" />
						</template>
					</el-table-column>
					<el-table-column align="center" prop="value" label="值">
						<template #default="{ row, $index }">
							<div class="relative">
								<VarInput
									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>

			<div class="flex items-center justify-between beautify">
				<label class="text-14px font-bold text-gray-700">BODY</label>
			</div>
			<el-form-item label="" label-position="top">
				<el-radio-group v-model="formData.body.type" @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.body.type === 'form-data' || formData.body.type === 'x-www-form-urlencoded'"
				class="mb-12px"
			>
				<el-table :data="body" border>
					<el-table-column align="center" prop="key" label="键">
						<template #default="{ row }">
							<VarInput v-model="row.key" variant="borderless" placeholder="输入/时选择变量" />
						</template>
					</el-table-column>
					<el-table-column
						v-if="formData.body.type === '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">
								<VarInput
									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.body.type)" class="mb-12px">
				<VarInput
					v-model="formData.body.data[0]!.value"
					:rows="3"
					variant="borderless"
					placeholder="输入/时选择变量"
				/>
			</div>

			<el-form-item label="" label-position="top">
				<div class="w-full flex items-center justify-between">
					<div class="flex items-center justify-between beautify">
						<label class="text-14px font-bold text-gray-700">验证SSL证书</label>
					</div>
					<el-switch v-model="formData.ssl_verify"></el-switch>
				</div>
			</el-form-item>

			<el-collapse>
				<el-collapse-item title="" name="1">
					<template #title>
						<div class="flex items-center justify-between beautify">
							<label class="text-14px font-bold text-gray-700">超时设置</label>
						</div>
					</template>
					<el-form-item label="最大连接超时（以秒为单位）" label-width="120px" label-position="top">
						<el-input-number
							v-model="formData.timeout_config.max_connect_timeout"
							: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.timeout_config.max_read_timeout"
							:min="1"
							:max="600"
							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.timeout_config.max_write_timeout"
							:min="1"
							:max="600"
							controls-position="right"
							style="width: 100%"
							suffix="s"
							placeholder="请输入连接超时"
						></el-input-number>
					</el-form-item>
				</el-collapse-item>
				<el-collapse-item title="" name="2">
					<template #title>
						<div class="flex items-center justify-between beautify">
							<label class="text-14px font-bold text-gray-700">输出变量</label>
						</div>
					</template>
					<ul>
						<li v-for="output in formData.outputs" :key="output.name">
							<div>
								<span class="text-#333">{{ output.name }}</span>
								<span class="text-#999 ml-8px">{{ output.type }}</span>
							</div>
							<div class="text-#666">{{ output.describe }}</div>
						</li>
					</ul>
				</el-collapse-item>
			</el-collapse>

			<el-form-item label="" label-position="top">
				<div class="w-full">
					<RetryConfig v-model="formData.retry_config" />
				</div>
			</el-form-item>

			<el-form-item label="" label-position="top">
				<div class="w-full">
					<ErrorHandling
						v-model:error_strategy="formData.error_strategy"
						v-model:default_value="formData.default_value"
						:outputs="formData.outputs"
					/>
				</div>
			</el-form-item>
		</el-form>
	</el-scrollbar>

	<el-dialog v-model="dialogVisible" title="鉴权设置" append-to-body>
		<el-form label-position="top">
			<el-form-item label="鉴权类型">
				<el-radio-group v-model="formData.authorization.type">
					<el-radio-button value="none">无</el-radio-button>
					<el-radio-button value="api-key">API-KEY</el-radio-button>
				</el-radio-group>
			</el-form-item>
			<el-form-item v-if="formData.authorization.type === 'api-key'" label="类型">
				<el-radio-group v-model="formData.authorization.config.type">
					<el-radio-button value="basic">Basic</el-radio-button>
					<el-radio-button value="bearer">Bearer</el-radio-button>
					<el-radio-button value="custom">自定义</el-radio-button>
				</el-radio-group>
			</el-form-item>
			<el-form-item v-if="formData.authorization.config.type === 'custom'" label="headers">
				<el-input v-model="formData.authorization.config.header" placeholder="请输入" />
			</el-form-item>
			<el-form-item v-if="formData.authorization.type === 'api-key'" label="API-KEY">
				<el-input v-model="formData.authorization.config.api_key" placeholder="请输入" />
			</el-form-item>
		</el-form>
		<template #footer>
			<el-button @click="dialogVisible = false">取消</el-button>
			<el-button type="primary" @click="handleSaveAuthorization">保存</el-button>
		</template>
	</el-dialog>
</template>

<style scoped>
:deep(.el-collapse-item__header) {
	padding-left: 0 !important;
}
</style>
