<template>
	<div class="panel">
		<div class="toolbar">
			<div class="toolbar-left">
				<el-input v-model="keyword" clearable placeholder="搜索 MCP 名称" class="search-input" @keyup.enter="loadList(1)">
					<template #prefix>
						<el-icon>
							<Search />
						</el-icon>
					</template>
				</el-input>
				<el-select v-model="transportType" clearable placeholder="传输类型" style="width: 160px" @change="loadList(1)">
					<el-option label="stdio" value="stdio" />
					<el-option label="sse" value="sse" />
					<el-option label="streamable" value="streamable" />
					<el-option label="http" value="http" />
				</el-select>
				<el-button @click="loadList(1)">查询</el-button>
				<el-button @click="handleReset">重置</el-button>
			</div>
			<div class="toolbar-right">
				<el-button type="primary" @click="openCreate">
					<el-icon>
						<Plus />
					</el-icon>
					新建 MCP
				</el-button>
			</div>
		</div>

		<div class="toolbar-meta">
			<span class="pill">共 {{ pagination.totalCount }} 个服务</span>
			<span class="pill">已启用 {{ enabledCount }} 个</span>
		</div>

		<!-- <div class="summary-grid">
			<div class="summary-card">
				<div class="summary-value">{{ pagination.totalCount }}</div>
				<div class="summary-label">MCP 总数</div>
			</div>
			<div class="summary-card">
				<div class="summary-value">{{ enabledCount }}</div>
				<div class="summary-label">启用中</div>
			</div>
			<div class="summary-card">
				<div class="summary-value">{{ transportCount }}</div>
				<div class="summary-label">传输类型</div>
			</div>
		</div> -->

		<div v-loading="loading" class="grid">
			<el-empty class="empty" v-if="!list.length && !loading" description="暂无 MCP 服务" />
			<div v-for="row in list" :key="row.id" class="card">
				<div class="card-head">
					<div class="card-head__top">
						<div class="title-block">
							<div class="title">{{ row.name || '未命名 MCP' }}</div>
							<div class="subtitle">{{ row.url || '未配置地址' }}</div>
						</div>
						<div class="actions">
							<el-dropdown>
								<span class="actions-trigger">
									<el-icon>
										<MoreFilled />
									</el-icon>
								</span>
								<template #dropdown>
									<el-dropdown-menu>
										<el-dropdown-item @click="checkItem(row.id)">测试</el-dropdown-item>
										<el-dropdown-item @click="openTools(row.id)">工具</el-dropdown-item>
										<el-dropdown-item @click="openEditById(row.id)">编辑</el-dropdown-item>
										<el-dropdown-item divided @click="removeItem(row.id)">
											<span class="danger-text">删除</span>
										</el-dropdown-item>
									</el-dropdown-menu>
								</template>
							</el-dropdown>
						</div>
					</div>
					<div class="badge-row">
						<span class="badge">{{ row.transport_type || '未设置传输类型' }}</span>
						<span class="badge subtle">{{ row.enabled ? '启用中' : '已禁用' }}</span>
					</div>
				</div>

				<div class="desc">{{ row.description || '暂无描述' }}</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, sizes, prev, pager, next, jumper" :page-sizes="[10, 20, 50, 100]" :total="pagination.totalCount"
				@current-change="handlePageChange" @size-change="handleSizeChange" />
		</div>

		<el-drawer v-model="drawerVisible" :title="currentId ? '编辑 MCP' : '新建 MCP'" direction="rtl" size="760px">
			<el-form ref="formRef" :model="form" :rules="rules" label-position="top">
				<el-form-item label="名称" prop="name">
					<el-input v-model="form.name" />
				</el-form-item>
				<el-form-item label="描述" prop="description">
					<el-input v-model="form.description" type="textarea" :rows="2" />
				</el-form-item>
				<div class="grid-2">
					<el-form-item label="传输类型" prop="transport_type">
						<el-select v-model="form.transport_type" style="width: 100%">
							<el-option label="SSE(Server-Sent Events)" value="sse" />
							<el-option label="HTTP Streamable" value="http-streamable" />
						</el-select>
					</el-form-item>
					<el-form-item label="启用" prop="enabled">
						<el-switch v-model="form.enabled" />
					</el-form-item>
				</div>
				<el-form-item label="地址" prop="url">
					<el-input v-model="form.url" />
				</el-form-item>
				<el-form-item label="超时（秒）" prop="advanced_config.timeout">
					<el-input-number v-model="form.advanced_config.timeout" :min="0" style="width: 100%" />
				</el-form-item>
				<div class="grid-2">
					<el-form-item label="重试次数" prop="advanced_config.retry_count">
						<el-input-number v-model="form.advanced_config.retry_count" :min="0" style="width: 100%" />
					</el-form-item>
					<el-form-item label="重试间隔（秒）" prop="advanced_config.retry_delay">
						<el-input-number v-model="form.advanced_config.retry_delay" :min="0" style="width: 100%" />
					</el-form-item>
				</div>
				<el-form-item label="Headers">
					<div class="kv-config">
						<div class="kv-config__top">
							<span>请求头</span>
							<el-button type="primary" link @click="addHeaderRow">
								<el-icon>
									<Plus />
								</el-icon>添加
							</el-button>
						</div>
						<div class="kv-config__rows">
							<div v-for="(item, index) in headerList" :key="`header-${index}`" class="kv-config__row">
								<el-input v-model="item.key" placeholder="Header 名称" />
								<el-input v-model="item.value" placeholder="Header 值" />
								<el-button link type="danger" :disabled="headerList.length === 1" @click="removeHeaderRow(index)">
									删除
								</el-button>
							</div>
						</div>
					</div>
				</el-form-item>
				<el-form-item label="Auth Config">
					<div class="kv-config">
						<div class="kv-config__top">
							<span>鉴权配置</span>
							<el-button type="primary" link @click="addAuthRow">
								<el-icon>
									<Plus />
								</el-icon>添加
							</el-button>
						</div>
						<div class="kv-config__rows">
							<div v-for="(item, index) in authList" :key="`auth-${index}`" class="kv-config__row">
								<el-input v-model="item.key" placeholder="配置项名称" />
								<el-input v-model="item.value" placeholder="配置项值" />
								<el-button link type="danger" :disabled="authList.length === 1" @click="removeAuthRow(index)">
									删除
								</el-button>
							</div>
						</div>
					</div>
				</el-form-item>
				<el-form-item label="Env Vars">
					<div class="kv-config">
						<div class="kv-config__top">
							<span>环境变量</span>
							<el-button type="primary" link @click="addEnvRow">
								<el-icon>
									<Plus />
								</el-icon>添加
							</el-button>
						</div>
						<div class="kv-config__rows">
							<div v-for="(item, index) in envList" :key="`env-${index}`" class="kv-config__row">
								<el-input v-model="item.key" placeholder="变量名" />
								<el-input v-model="item.value" placeholder="变量值" />
								<el-button link type="danger" :disabled="envList.length === 1" @click="removeEnvRow(index)">
									删除
								</el-button>
							</div>
						</div>
					</div>
				</el-form-item>
				<el-form-item>
					<div class="check-box">
						<el-button :loading="checkLoading" :disabled="!currentId" @click="checkItemByForm">
							测试连接
						</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">取消</el-button>
					<el-button type="primary" :loading="submitLoading" @click="handleSubmit">保存</el-button>
				</div>
			</template>
		</el-drawer>

		<el-dialog v-model="detailVisible" title="MCP 详情" width="720px">
			<el-descriptions v-if="detailItem" :column="1" border>
				<el-descriptions-item label="名称">{{ detailItem.name }}</el-descriptions-item>
				<el-descriptions-item label="传输类型">{{
					detailItem.transport_type
				}}</el-descriptions-item>
				<el-descriptions-item label="地址">{{ detailItem.url || '-' }}</el-descriptions-item>
				<el-descriptions-item label="描述">{{
					detailItem.description || '-'
				}}</el-descriptions-item>
			</el-descriptions>
		</el-dialog>

		<el-dialog v-model="resourcesVisible" title="MCP 资源" width="720px">
			<el-empty v-if="!resourceList.length" description="暂无资源" />
			<el-space v-else wrap>
				<el-tag v-for="item in resourceList" :key="item">{{ item }}</el-tag>
			</el-space>
		</el-dialog>

		<el-dialog v-model="toolsVisible" title="MCP 工具" width="720px">
			<div class="tool-dialog">
				<el-input
					v-model="toolKeyword"
					clearable
					placeholder="搜索工具名称或描述"
					class="tool-search-input"
				>
					<template #prefix>
						<el-icon>
							<Search />
						</el-icon>
					</template>
				</el-input>
				<el-empty v-if="!filteredToolDetailList.length" description="暂无工具" />
				<el-scrollbar v-else max-height="420px">
					<el-collapse>
						<el-collapse-item v-for="item in filteredToolDetailList" :key="item.name" :title="item.name">
							<div class="tool-desc">{{ item.description }}</div>
						</el-collapse-item>
					</el-collapse>
				</el-scrollbar>
			</div>
		</el-dialog>
	</div>
