<template>
	<div class="ollama-manage">
		<el-row :gutter="16" class="stats-row">
			<el-col :span="8">
				<el-card class="stat-card" shadow="hover">
					<div class="stat-content">
						<div :class="['stat-icon', ollamaStatus.isSuccess ? 'online' : 'offline']">
							<el-icon :size="24">
								<component :is="ollamaStatus.isSuccess ? CircleCheck : CircleClose" />
							</el-icon>
						</div>
						<div class="stat-info">
							<div class="stat-label">Ollama连接状态</div>
							<div class="stat-value">{{ ollamaStatus.isSuccess ? '已连接' : '未连接' }}</div>
						</div>
						<el-button type="primary" plain @click="checkOllamaStatus">刷新</el-button>
					</div>
				</el-card>
			</el-col>
			<el-col :span="8">
				<el-card class="stat-card" shadow="hover">
					<div class="stat-content">
						<div class="stat-icon default">
							<el-icon :size="24">
								<Document />
							</el-icon>
						</div>
						<div class="stat-info">
							<div class="stat-label">已下载模型</div>
							<div class="stat-value">{{ localModels.length }}</div>
						</div>
					</div>
				</el-card>
			</el-col>
			<el-col :span="8">
				<el-card class="stat-card" shadow="hover">
					<div class="stat-content">
						<div class="stat-icon default">
							<el-icon :size="24">
								<List />
							</el-icon>
						</div>
						<div class="stat-info">
							<div class="stat-label">进行中任务</div>
							<div class="stat-value">{{ downloadingTasks }}</div>
						</div>
					</div>
				</el-card>
			</el-col>
		</el-row>

		<div class="action-bar">
			<el-button type="primary" @click="showDownloadDialog = true">
				<el-icon>
					<Plus />
				</el-icon> 下载新模型
			</el-button>
			<el-button @click="handleRefresh()">
				<el-icon>
					<Refresh />
				</el-icon> 刷新
			</el-button>
		</div>

		<el-card class="list-card">
			<el-table v-if="localModels.length || localLoading" :data="localModels" v-loading="localLoading" border>
				<el-table-column prop="name" label="模型名称" />
				<el-table-column prop="size" label="大小" :formatter="formatSize" />
				<el-table-column prop="digest" label="Digest" />
				<el-table-column prop="modified_at" label="更新时间" />
				<template #empty>暂无已下载的本地模型</template>
			</el-table>
			<el-empty v-else description="暂无已下载的本地模型" class="page-empty" />
		</el-card>

		<div class="task-title">下载任务</div>
		<el-card class="list-card mt-4">
			<el-table v-if="sortedDownloadTasks.length" :data="sortedDownloadTasks" border no-data-text="暂无下载任务">
				<el-table-column prop="modelName" label="模型名称" width="200" />
				<el-table-column prop="status" label="状态" width="120">
					<template #default="{ row }">
						<el-tag :type="getStatusType(row.status)">{{ formatStatus(row.status) }}</el-tag>
					</template>
				</el-table-column>
				<el-table-column prop="progress" label="进度" width="200">
					<template #default="{ row }">
						<el-progress :percentage="getPercentage(row.progress)" :stroke-width="8"
							:show-text="row.status === 'downloading'" />
					</template>
				</el-table-column>
				<el-table-column prop="startTime" label="开始时间" />
				<el-table-column prop="message" label="消息" />
				<template #empty>暂无下载任务</template>
			</el-table>
			<el-empty v-else description="暂无下载任务" class="page-empty page-empty--compact" />
		</el-card>

		<el-dialog v-model="showDownloadDialog" title="下载新模型" width="500px">
			<el-form :model="downloadForm" label-width="80px">
				<el-form-item label="模型名称" required>
					<el-input v-model="downloadForm.modelName" placeholder="例如: llama3.1" />
				</el-form-item>
				<el-form-item>
					<div>
						你可访问
						<a href="https://ollama.ai/library" target="_blank">https://ollama.ai/library</a>
						查询可用模型
					</div>
				</el-form-item>
			</el-form>
			<template #footer>
				<el-button @click="showDownloadDialog = false">取消</el-button>
				<el-button type="primary" @click="startDownloadModel" :loading="downloadLoading">开始下载</el-button>
			</template>
		</el-dialog>
	</div>
</template>

<script setup lang="ts">
import { ref, reactive, onMounted, computed, onUnmounted } from 'vue'
import { ElMessage, dayjs } from 'element-plus'
import { Document, List, Plus, Refresh, CircleCheck, CircleClose } from '@element-plus/icons-vue'
import { ollama } from '@repo/api-service'
import type { OllamaModel, DownloadTask } from './types'

const emit = defineEmits<{
	(e: 'update:localModels', models: OllamaModel[]): void
	(e: 'open-import-model', name: string): void
}>()

const ollamaStatus = ref({ isSuccess: false })
const localLoading = ref(false)
const localModels = ref<OllamaModel[]>([])
const downloadTasks = ref<DownloadTask[]>([])
const showDownloadDialog = ref(false)
const downloadLoading = ref(false)
const downloadForm = reactive({ modelName: '' })
let progressTimer: number | null = null
let pollingActive = false

