<template>
	<div class="management-page">
		<div class="page-head">
			<div>
				<h1>{{ t('pages.webSearch.title') }}</h1>
				<p>{{ t('pages.webSearch.subtitle') }}</p>
			</div>
		</div>

		<el-card class="list-card">
			<div class="toolbar mb-16px">
				<div class="toolbar-left">
					<el-input
						v-model="keyword"
						clearable
						:placeholder="t('pages.webSearch.searchPlaceholder')"
						class="search-input"
						@keyup.enter="loadList(1)"
					>
						<template #prefix>
							<el-icon>
								<Search />
							</el-icon>
						</template>
					</el-input>
					<el-select
						v-model="provider"
						clearable
						:placeholder="t('pages.webSearch.provider')"
						style="width: 180px"
						@change="loadList(1)"
					>
						<el-option
							v-for="item in engineOptions"
							:key="item.id"
							:label="item.name"
							:value="item.id"
						/>
					</el-select>
					<div class="toolbar-actions">
						<el-button type="primary" @click="loadList(1)">
							<el-icon><Search /></el-icon>
							{{ t('pages.webSearch.query') }}
						</el-button>
						<el-button @click="handleReset">
							<el-icon><RefreshRight /></el-icon>
							{{ t('common.reset') }}
						</el-button>
					</div>
				</div>
				<div class="toolbar-right">
					<el-button v-permission="'add'" type="primary" @click="openCreate">
						<el-icon>
							<Plus />
						</el-icon>
						{{ t('pages.webSearch.createWebSearch') }}
					</el-button>
				</div>
			</div>

			<div v-loading="loading" class="grid">
				<el-empty
					v-if="!list.length && !loading"
					class="empty"
					:description="t('pages.webSearch.noWebSearch')"
				/>
				<div v-for="row in list" :key="row.id" class="card">
					<div class="card-head">
						<div class="flex items-center justify-between">
							<div class="title">{{ row.name || t('pages.webSearch.unnamedWebSearch') }}</div>
							<div class="actions" @click.stop>
								<el-dropdown>
									<span class="actions-trigger">
										<el-icon>
											<MoreFilled />
										</el-icon>
									</span>
									<template #dropdown>
										<el-dropdown-menu>
											<el-dropdown-item @click="openEditById(row.id)">
												<span v-permission="'edit'">{{ t('common.edit') }}</span>
											</el-dropdown-item>
											<el-dropdown-item @click="removeItem(row.id)" divided>
												<span v-permission="'del'" class="danger-text">{{ t('common.delete') }}</span>
											</el-dropdown-item>
										</el-dropdown-menu>
									</template>
								</el-dropdown>
							</div>
						</div>

						<div class="subtitle">{{ getEngineName(row.provider) }}</div>
						<div class="badge-row">
							<span class="badge">{{ getEngineName(row.provider) }}</span>
							<span class="badge subtle">{{
								row.is_default
									? t('pages.webSearch.defaultConfig')
									: t('pages.webSearch.normalConfig')
							}}</span>
						</div>
					</div>

					<div class="card-footer">
						<el-button link type="primary" @click="checkItem(row.id)">{{
							t('pages.webSearch.testConnection')
						}}</el-button>
					</div>
				</div>
			</div>

			<div v-if="pagination.totalCount > 0" class="pagination">
				<el-pagination
					v-model:current-page="pagination.pageIndex"
					v-model:page-size="pagination.pageSize"
					background
					layout="total, prev, pager, next"
					:total="pagination.totalCount"
					@current-change="handlePageChange"
					@size-change="handleSizeChange"
				/>
			</div>
		</el-card>

		<el-drawer
			v-model="drawerVisible"
			:title="
				currentId ? t('pages.webSearch.editWebSearch') : t('pages.webSearch.createWebSearchTitle')
			"
			direction="rtl"
			size="700px"
		>
			<el-form ref="formRef" :model="form" :rules="rules" label-position="top">
				<el-form-item :label="t('pages.webSearch.provider')" prop="provider">
					<el-select v-model="form.provider" style="width: 100%">
						<el-option
							v-for="item in engineOptions"
							:key="item.id"
							:label="item.name"
							:value="item.id"
						/>
					</el-select>
				</el-form-item>
				<el-form-item :label="t('pages.webSearch.name')" prop="name">
					<el-input v-model="form.name" />
				</el-form-item>
				<el-form-item :label="t('pages.webSearch.description')" prop="description">
					<el-input v-model="form.description" type="textarea" :rows="2" />
				</el-form-item>
				<!-- 编辑不需要编辑api_key -->
				<el-form-item v-if="!currentId" label="API Key" prop="parameters.api_key">
					<el-input v-model="form.parameters.api_key" type="password" show-password />
				</el-form-item>
				<el-form-item v-if="currentId">
					<div class="credential-actions">
						<el-button type="primary" plain @click="updateCredentials(currentId)">
							{{ t('pages.webSearch.updateCredential') }}
						</el-button>
						<el-button
							v-if="hasCurrentCredential"
							type="danger"
							plain
							@click="deleteCredentials(currentId)"
						>
							{{ t('pages.webSearch.deleteCredential') }}
						</el-button>
					</div>
				</el-form-item>
				<div class="grid-2">
					<el-form-item :label="t('pages.webSearch.proxyUrl')" prop="parameters.proxy_url">
						<el-input v-model="form.parameters.proxy_url" />
					</el-form-item>
					<el-form-item :label="t('pages.webSearch.engineId')" prop="parameters.engine_id">
						<el-input v-model="form.parameters.engine_id" />
					</el-form-item>
				</div>
				<el-form-item :label="t('pages.webSearch.setDefault')" prop="is_default">
					<el-switch v-model="form.is_default" />
				</el-form-item>
				<el-form-item>
					<div class="check-box">
						<el-button :loading="checkLoading" @click="checkWithParameters">{{
							t('pages.webSearch.testConnection')
						}}</el-button>
						<el-alert
							v-if="checkMessage"
							:title="checkMessage"
							:type="checkSuccess ? 'success' : 'error'"
							:closable="false"
							show-icon
						/>
					</div>
				</el-form-item>
			</el-form>
			<template #footer>
				<div class="drawer-footer">
					<el-button @click="drawerVisible = false">{{ t('common.cancel') }}</el-button>
					<el-button type="primary" :loading="submitLoading" @click="handleSubmit">{{
						t('common.save')
					}}</el-button>
				</div>
			</template>
		</el-drawer>
	</div>