</template>

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

type McpPageResponse = Awaited<ReturnType<typeof resource.postMcpPageList>>
type McpItem = NonNullable<McpPageResponse['result']>['model'][number]
type McpInfoResponse = Awaited<ReturnType<typeof resource.postMcpInfo>>
type McpInfoItem = NonNullable<McpInfoResponse['result']>
type McpCheckResponse = Awaited<ReturnType<typeof resource.postMcpCheck>>
type McpToolItem = NonNullable<McpCheckResponse['result']>['tools'][number]
type KvRow = { key: string; value: string }

const keyword = ref('')
const transportType = ref('')
const loading = ref(false)
const submitLoading = ref(false)
const checkLoading = ref(false)
const drawerVisible = ref(false)
const detailVisible = ref(false)
const resourcesVisible = ref(false)
const toolsVisible = ref(false)
const currentId = ref('')
const detailItem = ref<McpInfoItem | null>(null)
const resourceList = ref<string[]>([])
const toolDetailList = ref<McpToolItem[]>([])
const toolKeyword = ref('')
const checkMessage = ref('')
const checkSuccess = ref(false)
const headerList = ref<KvRow[]>([{ key: '', value: '' }])
const authList = ref<KvRow[]>([{ key: '', value: '' }])
const envList = ref<KvRow[]>([{ key: '', value: '' }])
const formRef = ref()

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