const downloadingTasks = computed(() => downloadTasks.value.filter((t) => t.status === 'downloading').length)
const sortedDownloadTasks = computed(() => {
	return [...downloadTasks.value].sort((a, b) => {
		const order = { downloading: 0, failed: 1, success: 2 }
		return (order[a.status as keyof typeof order] ?? 3) - (order[b.status as keyof typeof order] ?? 3)
	})
})

function getPercentage(progress = 0) {
	return Number(progress.toFixed(2))
}
function formatStatus(status: string) {
	const statusMap: Record<string, string> = {
		downloading: '下载中',
		completed: '已完成',
		failed: '失败'
	}
	return statusMap[status] || status
}
function formatSize(row: OllamaModel) {
	if (!row.size) return '-'
	const size = row.size / (1024 * 1024 * 1024)
	return `${size.toFixed(2)} GB`
}
function formatTime(time: string) {
	return dayjs(time).format('YYYY-MM-DD HH:mm:ss')
}
function getStatusType(status: string) {
	if (status === 'completed') return 'success'
	if (status === 'downloading') return 'primary'
	if (status === 'failed') return 'danger'
	return 'info'
}
function emitOpenImport(name: string) {
	emit('open-import-model', name)
}

async function checkOllamaStatus() {
	try {
		const res = await ollama.postOllamaStatus({})
		ollamaStatus.value = res as any
	} catch {
		ollamaStatus.value = { isSuccess: false }
	}
}

async function handleRefresh() {
	getLocalModels()
	getDownloadTasks()
}

async function getLocalModels() {
	localLoading.value = true
	try {
		const res = await ollama.postOllamaModels({})
		if (res.isSuccess) {
			localModels.value = res.result || []
			emit('update:localModels', localModels.value)
		}
	} finally {
		localLoading.value = false
	}
}

async function getDownloadTasks() {
	try {
		const res = await ollama.postOllamaDownloadTasks({})
		if (res.isSuccess) {
			const newTasks = res.result || []
			newTasks.forEach((task) => {
				const oldTask = downloadTasks.value.find((t) => t.id === task.id)
				if (!oldTask) {
					downloadTasks.value.push(task as DownloadTask)
				} else {
					Object.assign(oldTask, task)
				}
			})
		}
	} catch (error) {
		console.error(error)
	}
}

async function startDownloadModel() {
	if (!downloadForm.modelName.trim()) {
		ElMessage.warning('请输入模型名称')
		return
	}
	downloadLoading.value = true
	try {
		const res = await ollama.postOllamaDownloadModel({ model: downloadForm.modelName.trim() })
		if (res.isSuccess) {
			ElMessage.success('下载任务已创建')
			showDownloadDialog.value = false
			downloadForm.modelName = ''
			await getDownloadTasks()
			startProgressPoll()
		} else {
			ElMessage.error('创建下载任务失败')
		}
	} finally {
		downloadLoading.value = false
	}
}

function stopProgressPoll() {
	pollingActive = false
	if (progressTimer) {
		clearTimeout(progressTimer)
		progressTimer = null
	}
}
function scheduleNextPoll() {
	if (!pollingActive) return
	const hasDownloading = downloadTasks.value.some((t) => t.status === 'downloading')
	const delay = hasDownloading ? 3000 : 30000
	if (progressTimer) clearTimeout(progressTimer)
	progressTimer = window.setTimeout(async () => {
		await getDownloadTasks()
		scheduleNextPoll()
	}, delay)
}
function startProgressPoll() {
	pollingActive = true
	scheduleNextPoll()
}

onMounted(async () => {
	checkOllamaStatus()
	getLocalModels()
	await getDownloadTasks()
	startProgressPoll()
})

onUnmounted(() => {
	stopProgressPoll()
})
</script>

<style lang="less" scoped>
.ollama-manage {
	width: 100%;
}

.stats-row {
	margin-bottom: 16px;
}

.stat-card {
	.stat-content {
		display: flex;
		align-items: center;
		gap: 12px;

		.stat-icon {
			width: 48px;
			height: 48px;
			border-radius: 8px;
			display: flex;
			align-items: center;
			justify-content: center;

			&.online {
				background: #f0f9eb;
				color: #67c23a;
			}

			&.offline {
				background: #fef0f0;
				color: #f56c6c;
			}

			&.default {
				background: #ecf5ff;
				color: #409eff;
			}
		}

		.stat-info {
			flex: 1;

			.stat-label {
				font-size: 14px;
				color: #909399;
				margin-bottom: 4px;
			}

			.stat-value {
				font-size: 18px;
				font-weight: 600;
				color: #303133;
			}
		}
	}
}

.action-bar {
	margin-bottom: 16px;
	display: flex;
	gap: 12px;
}

.list-card {
	border-radius: 8px;
}

.task-title {
	margin: 16px 0 8px;
	font-size: 16px;
	font-weight: 600;
	color: #303133;
}

.mt-4 {
	margin-top: 16px;
}

.page-empty {
	min-height: 280px;
	display: flex;
	align-items: center;
	justify-content: center;
}

.page-empty--compact {
	min-height: 180px;
}
</style>
