<template>
	<div class="trade-operation-analysis-shop">
		<el-card shadow="hover">
			<template #header>
				<div class="card-header">
					<span>店铺评分监控</span>
					<el-button type="text" @click="openSettingDialog" class="setting-btn">
						<el-icon><eleSetting /></el-icon>
						<span>预警设置</span>
					</el-button>
				</div>
			</template>
			<div class="chart-container">
				<el-card>
					<template #header
						><div class="card-header">评分趋势 - {{ selectedShopName }}</div></template
					>
					<div ref="scoreChartRef" class="chart"></div>
				</el-card>
			</div>
			<div class="shop-list">
				<el-card>
					<template #header><div class="card-header">店铺列表</div></template>
					<div class="search-container">
						<el-form :model="searchParams" :inline="true" class="search-form">
							<el-form-item label="店铺搜索">
								<el-input v-model="searchParams.shopKeyword" placeholder="请输入店铺名称或店铺ID" clearable @keyup.enter="handleSearch" />
							</el-form-item>
							<el-form-item label="时间范围"
								><el-date-picker
									v-model="searchParams.dateRange"
									type="daterange"
									range-separator="至"
									start-placeholder="开始日期"
									end-placeholder="结束日期"
									value-format="YYYY-MM-DD"
									:shortcuts="dateShortcuts"
							/></el-form-item>
							<el-form-item label="时间粒度">
								<el-radio-group v-model="searchParams.granularity" class="granularity-group">
									<el-radio-button v-for="option in granularityOptions" :key="option.value" :label="option.value">
										{{ option.label }}
									</el-radio-button>
								</el-radio-group>
							</el-form-item>
							<el-form-item
								><el-button type="primary" @click="handleSearch">查询</el-button><el-button @click="handleReset">重置</el-button></el-form-item
							>
						</el-form>
					</div>
					<el-table :data="pagedShopList" style="width: 100%" highlight-current-row @row-click="handleShopClick">
						<el-table-column prop="id" label="店铺ID" width="100" />
						<el-table-column prop="name" label="店铺名称" />
						<el-table-column prop="type" label="店铺类型"
							><template #default="scope"
								><el-tag size="small">{{ scope.row.type === 'physical' ? '线下店铺' : '线上店铺' }}</el-tag></template
							></el-table-column
						>
						<el-table-column prop="status" label="状态"
							><template #default="scope"
								><el-tag size="small" :type="scope.row.status === 'active' ? 'success' : 'danger'">{{
									scope.row.status === 'active' ? '营业中' : '已关闭'
								}}</el-tag></template
							></el-table-column
						>
						<el-table-column label="操作" width="120"
							><template #default="scope"
								><el-button type="primary" size="small" @click.stop="handleShopSelect(scope.row.id)">查看监控</el-button></template
							></el-table-column
						>
					</el-table>
					<div class="pagination-container">
						<el-pagination
							v-model:current-page="shopPagination.currentPage"
							v-model:page-size="shopPagination.pageSize"
							:page-sizes="[5, 10, 20, 50]"
							layout="total, sizes, prev, pager, next, jumper"
							:total="shopPagination.total"
							@size-change="handleShopPageSizeChange"
							@current-change="handleShopPageChange"
						/>
					</div>
				</el-card>
			</div>
			<div class="score-detail">
				<el-card>
					<template #header
						><div class="card-header">评分详情 - {{ selectedShopName }}</div></template
					>
					<el-table :data="pagedScoreDetail" style="width: 100%">
						<el-table-column prop="date" label="日期" />
						<el-table-column prop="reputationScore" label="口碑分"
							><template #default="scope"
								><div class="score-item" :class="{ warning: scope.row.reputationScore < scoreSettings.reputationThreshold }">
									{{ scope.row.reputationScore }}
								</div></template
							></el-table-column
						>
						<el-table-column prop="experienceScore" label="体验分"
							><template #default="scope"
								><div class="score-item" :class="{ warning: scope.row.experienceScore < scoreSettings.experienceThreshold }">
									{{ scope.row.experienceScore }}
								</div></template
							></el-table-column
						>
						<el-table-column prop="commentCount" label="评价数量" />
					</el-table>
					<div class="pagination-container">
						<el-pagination
							v-model:current-page="detailPagination.currentPage"
							v-model:page-size="detailPagination.pageSize"
							:page-sizes="[5, 10, 20, 50]"
							layout="total, sizes, prev, pager, next, jumper"
							:total="detailPagination.total"
							@size-change="handleDetailPageSizeChange"
							@current-change="handleDetailPageChange"
						/>
					</div>
				</el-card>
			</div>
		</el-card>

		<!-- 评分预警设置弹窗 -->
		<el-dialog v-model="dialogVisible" :title="'评分预警设置 - ' + selectedShopName" width="400px">
			<el-form :model="scoreSettings" label-width="120px">
				<el-form-item label="口碑分预警阈值">
					<el-input-number v-model="scoreSettings.reputationThreshold" :min="0" :max="5" :step="0.1" />
				</el-form-item>
				<el-form-item label="体验分预警阈值">
					<el-input-number v-model="scoreSettings.experienceThreshold" :min="0" :max="5" :step="0.1" />
				</el-form-item>
			</el-form>
			<template #footer>
				<span class="dialog-footer">
					<el-button @click="dialogVisible = false">取消</el-button>
					<el-button type="primary" @click="handleSaveSettings">保存设置</el-button>
				</span>
			</template>
		</el-dialog>
	</div>