const list = ref<McpItem[]>([])

const form = reactive({
	name: '',
	description: '',
	transport_type: 'http-streamable',
	url: '',
	enabled: true,
	headers: {} as Record<string, any>,
	auth_config: {} as Record<string, any>,
	advanced_config: {
		timeout: 30,
		retry_count: 3,
		retry_delay: 1
	},
	env_vars: {} as Record<string, any>
})

const rules = {
	name: [{ required: true, message: '请输入名称', trigger: 'blur' }],
	transport_type: [{ required: true, message: '请选择传输类型', trigger: 'change' }],
	url: [{ required: true, message: '请输入地址', trigger: 'blur' }]
}

const enabledCount = computed(() => list.value.filter((item) => item.enabled).length)
const transportCount = computed(() => new Set(list.value.map((item) => item.transport_type)).size)
const filteredToolDetailList = computed(() => {
	const keywordValue = toolKeyword.value.trim().toLowerCase()
	if (!keywordValue) return toolDetailList.value
	return toolDetailList.value.filter((item) => {
		const name = item.name?.toLowerCase() || ''
		const description = item.description?.toLowerCase() || ''
		return name.includes(keywordValue) || description.includes(keywordValue)
	})
})

function toKvRows(record?: Record<string, any>) {
	const rows = Object.entries(record || {}).map(([key, value]) => ({
		key,
		value: String(value ?? '')
	}))
	return rows.length ? rows : [{ key: '', value: '' }]
}

function toRecord(rows: KvRow[]) {
	const record: Record<string, string> = {}
	for (const item of rows) {
		const key = item.key.trim()
		if (!key) continue
		record[key] = item.value
	}
	return record
}

function resetForm() {
	currentId.value = ''
	checkMessage.value = ''
	checkSuccess.value = false
	form.name = ''
	form.description = ''
	form.transport_type = 'http-streamable'
	form.url = ''
	form.enabled = true
	form.headers = {}
	form.auth_config = {}
	form.advanced_config.timeout = 30
	form.advanced_config.retry_count = 3
	form.advanced_config.retry_delay = 1
	form.env_vars = {}
	headerList.value = [{ key: '', value: '' }]
	authList.value = [{ key: '', value: '' }]
	envList.value = [{ key: '', value: '' }]
}