</template>

<script setup lang="ts">
import { onMounted, reactive, ref } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { Plus, Search, MoreFilled, RefreshRight } from '@element-plus/icons-vue'
import { resource } from '@repo/api-service'
import { useI18n } from '@/composables/useI18n'

const { t } = useI18n()

type EngineResponse = Awaited<ReturnType<typeof resource.postWebSearchEngines>>
type EngineItem = NonNullable<EngineResponse['result']>[number]

const keyword = ref('')
const provider = ref('')
const loading = ref(false)
const submitLoading = ref(false)
const checkLoading = ref(false)
const drawerVisible = ref(false)
const currentId = ref('')
const hasCurrentCredential = ref(false)
const checkMessage = ref('')
const checkSuccess = ref(false)
const formRef = ref()

const pagination = reactive({
	pageIndex: 1,
	pageSize: 20,
	totalCount: 0
})

const list = ref<any[]>([])
const engineOptions = ref<EngineItem[]>([])

const hasConfiguredCredential = (credential?: Record<string, { configured?: boolean }>) =>
	Object.values(credential || {}).some((item) => item?.configured === true)

const form = reactive({
	provider: '',
	name: '',
	description: '',
	is_default: false,
	parameters: {
		proxy_url: '',
		api_key: '',
		engine_id: ''
	}
})

const rules = {
	provider: [
		{ required: true, message: t('pages.webSearch.pleaseSelectProvider'), trigger: 'change' }
	],
	name: [{ required: true, message: t('pages.webSearch.pleaseInputName'), trigger: 'blur' }]
}