</template>

<script setup lang="ts">
import { computed, onMounted, reactive, ref, watch } from 'vue';
import * as echarts from 'echarts';
import { Setting as eleSetting } from '@element-plus/icons-vue';
interface Shop {
	id: string;
	name: string;
	type: string;
	status: string;
}
interface ScoreDetail {
	date: string;
	reputationScore: number;
	experienceScore: number;
	commentCount: number;
}
const granularityOptions = [
	{ label: '小时', value: 'hour' },
	{ label: '日', value: 'day' },
	{ label: '周', value: 'week' },
	{ label: '月', value: 'month' },
	{ label: '季度', value: 'quarter' },
	{ label: '年', value: 'year' },
];
const searchParams = reactive({ shopId: 'all', shopKeyword: '', dateRange: [], granularity: 'day' });
const dateShortcuts = [
	{
		text: '最近7天',
		value: () => {
			const end = new Date();
			const start = new Date();
			start.setTime(start.getTime() - 3600 * 1000 * 24 * 7);
			return [start, end];
		},
	},
	{
		text: '最近30天',
		value: () => {
			const end = new Date();
			const start = new Date();
			start.setTime(start.getTime() - 3600 * 1000 * 24 * 30);
			return [start, end];
		},
	},
	{
		text: '最近90天',
		value: () => {
			const end = new Date();
			const start = new Date();
			start.setTime(start.getTime() - 3600 * 1000 * 24 * 90);
			return [start, end];
		},
	},
	{
		text: '今年',
		value: () => {
			const end = new Date();
			const start = new Date(new Date().getFullYear(), 0, 1);
			return [start, end];
		},
	},
	{
		text: '去年',
		value: () => {
			const end = new Date(new Date().getFullYear() - 1, 11, 31);
			const start = new Date(new Date().getFullYear() - 1, 0, 1);
			return [start, end];
		},
	},
];
const scoreSettings = reactive({ reputationThreshold: 4.0, experienceThreshold: 4.2 });
const dialogVisible = ref(false);
const shopList = ref<Shop[]>([]);
const scoreDetail = ref<ScoreDetail[]>([]);
const filteredShopList = computed(() => {
	const keyword = searchParams.shopKeyword.trim().toLowerCase();
	if (!keyword) return shopList.value;
	return shopList.value.filter((shop) => shop.name.toLowerCase().includes(keyword) || String(shop.id).toLowerCase().includes(keyword));
});
const shopPagination = reactive({ currentPage: 1, pageSize: 5, total: 0 });
const detailPagination = reactive({ currentPage: 1, pageSize: 5, total: 0 });
const pagedShopList = computed(() =>
	filteredShopList.value.slice((shopPagination.currentPage - 1) * shopPagination.pageSize, shopPagination.currentPage * shopPagination.pageSize)
);
const pagedScoreDetail = computed(() =>
	scoreDetail.value.slice((detailPagination.currentPage - 1) * detailPagination.pageSize, detailPagination.currentPage * detailPagination.pageSize)
);
const scoreChartRef = ref();
let scoreChart: echarts.ECharts | null = null;
const getMockShopList = () => [
	{ id: '1', name: '旗舰店', type: 'online', status: 'active' },
	{ id: '2', name: '华东直营网点', type: 'physical', status: 'active' },
	{ id: '3', name: '华南直营店', type: 'physical', status: 'active' },
	{ id: '4', name: '品牌商城', type: 'online', status: 'active' },
	{ id: '5', name: '北区体验店', type: 'physical', status: 'closed' },
];
const selectedShopName = computed(() => {
	if (searchParams.shopId === 'all') return '全部店铺';
	const shop = shopList.value.find((item) => String(item.id) === searchParams.shopId);
	return shop?.name || '未知店铺';
});
const DAY_IN_MS = 24 * 60 * 60 * 1000;
const toDate = (value?: string | Date) => {
	if (!value) return new Date();
	return value instanceof Date ? new Date(value.getTime()) : new Date(`${value}T00:00:00`);
};
const formatDate = (date: Date) => {
	const year = date.getFullYear();
	const month = `${date.getMonth() + 1}`.padStart(2, '0');
	const day = `${date.getDate()}`.padStart(2, '0');
	return `${year}-${month}-${day}`;
};
const getDateRange = () => {
	if (Array.isArray(searchParams.dateRange) && searchParams.dateRange.length === 2) {
		const [start, end] = searchParams.dateRange as Array<string | Date>;
		return { start: toDate(start), end: toDate(end) };
	}
	const end = new Date();
	const start = new Date(end.getTime() - 6 * DAY_IN_MS);
	return { start, end };
};
const getWeekLabel = (date: Date) => {
	const firstDay = new Date(date.getFullYear(), 0, 1);
	const dayOffset = Math.floor((date.getTime() - firstDay.getTime()) / DAY_IN_MS);
	return `${date.getFullYear()}年第${Math.floor(dayOffset / 7) + 1}周`;
};
const getQuarterLabel = (date: Date) => `${date.getFullYear()}年Q${Math.floor(date.getMonth() / 3) + 1}`;
const buildTrendLabels = () => {
	const { start, end } = getDateRange();
	const labels: string[] = [];
	const cursor = new Date(start.getTime());
	if (searchParams.granularity === 'hour') {
		return Array.from({ length: 24 }, (_, index) => `${index}:00`);
	}
	if (searchParams.granularity === 'day') {
		while (cursor <= end) {
			labels.push(formatDate(cursor));
			cursor.setDate(cursor.getDate() + 1);
		}
		return labels;
	}
	if (searchParams.granularity === 'week') {
		while (cursor <= end) {
			labels.push(getWeekLabel(cursor));
			cursor.setDate(cursor.getDate() + 7);
		}
		return [...new Set(labels)];
	}
	if (searchParams.granularity === 'month') {
		cursor.setDate(1);
		while (cursor <= end) {
			labels.push(`${cursor.getFullYear()}-${`${cursor.getMonth() + 1}`.padStart(2, '0')}`);
			cursor.setMonth(cursor.getMonth() + 1);
		}
		return labels;
	}
	if (searchParams.granularity === 'quarter') {
		cursor.setMonth(Math.floor(cursor.getMonth() / 3) * 3, 1);
		while (cursor <= end) {
			labels.push(getQuarterLabel(cursor));
			cursor.setMonth(cursor.getMonth() + 3);
		}
		return [...new Set(labels)];
	}
	cursor.setMonth(0, 1);
	while (cursor <= end) {
		labels.push(`${cursor.getFullYear()}年`);
		cursor.setFullYear(cursor.getFullYear() + 1);
	}
	return [...new Set(labels)];
};
const getShopSeed = (shopId: string) => (shopId && shopId !== 'all' ? Number(shopId) : 0);
const getMockScoreTrend = (shopId: string) => {
	const labels = buildTrendLabels();
	const seed = getShopSeed(shopId);
	const baseReputation = 4.55 - seed * 0.08;
	const baseExperience = 4.62 - seed * 0.06;
	return labels.map((date, index) => ({
		date,
		reputationScore: Number(Math.min(5, Math.max(3.2, baseReputation + Math.sin(index + seed) * 0.18 + index * 0.01)).toFixed(2)),
		experienceScore: Number(Math.min(5, Math.max(3.3, baseExperience + Math.cos(index + seed) * 0.16 + index * 0.008)).toFixed(2)),
	}));
};
const getMockScoreDetail = (shopId: string) => {
	const trend = getMockScoreTrend(shopId);
	return trend.map((item, index) => ({
		date: item.date,
		reputationScore: item.reputationScore,
		experienceScore: item.experienceScore,
		commentCount: 120 + getShopSeed(shopId) * 18 + index * 15,
	}));
};
const syncSelectedShop = () => {
	if (searchParams.shopId === 'all') return;
	const hasSelectedShop = filteredShopList.value.some((shop) => String(shop.id) === searchParams.shopId);
	if (!hasSelectedShop) {
		searchParams.shopId = 'all';
	}
};
const handleSearch = () => {
	shopPagination.currentPage = 1;
	detailPagination.currentPage = 1;
	syncSelectedShop();
	shopPagination.total = filteredShopList.value.length;
	scoreDetail.value = getMockScoreDetail(searchParams.shopId);
	detailPagination.total = scoreDetail.value.length;
	initScoreChart(getMockScoreTrend(searchParams.shopId));
};
const handleReset = () => {
	searchParams.shopId = 'all';
	searchParams.shopKeyword = '';
	searchParams.dateRange = [];
	searchParams.granularity = 'day';
	shopPagination.currentPage = 1;
	detailPagination.currentPage = 1;
	handleSearch();
};
const handleShopClick = (shop: Shop) => {
	searchParams.shopId = String(shop.id);
	handleSearch();
};
const handleShopSelect = (shopId: string) => {
	searchParams.shopId = String(shopId);
	handleSearch();
};
const handleShopPageSizeChange = (size: number) => {
	shopPagination.pageSize = size;
	shopPagination.currentPage = 1;
};
const handleShopPageChange = (page: number) => {
	shopPagination.currentPage = page;
};
const handleDetailPageSizeChange = (size: number) => {
	detailPagination.pageSize = size;
	detailPagination.currentPage = 1;
};
const handleDetailPageChange = (page: number) => {
	detailPagination.currentPage = page;
};
const openSettingDialog = () => {
	dialogVisible.value = true;
};
const handleSaveSettings = () => {
	dialogVisible.value = false;
};
const initScoreChart = (scoreTrend: Array<{ date: string; reputationScore: number; experienceScore: number }>) => {
	if (!scoreChartRef.value) return;
	if (scoreChart) scoreChart.dispose();
	scoreChart = echarts.init(scoreChartRef.value);
	const isSingle = scoreTrend.length <= 1;
	scoreChart.setOption({
		tooltip: { trigger: 'axis', axisPointer: { type: 'cross', label: { backgroundColor: '#6a7985' } } },
		legend: { data: ['口碑分', '体验分'] },
		grid: { left: '3%', right: '4%', bottom: '3%', containLabel: true },
		xAxis: { type: 'category', boundaryGap: isSingle, data: scoreTrend.map((item) => item.date) },
		yAxis: { type: 'value', name: '评分', min: 0, max: 5 },
		series: [
			{
				name: '口碑分',
				type: 'line',
				data: scoreTrend.map((item) => item.reputationScore),
				smooth: true,
				showSymbol: true,
				symbolSize: isSingle ? 10 : 6,
			},
			{
				name: '体验分',
				type: 'line',
				data: scoreTrend.map((item) => item.experienceScore),
				smooth: true,
				showSymbol: true,
				symbolSize: isSingle ? 10 : 6,
			},
		],
	});
};
watch(
	() => filteredShopList.value.length,
	(length) => {
		shopPagination.total = length;
		const maxPage = Math.max(1, Math.ceil(length / shopPagination.pageSize));
		if (shopPagination.currentPage > maxPage) {
			shopPagination.currentPage = maxPage;
		}
	}
);
watch(
	() => searchParams.granularity,
	() => handleSearch()
);
onMounted(() => {
	shopList.value = getMockShopList();
	shopPagination.total = shopList.value.length;
	handleSearch();
	window.addEventListener('resize', () => scoreChart?.resize());
});
</script>

<style scoped>
.trade-operation-analysis-shop {
	padding: 20px;
}
.card-header {
	display: flex;
	align-items: center;
	justify-content: space-between;
	font-size: 16px;
	font-weight: 600;
}
.setting-btn {
	display: flex;
	align-items: center;
	gap: 4px;
}
.search-container {
	margin-bottom: 16px;
}
.search-form {
	display: flex;
	align-items: center;
	flex-wrap: wrap;
}
.search-form :deep(.el-form-item) {
	margin-right: 12px;
	margin-bottom: 12px;
}
.granularity-group {
	flex-wrap: wrap;
}
.shop-list {
	margin-bottom: 20px;
}
.chart-container {
	margin: 0 0 20px;
}
.chart {
	width: 100%;
	height: 400px;
}
.score-detail {
	margin-top: 20px;
}
.score-item {
	padding: 2px 8px;
	border-radius: 10px;
	display: inline-block;
}
.score-item.warning {
	background-color: #fde2e2;
	color: #f56c6c;
}
.pagination-container {
	margin-top: 16px;
	display: flex;
	justify-content: flex-end;
}
</style>