function addHeaderRow() {
	headerList.value.push({ key: '', value: '' })
}

function removeHeaderRow(index: number) {
	if (headerList.value.length === 1) {
		headerList.value[0] = { key: '', value: '' }
		return
	}
	headerList.value.splice(index, 1)
}

function addAuthRow() {
	authList.value.push({ key: '', value: '' })
}

function removeAuthRow(index: number) {
	if (authList.value.length === 1) {
		authList.value[0] = { key: '', value: '' }
		return
	}
	authList.value.splice(index, 1)
}

function addEnvRow() {
	envList.value.push({ key: '', value: '' })
}

function removeEnvRow(index: number) {
	if (envList.value.length === 1) {
		envList.value[0] = { key: '', value: '' }
		return
	}
	envList.value.splice(index, 1)
}

async function loadList(pageIndex = 1) {
	loading.value = true
	try {
		const res = await resource.postMcpPageList({
			keyword: keyword.value,
			transport_type: transportType.value,
			pageIndex,
			pageSize: pagination.pageSize
		})
		if (res.isSuccess && res.result) {
			list.value = (res.result.model || []) as McpItem[]
			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 = ''
	transportType.value = ''
	loadList(1)
}

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

async function openEditById(id: string) {
	const res = await resource.postMcpInfo({ id })
	if (!res.isSuccess || !res.result) {
		ElMessage.error('获取详情失败')
		return
	}
	resetForm()
	currentId.value = id
	form.name = res.result.name || ''
	form.description = res.result.description || ''
	form.transport_type = res.result.transport_type || 'http-streamable'
	form.url = res.result.url || ''
	form.enabled = !!res.result.enabled
	form.headers = res.result.headers || {}
	form.auth_config = res.result.auth_config || {}
	form.advanced_config.timeout = res.result.advanced_config?.timeout ?? 30
	form.advanced_config.retry_count = res.result.advanced_config?.retry_count ?? 1
	form.advanced_config.retry_delay = res.result.advanced_config?.retry_delay ?? 1
	form.env_vars = res.result.env_vars || {}
	headerList.value = toKvRows(form.headers)
	authList.value = toKvRows(form.auth_config)
	envList.value = toKvRows(form.env_vars)
	drawerVisible.value = true
}

async function checkItem(id: string) {
	try {
		const res = await resource.postMcpCheck({ id })
		if (res.isSuccess) {
			ElMessage.success(res.result?.message || '连通测试成功')
		} else {
			ElMessage.error('连通测试失败')
		}
	} catch {
		ElMessage.error('连通测试失败')
	}
}

async function checkItemByForm() {
	if (!currentId.value) {
		checkSuccess.value = false
		checkMessage.value = '请先保存 MCP 服务，再执行连通测试'
		return
	}
	checkLoading.value = true
	checkMessage.value = ''
	try {
		const res = await resource.postMcpCheck({ id: currentId.value })
		checkSuccess.value = !!res.isSuccess
		checkMessage.value = res.isSuccess ? res.result?.message || '连通测试成功' : '连通测试失败'
	} catch {
		checkSuccess.value = false
		checkMessage.value = '连通测试失败'
	} finally {
		checkLoading.value = false
	}
}

async function handleSubmit() {
	await formRef.value?.validate(async (valid: boolean) => {
		if (!valid) return
		submitLoading.value = true
		try {
			const payload = {
				name: form.name,
				description: form.description,
				transport_type: form.transport_type,
				url: form.url,
				enabled: form.enabled,
				headers: toRecord(headerList.value),
				auth_config: toRecord(authList.value),
				advanced_config: {
					timeout: form.advanced_config.timeout,
					retry_count: form.advanced_config.retry_count,
					retry_delay: form.advanced_config.retry_delay
				},
				env_vars: toRecord(envList.value)
			}
			if (currentId.value) {
				await resource.postMcpUpdate({ id: currentId.value, ...(payload as any) })
				ElMessage.success('更新成功')
			} else {
				await resource.postMcpCreate(payload as any)
				ElMessage.success('创建成功')
			}
			drawerVisible.value = false
			loadList(pagination.pageIndex)
		} catch {
			ElMessage.error('保存失败')
		} finally {
			submitLoading.value = false
		}
	})
}

async function removeItem(id: string) {
	try {
		await ElMessageBox.confirm('确定删除该 MCP 服务吗？', '提示', { type: 'warning' })
		await resource.postMcpOpenApiDelete({ id })
		ElMessage.success('删除成功')
		loadList(pagination.pageIndex)
	} catch {
		// ignore
	}
}

async function openResources(id: string) {
	const res = await resource.postMcpResources({ id })
	resourceList.value = res.isSuccess ? res.result || [] : []
	resourcesVisible.value = true
}

async function openTools(id: string) {
	const res = await resource.postMcpTools({ id })
	toolKeyword.value = ''
	toolDetailList.value = res.isSuccess ? res.result || [] : []
	toolsVisible.value = true
}

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

<style scoped lang="less">
.panel {
	display: flex;
	flex-direction: column;
	gap: 16px;
}

.section-title {
	margin: 10px 0 12px;
	font-size: 14px;
	font-weight: 700;
	color: #111827;
	display: flex;
	align-items: center;
	gap: 12px;
}

.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;
}

.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 #e5e7eb;
	background: #f8fafc;
	font-size: 12px;
	color: #64748b;
}