function resetForm() {
	currentId.value = ''
	hasCurrentCredential.value = false
	checkMessage.value = ''
	checkSuccess.value = false
	form.provider = ''
	form.name = ''
	form.description = ''
	form.is_default = false
	form.parameters.proxy_url = ''
	form.parameters.api_key = ''
	form.parameters.engine_id = ''
}

function getEngineName(id?: string) {
	return (
		engineOptions.value.find((item) => item.id === id)?.name ||
		id ||
		t('pages.webSearch.noProvider')
	)
}

async function loadEngines() {
	const res = await resource.postWebSearchEngines({})
	if (res.isSuccess) {
		engineOptions.value = res.result || []
	}
}

async function loadList(pageIndex = 1) {
	loading.value = true
	try {
		const res = await resource.postWebSearchPageList({
			keyword: keyword.value,
			provider: provider.value,
			pageIndex,
			pageSize: pagination.pageSize
		})
		if (res.isSuccess && res.result) {
			list.value = (res.result.model || []) as any[]
			pagination.pageIndex = res.result.currentPage || pageIndex
			pagination.pageSize = res.result.pageSize || pagination.pageSize
			pagination.totalCount = res.result.totalCount || 0
		}
	} finally {
		loading.value = false
	}
}

function handlePageChange(page: number) {
	pagination.pageIndex = page
	loadList(page)
}

function handleSizeChange(size: number) {
	pagination.pageSize = size
	loadList(1)
}

function handleReset() {
	keyword.value = ''
	provider.value = ''
	loadList(1)
}

function openCreate() {
	resetForm()
	drawerVisible.value = true
}

async function openEditById(id: string) {
	const res = await resource.postWebSearchInfo({ id })
	if (!res.isSuccess || !res.result) {
		ElMessage.error(t('pages.webSearch.fetchDetailFailed'))
		return
	}
	resetForm()
	currentId.value = id
	form.provider = res.result.provider || ''
	form.name = res.result.name || ''
	form.description = res.result.description || ''
	form.is_default = !!res.result.is_default
	form.parameters.api_key = res.result.parameters?.api_key || ''
	hasCurrentCredential.value = hasConfiguredCredential((res.result as any).credential)
	drawerVisible.value = true
}

async function checkItem(id: string) {
	try {
		const res = await resource.postWebSearchCheckById({ id })
		if (res.isSuccess) {
			ElMessage.success(t('pages.webSearch.connectSuccess'))
		}
	} catch {
		ElMessage.error(t('pages.webSearch.connectFailed'))
	}
}

async function checkWithParameters() {
	checkLoading.value = true
	checkMessage.value = ''
	try {
		if (currentId.value) {
			const res = await resource.postWebSearchCheckById({ id: currentId.value })
			checkSuccess.value = !!res.isSuccess
			checkMessage.value = res.isSuccess
				? t('pages.webSearch.connectSuccess')
				: t('pages.webSearch.connectFailed')
		} else {
			const res = await resource.postWebSearchCheckWithParameters({
				provider: form.provider,
				parameters: {
					api_key: form.parameters.api_key,
					proxy_url: form.parameters.proxy_url,
					engine_id: form.parameters.engine_id
				}
			})
			checkSuccess.value = !!res.isSuccess
			checkMessage.value = res.isSuccess
				? t('pages.webSearch.connectSuccess')
				: t('pages.webSearch.connectFailed')
		}
	} catch {
		checkSuccess.value = false
	} finally {
		checkLoading.value = false
	}
}

