<template>
	<div class="execution-container">
		<div class="header">
			<div>
				<h1>{{ t('pages.execution.title') }}</h1>
				<p class="subtitle">{{ t('pages.execution.subtitle') }}</p>
			</div>
			<el-button type="primary" :loading="statsLoading || tableLoading" @click="refresh">
				<el-icon><RefreshRight /></el-icon>
				{{ t('common.refresh') }}
			</el-button>
		</div>

		<div class="stats-grid">
			<div class="stat-card">
				<div class="stat-icon">
					<SvgIcon name="play" size="20" />
				</div>
				<div>
					<div class="stat-value">{{ stats.runTotal }}</div>
					<div class="stat-label">{{ t('pages.execution.stats.recentExecutions') }}</div>
				</div>
			</div>
			<div class="stat-card">
				<div class="stat-icon success">
					<SvgIcon name="check-circle" size="20" />
				</div>
				<div>
					<div class="stat-value">{{ successRateText }}</div>
					<div class="stat-label">{{ t('pages.execution.stats.successRate') }}</div>
				</div>
			</div>
			<div class="stat-card">
				<div class="stat-icon warning">
					<SvgIcon name="clock" size="20" />
				</div>
				<div>
					<div class="stat-value">{{ stats.avgElapsedSec }}s</div>
					<div class="stat-label">{{ t('pages.execution.stats.avgDuration') }}</div>
				</div>
			</div>
			<div class="stat-card">
				<div class="stat-icon danger">
					<SvgIcon name="x-circle" size="20" />
				</div>
				<div>
					<div class="stat-value">{{ stats.errorTotal }}</div>
					<div class="stat-label">{{ t('pages.execution.stats.failedCount') }}</div>
				</div>
			</div>
		</div>

		<div class="filters">
			<div class="filters-left">
				<el-input
					v-model="keyword"
					placeholder="关键词搜索"
					clearable
					class="filter-item"
					@keyup.enter="handleSearch"
					@clear="handleSearch"
				>
					<template #prefix>
						<el-icon><Search /></el-icon>
					</template>
				</el-input>
				<el-select
					v-model="status"
					:placeholder="t('pages.execution.filters.status')"
					class="filter-item"
					clearable
					@change="handleSearch"
				>
					<el-option :label="t('common.all')" value="" />
					<el-option :label="t('common.status.running')" value="running" />
					<el-option :label="t('common.status.success')" value="finish" />
					<el-option :label="t('common.status.failed')" value="error" />
				</el-select>
				<el-select
					v-model="source"
					:placeholder="t('pages.execution.filters.source')"
					class="filter-item"
					clearable
					@change="handleSearch"
				>
					<el-option :label="t('common.all')" value="" />
					<el-option :label="t('pages.execution.sources.manual')" value="manual" />
					<el-option :label="t('pages.execution.sources.schedule')" value="schedule" />
					<el-option :label="t('pages.execution.sources.webhook')" value="webhook" />
					<el-option :label="t('pages.execution.sources.api')" value="api" />
				</el-select>
				<div class="toolbar-actions">
					<el-button type="primary" @click="handleSearch">
						<el-icon><Search /></el-icon>
						{{ t('common.search') }}
					</el-button>
					<el-button @click="resetFilters">
						<el-icon><RefreshRight /></el-icon>
						{{ t('common.reset') }}
					</el-button>
				</div>
			</div>
		</div>

		<div class="panel">
			<el-table v-loading="tableLoading" :data="executions" stripe style="width: 100%">
				<el-table-column
					prop="agentName"
					:label="t('pages.execution.table.agentName')"
					min-width="220"
					show-overflow-tooltip
				/>
				<el-table-column
					prop="executionId"
					:label="t('pages.execution.table.executionId')"
					min-width="260"
					show-overflow-tooltip
				/>
				<el-table-column
					prop="startedAt"
					:label="t('pages.execution.table.startedAt')"
					min-width="180"
				/>
				<el-table-column
					prop="endedAt"
					:label="t('pages.execution.table.endedAt')"
					min-width="180"
				/>
				<el-table-column
					prop="duration"
					:label="t('pages.execution.table.duration')"
					min-width="120"
				/>
				<el-table-column prop="source" :label="t('pages.execution.filters.source')" />
				<el-table-column :label="t('pages.execution.table.status')">
					<template #default="scope">
						<el-tag :type="statusType(scope.row.status)">
							{{ statusText(scope.row.status) }}
						</el-tag>
					</template>
				</el-table-column>
			</el-table>
			<div v-if="pagination.totalCount" class="pagination">
				<el-pagination
					v-model:current-page="pagination.pageIndex"
					v-model:page-size="pagination.pageSize"
					background
					layout="total, prev, pager, next"
					:page-sizes="[10, 20, 50, 100]"
					:total="pagination.totalCount"
					@current-change="handlePageChange"
					@size-change="handleSizeChange"
				/>
			</div>
		</div>

		<div class="side-panels">
			<div class="panel">
				<div class="panel-title">{{ t('pages.execution.panels.summary') }}</div>
				<div class="summary-item" v-for="item in summary" :key="item.label">
					<span class="label">{{ item.label }}</span>
					<span class="value">{{ item.value }}</span>
				</div>
			</div>
			<div class="panel">
				<div class="panel-title">{{ t('pages.execution.panels.tips') }}</div>
				<ul class="tips">
					<li v-for="item in tips" :key="item">{{ item }}</li>
				</ul>
			</div>
		</div>
	</div>