.summary-grid {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
	gap: 12px;
}

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

.summary-value {
	font-size: 28px;
	font-weight: 700;
	color: var(--text-primary);
}

.summary-label {
	margin-top: 6px;
	font-size: 13px;
	color: var(--text-secondary);
}

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

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

.card {
	overflow: hidden;
	border-radius: 20px;
	border: 1px solid #e5e7eb;
	background: #fff;
	box-shadow: 0 12px 28px rgba(15, 23, 42, 0.06);
	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: #d8dee9;
	box-shadow: 0 18px 36px rgba(15, 23, 42, 0.1);
}

.card-head {
	padding: 14px 16px;
	border-radius: 18px;
	background:
		radial-gradient(circle at top left, rgba(15, 23, 42, 0.06), transparent 38%),
		linear-gradient(135deg, #f8fafc, #eef2ff 58%, #fff7ed);
}

.card-head__top {
	display: flex;
	align-items: flex-start;
	justify-content: space-between;
	gap: 12px;
}

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

.actions-trigger {
	width: 30px;
	height: 30px;
	border-radius: 999px;
	display: grid;
	place-items: center;
	color: #475569;
	background: rgba(255, 255, 255, 0.8);
	transition:
		background 0.2s ease,
		color 0.2s ease;
}

.actions-trigger:hover {
	background: rgba(15, 23, 42, 0.08);
	color: #0f172a;
}

.title {
	font-size: 18px;
	font-weight: 700;
	line-height: 1.25;
	color: #0f172a;
	word-break: break-word;
}

.subtitle {
	margin-top: 6px;
	font-size: 13px;
	color: #64748b;
	word-break: break-all;
}

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

.badge {
	padding: 5px 10px;
	border-radius: 999px;
	background: rgba(255, 255, 255, 0.92);
	font-size: 12px;
	color: #334155;
	border: 1px solid rgba(203, 213, 225, 0.9);
}

.badge.subtle {
	background: rgba(15, 23, 42, 0.82);
	color: #f8fafc;
	border-color: transparent;
}

.desc {
	min-height: 44px;
	color: #64748b;
	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: #f8fafc;
	border: 1px solid #e2e8f0;
	display: flex;
	flex-direction: column;
	gap: 4px;
	min-width: 0;
}

.meta-label {
	font-size: 12px;
	color: #94a3b8;
}

.meta-value {
	font-size: 13px;
	color: #334155;
	word-break: break-word;
}

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

.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;
}

.tool-dialog {
	display: flex;
	flex-direction: column;
	gap: 12px;
}

.tool-search-input {
	width: 100%;
}

.kv-config {
	width: 100%;
}

.kv-config__top {
	display: flex;
	align-items: center;
	justify-content: space-between;
}

.kv-config__desc {
	margin: 4px 0 10px;
	font-size: 12px;
	color: var(--text-secondary);
}

.kv-config__rows {
	display: flex;
	flex-direction: column;
	gap: 8px;
}

.kv-config__row {
	display: grid;
	grid-template-columns: 1fr 1fr auto;
	gap: 8px;
	align-items: center;
}

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

.tool-desc {
	color: var(--text-secondary);
	line-height: 1.6;
}

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

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