﻿<template>
	<view class="app-page" :class="themeClass">
		<section-card title="报表总览" subtitle="按月份查看收支分布、消费趋势和月度对比">
			<template #action>
				<picker mode="date" fields="month" :value="monthPickerValue" @change="onMonthChange">
					<text class="section-link">{{ selectedMonthLabel }}</text>
				</picker>
			</template>
			<view class="summary-row">
				<view class="summary-item surface-strong">
					<text class="tiny-text">支出</text>
					<text class="summary-value negative">{{ formatCurrency(monthExpenseTotal) }}</text>
				</view>
				<view class="summary-item surface-strong">
					<text class="tiny-text">收入</text>
					<text class="summary-value positive">{{ formatCurrency(monthIncomeTotal) }}</text>
				</view>
				<view class="summary-item surface-strong">
					<text class="tiny-text">结余</text>
					<text class="summary-value">{{ formatCurrency(monthIncomeTotal - monthExpenseTotal) }}</text>
				</view>
			</view>
		</section-card>
		<ad-custom unit-id="adunit-74730c6c27c95a37"></ad-custom>
		<section-card title="支出分类" subtitle="查看本月主要消费去向与占比结构">
			<view v-if="categoryStats.length" class="chart-list">
				<view v-for="item in categoryStats" :key="item.id" class="chart-row">
					<view class="chart-head">
						<view class="chart-title-row">
							<view class="chart-dot" :style="{ background: item.color }"></view>
							<text class="chart-title">{{ item.name }}</text>
						</view>
						<text class="tiny-text">{{ formatCurrency(item.total) }} · {{ item.percentLabel }}</text>
					</view>
					<view class="bar-track"><view class="bar-fill" :style="{ width: item.percentWidth, background: item.color }"></view></view>
				</view>
			</view>
			<view v-else class="empty-card"><text class="section-subtitle">当前月份暂无支出数据，记一笔后会自动生成图表。</text></view>
		</section-card>

		<section-card title="近 7 日趋势" subtitle="观察近一周消费变化，便于发现异常高峰">
			<view class="column-chart">
				<view v-for="item in dailySeries" :key="item.date" class="column-item">
					<view class="column-track"><view class="column-fill" :style="{ height: item.height }"></view></view>
					<text class="tiny-text">{{ item.label }}</text>
					<text class="tiny-text">{{ item.value === 0 ? '-' : item.value }}</text>
				</view>
			</view>
		</section-card>

		<section-card title="月度对比" subtitle="最近 6 个月收入与支出走势一目了然">
			<view class="compare-list">
				<view v-for="item in monthCompare" :key="item.month" class="compare-row">
					<text class="compare-label">{{ item.label }}</text>
					<view class="compare-bars">
						<view class="mini-track"><view class="mini-fill expense-fill" :style="{ width: item.expenseWidth }"></view></view>
						<view class="mini-track"><view class="mini-fill income-fill" :style="{ width: item.incomeWidth }"></view></view>
					</view>
					<text class="tiny-text">{{ formatCurrency(item.expense) }} / {{ formatCurrency(item.income) }}</text>
				</view>
			</view>
		</section-card>

		<section-card title="导出与分享" subtitle="支持导出当月 CSV 账单与生成分享文案">
			<view class="action-grid">
				<view class="primary-button" @click="exportCsv">导出 CSV</view>
				<view class="ghost-button" @click="posterVisible = true">分享摘要</view>
			</view>
		</section-card>

		<view v-if="posterVisible" class="poster-shell" @touchmove.stop.prevent="">
			<view class="poster-mask" @click="posterVisible = false"></view>
			<view class="surface-card poster-panel">
				<view class="poster-card">
					<text class="poster-month">{{ selectedMonthLabel }}</text>
					<text class="poster-title">收支月报</text>
					<text class="poster-line">支出 {{ formatCurrency(monthExpenseTotal) }}</text>
					<text class="poster-line">收入 {{ formatCurrency(monthIncomeTotal) }}</text>
					<text class="poster-line">结余 {{ formatCurrency(monthIncomeTotal - monthExpenseTotal) }}</text>
					<text class="poster-tip">内容本地生成，可复制摘要或直接截图分享。</text>
				</view>
				<view class="action-grid">
					<view class="ghost-button" @click="copyPosterText">复制摘要</view>
					<view class="primary-button" @click="posterVisible = false">关闭</view>
				</view>
			</view>
		</view>

		<app-tab-bar current="stats" />
	</view>
</template>

<script setup>
import { computed, ref } from 'vue'
import { onShareAppMessage } from '@dcloudio/uni-app'
import SectionCard from '../../components/SectionCard.vue'
import AppTabBar from '../../components/AppTabBar.vue'
import { useAppStore } from '../../utils/store'
import { formatMonthLabel, getMonthSeries, getRecentDateKeys, isSameMonth, toDateKey, toMonthKey } from '../../utils/date'
import { clampPercent, formatCurrency, formatPercent } from '../../utils/money'