</template>

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

type AgentRunnerPageResponse = Awaited<ReturnType<typeof agentLog.postAgentGetAgentRunnerPageList>>
type AgentRunnerPageItem = NonNullable<AgentRunnerPageResponse['result']>['model'][number]

interface ExecutionRow {
	agentName: string
	executionId: string
	startedAt: string
	endedAt: string
	duration: string
	status: string
}

const { t } = useI18n()
const keyword = ref('')
const status = ref('')
const source = ref('')
const tableLoading = ref(false)
const statsLoading = ref(false)
const executions = ref<ExecutionRow[]>([])

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

const stats = reactive({
	runTotal: 0,
	successTotal: 0,
	errorTotal: 0,
	processTotal: 0,
	avgElapsedSec: 0
})

const sourceMap = {
	manual: t('pages.execution.sources.manual'),
	schedule: t('pages.execution.sources.schedule'),
	webhook: t('pages.execution.sources.webhook'),
	api: t('pages.execution.sources.api')
}

const summary = computed(() => [
	{ label: t('pages.execution.summaryLabels.processing'), value: `${stats.processTotal}` },
	{ label: t('pages.execution.summaryLabels.success'), value: `${stats.successTotal}` },
	{ label: t('pages.execution.summaryLabels.failed'), value: `${stats.errorTotal}` }
])

const tips = computed(() => [
	t('pages.execution.tips.0'),
	t('pages.execution.tips.1'),
	t('pages.execution.tips.2')
])

const successRateText = computed(() => {
	if (!stats.runTotal) return '0%'
	return `${((stats.successTotal / stats.runTotal) * 100).toFixed(1)}%`
})

const allStatuses = 'running,finish,error'
const allSources = 'manual,schedule,webhook,api'

const formatDuration = (value?: number | string | null) => {
	const duration = Number(value || 0)
	if (!Number.isFinite(duration) || duration <= 0) return '-'
	if (duration < 1000) return `${Math.round(duration)}ms`
	if (duration < 60_000) {
		const seconds = duration / 1000
		return `${Number.isInteger(seconds) ? seconds.toFixed(0) : seconds.toFixed(1)}s`
	}
	const minutes = Math.floor(duration / 60_000)
	const seconds = Math.round((duration % 60_000) / 1000)
	return `${minutes}m ${seconds}s`
}

const normalizeStatus = (value?: string) => `${value || ''}`.trim().toLowerCase()
const getStatusQuery = () => status.value || allStatuses
const getSourceQuery = () => source.value || allSources

const mapExecutionRow = (item: AgentRunnerPageItem): ExecutionRow => ({
	agentName: item.agentName || '-',
	executionId: item.runnerId || '-',
	startedAt: item.beginDate || '-',
	endedAt: item.endDate || '-',
	duration: formatDuration(item.useTime),
	status: normalizeStatus(item.status),
	source: sourceMap[item.source]
})

const statusType = (value: string) => {
	if (value === 'finish') return 'success'
	if (value === 'error') return 'danger'
	if (value === 'running') return 'warning'
	return 'info'
}

const statusText = (value: string) => {
	if (value === 'finish') return t('common.status.success')
	if (value === 'error') return t('common.status.failed')
	if (value === 'running') return t('common.status.running')
	return t('common.status.unknown')
}