async function handleSubmit() {
	await formRef.value?.validate(async (valid: boolean) => {
		if (!valid) return
		submitLoading.value = true
		try {
			const payload = {
				provider: form.provider,
				name: form.name,
				description: form.description,
				is_default: form.is_default,
				parameters: {
					proxy_url: form.parameters.proxy_url,
					api_key: form.parameters.api_key,
					engine_id: form.parameters.engine_id
				}
			}
			if (currentId.value) {
				const res = await resource.postWebSearchUpdate({ id: currentId.value, ...(payload as any) })
				if (!res?.isSuccess) return
				ElMessage.success(t('pages.webSearch.updateSuccess'))
			} else {
				const res = await resource.postWebSearchCreate(payload as any)
				if (!res?.isSuccess) return
				ElMessage.success(t('pages.webSearch.createSuccess'))
			}
			drawerVisible.value = false
			loadList(pagination.pageIndex)
		} catch {
			ElMessage.error(t('pages.webSearch.saveFailed'))
		} finally {
			submitLoading.value = false
		}
	})
}

async function removeItem(id: string) {
	try {
		await ElMessageBox.confirm(t('pages.webSearch.confirmDelete'), t('pages.webSearch.tip'), {
			type: 'warning'
		})
		const res = await resource.postWebSearchOpenApiDelete({ id })
		if (!res?.isSuccess) return
		ElMessage.success(t('pages.webSearch.deleteSuccess'))
		loadList(pagination.pageIndex)
	} catch {
		// ignore
	}
}

async function updateCredentials(id: string) {
	try {
		const { value } = await ElMessageBox.prompt(
			t('pages.webSearch.pleaseInputNewApiKey'),
			t('pages.webSearch.updateCredentialTitle'),
			{
				confirmButtonText: t('common.confirm'),
				cancelButtonText: t('common.cancel'),
				inputType: 'password',
				inputValidator: (value) => !!value?.trim() || t('pages.webSearch.pleaseInputApiKey')
			}
		)
		const res = await resource.postWebSearchCredentials({ id, api_key: value.trim() })
		if (!res?.isSuccess) return
		hasCurrentCredential.value = true
		ElMessage.success(t('pages.webSearch.credentialUpdateSuccess'))
		loadList(pagination.pageIndex)
	} catch (error) {
		if (error !== 'cancel' && error !== 'close') {
			ElMessage.error(t('pages.webSearch.credentialUpdateFailed'))
		}
	}
}

async function deleteCredentials(id: string) {
	try {
		await ElMessageBox.confirm(
			t('pages.webSearch.confirmDeleteCredential'),
			t('pages.webSearch.tip'),
			{
				type: 'warning'
			}
		)
		const res = await resource.postWebSearchDeleteCredentials({ id })
		if (!res?.isSuccess) return
		hasCurrentCredential.value = false
		ElMessage.success(t('pages.webSearch.credentialDeleteSuccess'))
		loadList(pagination.pageIndex)
	} catch (error) {
		if (error !== 'cancel' && error !== 'close') {
			ElMessage.error(t('pages.webSearch.credentialDeleteFailed'))
		}
	}
}

onMounted(async () => {
	await loadEngines()
	await loadList(1)
})
</script>

<style scoped lang="less">
.management-page {
	padding: 24px;
	min-height: 100%;
	box-sizing: border-box;
}

.page-head {
	margin-bottom: 20px;

	h1 {
		margin: 0;
		font-size: 28px;
		color: var(--text-primary);
	}

	p {
		margin: 6px 0 0;
		font-size: 14px;
		color: var(--text-secondary);
	}
}

.list-card {
	border-radius: 18px;
	margin-bottom: 16px;
}

.toolbar {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 12px;
	flex-wrap: wrap;
}

.toolbar-left,
.toolbar-right {
	display: flex;
	align-items: center;
	gap: 10px;
	flex-wrap: wrap;
}

.toolbar-actions {
	display: flex;
	align-items: center;
	gap: 8px;

	.el-button + .el-button {
		margin-left: 0;
	}
}

.search-input {
	width: 280px;
}

.toolbar-meta {
	display: flex;
	align-items: center;
	gap: 10px;
	flex-wrap: wrap;
}

.pill {
	padding: 8px 12px;
	border-radius: 999px;
	border: 1px solid var(--border-light);
	background: var(--bg-container);
	font-size: 12px;
	color: var(--text-secondary);
}