const store = useAppStore()
const monthValue = ref(toMonthKey())
const posterVisible = ref(false)
const themeClass = computed(() => (store.state.settings.theme === 'dark' ? 'theme-dark' : ''))
const selectedMonthKey = computed(() => monthValue.value.slice(0, 7))
const selectedMonthLabel = computed(() => formatMonthLabel(selectedMonthKey.value))
const monthPickerValue = computed(() => monthValue.value)

const monthBills = computed(() => store.state.bills.filter((item) => isSameMonth(item.date, selectedMonthKey.value)))
const monthExpenseBills = computed(() => monthBills.value.filter((item) => item.type === 'expense'))
const monthExpenseTotal = computed(() => monthExpenseBills.value.reduce((sum, item) => sum + Number(item.amount), 0))
const monthIncomeTotal = computed(() => monthBills.value.filter((item) => item.type === 'income').reduce((sum, item) => sum + Number(item.amount), 0))

const categoryStats = computed(() => {
	const total = Math.max(monthExpenseTotal.value, 1)
	return store.state.categories.expense
		.map((category) => {
			const categoryTotal = monthExpenseBills.value
				.filter((item) => item.categoryId === category.id)
				.reduce((sum, item) => sum + Number(item.amount), 0)
			return {
				...category,
				total: categoryTotal,
				percentLabel: formatPercent(categoryTotal / total),
				percentWidth: clampPercent(categoryTotal / total)
			}
		})
		.filter((item) => item.total > 0)
		.sort((left, right) => right.total - left.total)
})

const dailySeries = computed(() => {
	const [year, month] = selectedMonthKey.value.split('-').map(Number)
	const today = toDateKey()
	const monthEnd = new Date(year, month, 0)
	const endDate = toMonthKey(today) === selectedMonthKey.value ? new Date() : monthEnd
	const dateKeys = getRecentDateKeys(7, endDate)
	const maxValue = Math.max(1, ...dateKeys.map((dateKey) => monthExpenseBills.value
		.filter((item) => item.date === dateKey)
		.reduce((sum, item) => sum + Number(item.amount), 0)))

	return dateKeys.map((dateKey) => {
		const value = monthExpenseBills.value
			.filter((item) => item.date === dateKey)
			.reduce((sum, item) => sum + Number(item.amount), 0)
		return {
			date: dateKey,
			label: dateKey.slice(5),
			value: Number(value.toFixed(2)),
			height: `${Math.max(8, (value / maxValue) * 100)}%`
		}
	})
})

const monthCompare = computed(() => {
	const series = getMonthSeries(6, selectedMonthKey.value)
	const maxExpense = Math.max(1, ...series.map((month) => store.state.bills
		.filter((item) => item.type === 'expense' && isSameMonth(item.date, month))
		.reduce((sum, item) => sum + Number(item.amount), 0)))
	const maxIncome = Math.max(1, ...series.map((month) => store.state.bills
		.filter((item) => item.type === 'income' && isSameMonth(item.date, month))
		.reduce((sum, item) => sum + Number(item.amount), 0)))

	return series.map((month) => {
		const expense = store.state.bills
			.filter((item) => item.type === 'expense' && isSameMonth(item.date, month))
			.reduce((sum, item) => sum + Number(item.amount), 0)
		const income = store.state.bills
			.filter((item) => item.type === 'income' && isSameMonth(item.date, month))
			.reduce((sum, item) => sum + Number(item.amount), 0)
		return {
			month,
			label: month.slice(5),
			expense,
			income,
			expenseWidth: `${Math.max(8, (expense / maxExpense) * 100)}%`,
			incomeWidth: `${Math.max(8, (income / maxIncome) * 100)}%`
		}
	})
})

function onMonthChange(event) {
	monthValue.value = String(event.detail.value).slice(0, 7)
}

function categoryNameOf(bill) {
	return (store.state.categories[bill.type] || []).find((item) => item.id === bill.categoryId)?.name || '未分类'
}

function accountNameOf(bill) {
	return store.state.accounts.find((item) => item.id === bill.accountId)?.name || '未知账户'
}