const loadStats = async () => {
	statsLoading.value = true
	try {
		const res = await agentLog.postAgentGetBefore7DayAgentRunnerStatic({})
		if (!res.isSuccess || !res.result) throw new Error('load stats failed')
		const avgElapsedValue = (res.result as typeof res.result & { avg_elapsed_time?: string })
			.avg_elapsed_time
		stats.runTotal = res.result.run_total || 0
		stats.successTotal = res.result.success_total || 0
		stats.errorTotal = res.result.error_total || 0
		stats.processTotal = res.result.process_total || 0
		stats.avgElapsedSec = Number(res.result.avg_elapsed_sec || avgElapsedValue || 0)
	} catch (error) {
		console.error(error)
		ElMessage.error(t('pages.execution.messages.loadStatsFailed'))
	} finally {
		statsLoading.value = false
	}
}

const loadExecutions = async (pageIndex = pagination.pageIndex) => {
	tableLoading.value = true
	try {
		const res = await agentLog.postAgentGetAgentRunnerPageList({
			keyword: keyword.value.trim(),
			status: getStatusQuery(),
			source: getSourceQuery(),
			pageIndex,
			pageSize: pagination.pageSize
		})
		if (!res.isSuccess || !res.result) throw new Error('load executions failed')
		executions.value = (res.result.model || []).map(mapExecutionRow)
		pagination.pageIndex = res.result.currentPage || pageIndex
		pagination.pageSize = res.result.pageSize || pagination.pageSize
		pagination.totalCount = res.result.totalCount || 0
		pagination.totalPages = res.result.totalPages || 0
	} catch (error) {
		console.error(error)
		ElMessage.error(t('pages.execution.messages.loadListFailed'))
	} finally {
		tableLoading.value = false
	}
}

const refresh = async () => {
	await Promise.all([loadStats(), loadExecutions(pagination.pageIndex)])
}

const handleSearch = async () => {
	pagination.pageIndex = 1
	await loadExecutions(1)
}

const handlePageChange = async (page: number) => {
	pagination.pageIndex = page
	await loadExecutions(page)
}

const handleSizeChange = async (size: number) => {
	pagination.pageSize = size
	pagination.pageIndex = 1
	await loadExecutions(1)
}

const resetFilters = () => {
	keyword.value = ''
	status.value = ''
	source.value = ''
	handleSearch()
}

onMounted(() => {
	refresh()
})
</script>

<style lang="less" scoped>
.execution-container {
	margin: 0 auto;
	padding: 24px;

	.header {
		display: flex;
		justify-content: space-between;
		align-items: center;
		margin-bottom: 24px;

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

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

	.stats-grid {
		display: grid;
		grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
		gap: 16px;
		margin-bottom: 20px;

		.stat-card {
			background: var(--bg-base);
			border-radius: 12px;
			padding: 18px;
			box-shadow: var(--shadow-sm);
			display: flex;
			gap: 12px;
			align-items: center;

			.stat-icon {
				width: 40px;
				height: 40px;
				border-radius: 10px;
				background: #eef2ff;
				color: #4f46e5;
				display: flex;
				align-items: center;
				justify-content: center;

				&.success {
					background: #ecfdf3;
					color: #10b981;
				}

				&.warning {
					background: #fff7ed;
					color: #f97316;
				}

				&.danger {
					background: #fef2f2;
					color: #ef4444;
				}
			}

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

			.stat-label {
				font-size: 13px;
				color: var(--text-secondary);
			}
		}
	}

	.filters {
		display: flex;
		flex-wrap: wrap;
		gap: 12px;
		margin-bottom: 16px;
		align-items: center;
		justify-content: space-between;

		.filters-left {
			display: flex;
			flex-wrap: wrap;
			gap: 12px;
			align-items: center;
		}

		.filter-item {
			width: 220px;
		}

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

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

	.panel {
		background: var(--bg-base);
		border-radius: 12px;
		padding: 20px;
		box-shadow: var(--shadow-sm);
	}

	.pagination {
		display: flex;
		justify-content: flex-end;
		margin-top: 16px;
	}

	.side-panels {
		display: grid;
		grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
		gap: 16px;
		margin-top: 16px;

		.panel-title {
			font-size: 16px;
			font-weight: 600;
			margin-bottom: 12px;
			color: var(--text-primary);
		}

		.summary-item {
			display: flex;
			justify-content: space-between;
			padding: 10px 0;
			border-bottom: 1px solid var(--border-light);

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

			.value {
				font-weight: 600;
				color: var(--text-primary);
			}
		}

		.tips {
			margin: 0;
			padding-left: 16px;
			color: var(--text-secondary);
			line-height: 1.6;
			font-size: 13px;
		}
	}
}
</style>