.tip-box {
	padding: 14px 16px;
	border-radius: 16px;
	background: var(--bg-container);
	border: 1px solid var(--border-light);
}

.tip-title {
	font-weight: 700;
	color: var(--text-primary);
	margin-bottom: 10px;
}

.engine-tags {
	display: flex;
	flex-wrap: wrap;
	gap: 8px;
}

.grid {
	display: grid;
	grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
	gap: 16px;
	min-height: 200px;

	.empty {
		grid-column: span 4;
	}
}

.actions {
	display: flex;
	justify-content: flex-end;
}

.actions-trigger {
	width: 30px;
	height: 30px;
	border-radius: 999px;
	display: grid;
	place-items: center;
	color: var(--text-secondary);
	background: var(--bg-overlay);
	transition:
		background 0.2s ease,
		color 0.2s ease;
}

.actions-trigger:hover {
	background: var(--bg-container);
	color: var(--text-strong);
}

.danger-text {
	color: var(--el-color-danger);
}

.card {
	overflow: hidden;
	border-radius: 20px;
	border: 1px solid var(--border-light);
	background: var(--bg-base);
	box-shadow: var(--shadow-sm);
	padding: 16px;
	display: flex;
	flex-direction: column;
	gap: 14px;
	transition:
		transform 0.22s ease,
		box-shadow 0.22s ease,
		border-color 0.22s ease;
}

.card:hover {
	transform: translateY(-3px);
	border-color: var(--border-base);
	box-shadow: var(--shadow-md);
}

.card-head {
	padding: 14px 16px;
	border-radius: 18px;
	background: var(--card-bg-unselected);
}

.title {
	font-size: 18px;
	font-weight: 700;
	line-height: 1.25;
	color: var(--text-strong);
	word-break: break-word;
}

.subtitle {
	margin-top: 6px;
	font-size: 13px;
	color: var(--text-secondary);
	word-break: break-word;
}

.badge-row {
	margin-top: 10px;
	display: flex;
	flex-wrap: wrap;
	gap: 8px;
}

.badge {
	padding: 5px 10px;
	border-radius: 999px;
	background: var(--bg-overlay);
	font-size: 12px;
	color: var(--text-primary);
	border: 1px solid var(--border-light);
}

.badge.subtle {
	background: var(--text-strong);
	color: var(--bg-base);
	border-color: transparent;
}

.desc {
	min-height: 44px;
	color: var(--text-secondary);
	font-size: 14px;
	line-height: 1.65;
	display: -webkit-box;
	-webkit-line-clamp: 2;
	-webkit-box-orient: vertical;
	overflow: hidden;
}

.tags {
	display: flex;
	flex-wrap: wrap;
	gap: 8px;
}

.meta-list {
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 1fr));
	gap: 10px;
}

.meta-item {
	padding: 10px 12px;
	border-radius: 14px;
	background: var(--bg-container);
	border: 1px solid var(--border-light);
	display: flex;
	flex-direction: column;
	gap: 4px;
	min-width: 0;
}

.meta-label {
	font-size: 12px;
	color: var(--text-tertiary);
}

.meta-value {
	font-size: 13px;
	color: var(--text-primary);
	word-break: break-word;
}

.card-footer {
	display: flex;
	justify-content: flex-end;
	gap: 6px;
	margin-top: auto;
	flex-wrap: wrap;
}

.pagination {
	display: flex;
	justify-content: flex-end;
}

.grid-2 {
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 1fr));
	gap: 12px;
}

.drawer-footer {
	display: flex;
	justify-content: flex-end;
	gap: 10px;
}

.check-box {
	width: 100%;
	display: flex;
	flex-direction: column;
	gap: 10px;
}

.credential-actions {
	display: flex;
	gap: 8px;
}

@media (max-width: 768px) {
	.search-input {
		width: 100%;
	}

	.grid-2,
	.meta-list {
		grid-template-columns: 1fr;
	}
}
</style>