function escapeCsvCell(value) {
	const text = String(value ?? '')
	if (!/[",\n]/.test(text)) {
		return text
	}
	return `"${text.replace(/"/g, '""')}"`
}

function writeTextToFile(fileName, content, successText) {
	if (typeof wx !== 'undefined' && wx.getFileSystemManager) {
		const filePath = `${wx.env.USER_DATA_PATH}/${fileName}`
		wx.getFileSystemManager().writeFile({
			filePath,
			data: content,
			encoding: 'utf8',
			success: () => {
				uni.showModal({
					title: successText,
					content: `文件已生成：${filePath}`,
					showCancel: false
				})
			},
			fail: () => {
				uni.setClipboardData({ data: content })
			}
		})
		return
	}

	uni.setClipboardData({ data: content })
}

function exportCsv() {
	const header = '\uFEFF日期,类型,分类,账户,金额,备注'
	const rows = monthBills.value.map((bill) => [
		escapeCsvCell(bill.date),
		escapeCsvCell(bill.type === 'income' ? '收入' : '支出'),
		escapeCsvCell(categoryNameOf(bill)),
		escapeCsvCell(accountNameOf(bill)),
		escapeCsvCell(Number(bill.amount).toFixed(2)),
		escapeCsvCell(bill.note || '')
	].join(','))
	writeTextToFile(`账单-${selectedMonthKey.value}.csv`, [header, ...rows].join('\n'), 'CSV 导出成功')
}

function copyPosterText() {
	const message = `${selectedMonthLabel.value}，支出 ${formatCurrency(monthExpenseTotal.value)}，收入 ${formatCurrency(monthIncomeTotal.value)}，结余 ${formatCurrency(monthIncomeTotal.value - monthExpenseTotal.value)}。`
	uni.setClipboardData({ data: message })
}

onShareAppMessage(() => ({
	title: `${selectedMonthLabel.value}收支摘要`,
	path: '/pages/stats/index'
}))
</script>

<style lang="scss" scoped>
.summary-row,
.action-grid {
	display: flex;
	gap: 16rpx;
}

.summary-item {
	flex: 1;
	padding: 22rpx;
	border-radius: 24rpx;
}

.summary-value {
	display: block;
	margin-top: 10rpx;
	font-size: 30rpx;
	font-weight: 700;
	color: var(--text-primary);
}

.section-link {
	font-size: 24rpx;
	color: var(--brand);
}

.chart-list,
.compare-list {
	display: flex;
	flex-direction: column;
	gap: 18rpx;
}

.chart-head,
.chart-title-row,
.compare-row {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 16rpx;
}

.chart-dot {
	width: 16rpx;
	height: 16rpx;
	border-radius: 50%;
}

.chart-title {
	font-size: 28rpx;
	font-weight: 600;
	color: var(--text-primary);
}

.bar-track,
.mini-track,
.column-track {
	overflow: hidden;
	border-radius: 999rpx;
	background: var(--surface-muted);
}

.bar-track {
	height: 16rpx;
	margin-top: 12rpx;
}

.bar-fill,
.mini-fill {
	height: 100%;
	border-radius: inherit;
}

.column-chart {
	display: grid;
	grid-template-columns: repeat(7, minmax(0, 1fr));
	gap: 12rpx;
	align-items: end;
	height: 260rpx;
}

.column-item {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 10rpx;
}

.column-track {
	display: flex;
	align-items: flex-end;
	justify-content: center;
	width: 100%;
	height: 180rpx;
	padding: 0 6rpx;
}

.column-fill {
	width: 100%;
	border-radius: 999rpx 999rpx 16rpx 16rpx;
	background: linear-gradient(180deg, #5f8df5 0%, #1f6f5f 100%);
}

.compare-label {
	width: 64rpx;
	font-size: 24rpx;
	color: var(--text-secondary);
}

.compare-bars {
	flex: 1;
	display: flex;
	flex-direction: column;
	gap: 10rpx;
}

.mini-track {
	height: 12rpx;
}

.expense-fill {
	background: #d36c43;
}

.income-fill {
	background: #1f6f5f;
}

.action-grid {
	margin-top: 8rpx;
}

.action-grid .primary-button,
.action-grid .ghost-button {
	flex: 1;
}

.empty-card {
	padding: 32rpx 0 10rpx;
	text-align: center;
}

.poster-shell {
	position: fixed;
	inset: 0;
	z-index: 50;
}

.poster-mask {
	position: absolute;
	inset: 0;
	background: rgba(4, 12, 18, 0.42);
}

.poster-panel {
	position: absolute;
	left: 24rpx;
	right: 24rpx;
	top: 16vh;
	padding: 28rpx;
}

.poster-card {
	padding: 32rpx;
	border-radius: 28rpx;
	background: linear-gradient(145deg, #102a43 0%, #1f6f5f 100%);
	color: #ffffff;
	margin-bottom: 20rpx;
}

.poster-month,
.poster-tip {
	color: rgba(255, 255, 255, 0.76);
}

.poster-title {
	display: block;
	margin: 12rpx 0 20rpx;
	font-size: 42rpx;
	font-weight: 700;
}

.poster-line {
	display: block;
	margin-bottom: 12rpx;
	font-size: 28rpx;
}

.poster-tip {
	display: block;
	margin-top: 24rpx;
	font-size: 22rpx;
	line-height: 1.6;
}
</style>
