<template>

  <view class="page">

    <view class="header-hero" :style="{ paddingTop: statusBarHeight + 'px' }">

      <view class="top-bar">

        <view class="top-left" @click="goBack">

          <AppIcon name="chevronLeft" size="sm" color="white" />

        </view>

        <view class="top-center">

          <text class="page-title">Label Report</text>

          <LocationPicker />

        </view>

        <view class="top-right" @click="isMenuOpen = true">

          <AppIcon name="menu" size="sm" color="white" />

        </view>

      </view>

    </view>



    <view class="period-bar">

      <view

        v-for="p in periodOptions"

        :key="p.value"

        class="period-btn"

        :class="{ active: period === p.value }"

        @click="selectPeriod(p.value)"

      >

        <text class="period-text">{{ p.label }}</text>

      </view>

    </view>



    <view v-if="period === 'custom'" class="custom-date-bar">

      <view class="date-field">

        <text class="date-label">Start</text>

        <AppDatePicker

          v-model="customStart"

          :max="customEnd || '2099-12-31'"

          placeholder="Select"

          dialog-title="Start date"

        />

      </view>

      <view class="date-field">

        <text class="date-label">End</text>

        <AppDatePicker

          v-model="customEnd"

          :min="customStart || '2000-01-01'"

          placeholder="Select"

          dialog-title="End date"

        />

      </view>

    </view>



    <scroll-view class="content" scroll-y>

      <view v-if="loading" class="state-block">

        <text class="state-text">Loading…</text>

      </view>



      <template v-else>

        <!-- 指标卡 -->

        <view class="metrics-grid">

          <view class="metric-card">

            <text class="metric-label">Total Labels Printed</text>

            <text class="metric-value">{{ totalPrintedDisplay }}</text>

            <text class="metric-trend" :class="totalChangeClass">{{ totalChangeText }}</text>

          </view>

          <view class="metric-card">

            <text class="metric-label">Most Printed Category</text>

            <text class="metric-value">{{ topCategoryName }}</text>

            <text class="metric-trend">{{ topCategorySubtext }}</text>

          </view>

          <view class="metric-card">

            <text class="metric-label">Top Product</text>

            <text class="metric-value">{{ topProductName }}</text>

            <text class="metric-trend">{{ topProductSubtext }}</text>

          </view>

          <view class="metric-card">

            <text class="metric-label">Avg. Daily Prints</text>

            <text class="metric-value">{{ avgDailyDisplay }}</text>

            <text class="metric-trend" :class="avgChangeClass">{{ avgChangeText }}</text>

          </view>

        </view>



        <!-- 柱状图 -->

        <view class="section">

          <text class="section-title">Labels by Category</text>

          <text class="section-desc">Distribution of printed labels across product categories.</text>

          <view v-if="!categoryChart.length" class="empty-panel">

            <text class="empty-text">No category data for this period</text>

          </view>

          <view v-else class="bar-chart">

            <view v-for="item in categoryChart" :key="item.key" class="bar-row">

              <text class="bar-label">{{ item.name }}</text>

              <view class="bar-track">

                <view class="bar-fill" :style="{ width: item.percent + '%' }" />

              </view>

              <text class="bar-value">{{ item.value }}</text>

            </view>

          </view>

        </view>



        <!-- 走势图 -->

        <view class="section">

          <text class="section-title">Print Volume Trends</text>

          <text class="section-desc">{{ trendDescription }}</text>

          <view v-if="!trendChart.length" class="empty-panel">

            <text class="empty-text">No trend data for this period</text>

          </view>

          <view v-else class="line-chart">

            <view class="chart-bars">

              <view v-for="(bar, i) in trendChart" :key="'t-' + i" class="day-bar-wrap">

                <view class="day-bar" :style="{ height: bar.heightPct + '%' }" />

              </view>

            </view>

            <view class="chart-labels">

              <text v-for="(bar, i) in trendChart" :key="'l-' + i" class="day-label">{{ bar.label }}</text>

            </view>

          </view>

        </view>



        <!-- 最常用产品列表 -->

        <view class="section">

          <text class="section-title">Most Used Products</text>

          <view class="product-table">

            <view class="product-row header">

              <text class="col-name">Product Name</text>

              <text class="col-cat">Category</text>

              <text class="col-total">Total Printed</text>

              <text class="col-pct">Usage %</text>

            </view>

            <view v-if="!topProducts.length" class="product-row empty-row">

              <text class="empty-row-text">No products in this period</text>

            </view>

            <view v-for="p in topProducts" :key="p.key" class="product-row">

              <text class="col-name">{{ p.name }}</text>

              <text class="col-cat">{{ p.category }}</text>

              <text class="col-total">{{ p.total }}</text>

              <text class="col-pct">{{ p.usage }}%</text>

            </view>

          </view>

        </view>

      </template>

    </scroll-view>



    <SideMenu v-model="isMenuOpen" />

  </view>

</template>



<script setup lang="ts">

import { ref, computed, watch } from 'vue'

import { onShow } from '@dcloudio/uni-app'

import AppIcon from '../../components/AppIcon.vue'

import AppDatePicker from '../../components/AppDatePicker.vue'

import SideMenu from '../../components/SideMenu.vue'

import LocationPicker from '../../components/LocationPicker.vue'

import { getStatusBarHeight } from '../../utils/statusBar'

import { getCurrentStoreId } from '../../utils/stores'

import { fetchUsAppLabelReport } from '../../services/usAppLabeling'

import type { UsAppLabelReportOutputDto, UsAppLabelReportPeriod } from '../../types/usAppLabeling'

import { isUsAppSessionExpiredError } from '../../utils/usAppApiRequest'

import { formatDisplayText } from '../../utils/emptyDisplay'



const statusBarHeight = getStatusBarHeight()

const isMenuOpen = ref(false)

const loading = ref(false)

const period = ref<UsAppLabelReportPeriod>('7d')

const customStart = ref('')

const customEnd = ref('')

const report = ref<UsAppLabelReportOutputDto | null>(null)



const periodOptions = [

  { value: '7d' as const, label: 'Last 7 Days' },

  { value: '30d' as const, label: 'Last 30 Days' },

  { value: '90d' as const, label: 'Last 90 Days' },

  { value: 'custom' as const, label: 'Custom' },

]



function formatDate(d: Date): string {

  const y = d.getFullYear()

  const m = String(d.getMonth() + 1).padStart(2, '0')

  const day = String(d.getDate()).padStart(2, '0')

  return `${y}-${m}-${day}`

}



function selectPeriod(val: UsAppLabelReportPeriod) {

  period.value = val

  if (val === 'custom') {

    const today = formatDate(new Date())

    const weekAgo = new Date()

    weekAgo.setDate(weekAgo.getDate() - 7)

    customStart.value = customStart.value || formatDate(weekAgo)

    customEnd.value = customEnd.value || today

  }

  loadReport()

}



watch(customStart, (start) => {

  if (!start || !customEnd.value) return

  if (start > customEnd.value) customEnd.value = start

})



watch([customStart, customEnd], () => {

  if (period.value === 'custom' && customStart.value && customEnd.value) {

    loadReport()

  }

})



function formatNumber(n: number): string {

  return Math.round(n).toLocaleString('en-US')

}



function formatChangeRate(rate: number): { text: string; cls: string } {

  const r = Number(rate)

  if (!Number.isFinite(r) || r === 0) {

    return { text: 'No change vs previous period', cls: '' }

  }

  const sign = r > 0 ? '+' : ''

  const cls = r > 0 ? 'up' : 'down'

  return {

    text: `${sign}${r.toFixed(1)}% vs previous period`,

    cls,

  }

}



const summary = computed(() => report.value?.summary)



const totalPrintedDisplay = computed(() =>

  formatNumber(summary.value?.totalLabelsPrinted ?? 0),

)



const totalChangeText = computed(() =>

  formatChangeRate(summary.value?.totalLabelsPrintedChangeRate ?? 0).text,

)

const totalChangeClass = computed(() =>

  formatChangeRate(summary.value?.totalLabelsPrintedChangeRate ?? 0).cls,

)



const topCategoryName = computed(() =>

  formatDisplayText(summary.value?.mostPrintedCategoryName, 'None'),

)

const topCategorySubtext = computed(() => {

  const n = summary.value?.mostPrintedCategoryCount ?? 0

  return n > 0 ? `${formatNumber(n)} labels generated` : 'No labels in period'

})



const topProductName = computed(() =>

  formatDisplayText(summary.value?.topProductName, 'None'),

)

const topProductSubtext = computed(() => {

  const n = summary.value?.topProductCount ?? 0

  return n > 0 ? `${formatNumber(n)} labels generated` : 'No labels in period'

})



const avgDailyDisplay = computed(() => {

  const v = summary.value?.avgDailyPrints ?? 0

  const rounded = Math.round(v * 10) / 10

  return rounded % 1 === 0 ? String(Math.round(rounded)) : rounded.toFixed(1)

})



const avgChangeText = computed(() =>

  formatChangeRate(summary.value?.avgDailyPrintsChangeRate ?? 0).text,

)

const avgChangeClass = computed(() =>

  formatChangeRate(summary.value?.avgDailyPrintsChangeRate ?? 0).cls,

)



const trendDescription = computed(() => {

  const fromApi = report.value?.appliedRange?.trendDescription?.trim()

  if (fromApi) return fromApi

  const days = report.value?.appliedRange?.dayCount

  if (days && days > 7) {

    return `Daily label printing volume for the last ${days} days.`

  }

  return 'Daily label printing volume for the selected period.'

})



const categoryChart = computed(() => {

  const rows = report.value?.labelsByCategory ?? []

  const max = Math.max(1, ...rows.map((d) => d.count))

  return rows.map((d, i) => ({

    key: (d.categoryId || d.categoryName || 'cat') + i,

    name: formatDisplayText(d.categoryName, 'Uncategorized'),

    value: formatNumber(d.count),

    percent: (d.count / max) * 100,

  }))

})



function formatTrendMd(dateStr: string): string {

  const m = /^(\d{4})-(\d{2})-(\d{2})/.exec(dateStr)

  if (!m) return dateStr.slice(5) || dateStr

  return `${m[2]}/${m[3]}`

}



const trendChart = computed(() => {

  const pts = report.value?.printVolumeTrend ?? []

  if (!pts.length) return []

  const max = Math.max(1, ...pts.map((p) => p.count))

  const n = pts.length

  const labelStep = n <= 7 ? 1 : Math.max(1, Math.ceil(n / 6))

  return pts.map((p, i) => ({

    heightPct: (p.count / max) * 100,

    label: i % labelStep === 0 || i === n - 1 ? formatTrendMd(p.date) : '',

  }))

})



const topProducts = computed(() =>

  (report.value?.mostUsedProducts ?? []).map((p, i) => ({

    key: (p.productId || p.productName) + i,

    name: formatDisplayText(p.productName, 'None'),

    category: formatDisplayText(p.categoryName, '—'),

    total: formatNumber(p.totalPrinted),

    usage: Number(p.usagePercent).toFixed(1),

  })),

)



let loadSeq = 0



async function loadReport() {

  const locationId = getCurrentStoreId()

  if (!locationId) {

    report.value = null

    return

  }

  if (period.value === 'custom' && (!customStart.value || !customEnd.value)) {

    return

  }



  const seq = ++loadSeq

  loading.value = true

  try {

    const data = await fetchUsAppLabelReport({

      locationId,

      period: period.value,

      startDate: period.value === 'custom' ? customStart.value : undefined,

      endDate: period.value === 'custom' ? customEnd.value : undefined,

    })

    if (seq !== loadSeq) return

    report.value = data

  } catch (e) {

    if (seq !== loadSeq) return

    if (!isUsAppSessionExpiredError(e)) {

      const msg = e instanceof Error ? e.message : 'Load failed'

      uni.showToast({ title: msg, icon: 'none', duration: 2500 })

    }

    report.value = null

  } finally {

    if (seq === loadSeq) loading.value = false

  }

}



onShow(() => {

  loadReport()

})



const goBack = () => {

  const pages = getCurrentPages()

  if (pages.length > 1) {

    uni.navigateBack()

  } else {

    uni.redirectTo({ url: '/pages/index/index' })

  }

}

</script>



<style scoped>

.page {

  min-height: 100vh;

  background: #f3f4f6;

  display: flex;

  flex-direction: column;

}



.header-hero {

  background: linear-gradient(135deg, #1F3A8A, #142a6c);

  padding: 16rpx 32rpx 24rpx;

}



.top-bar {

  height: 96rpx;

  display: flex;

  align-items: center;

  justify-content: space-between;

}



.top-left, .top-right {

  width: 64rpx;

  height: 64rpx;

  border-radius: 999rpx;

  background: rgba(255, 255, 255, 0.15);

  display: flex;

  align-items: center;

  justify-content: center;

}



.top-center {

  flex: 1;

  display: flex;

  flex-direction: column;

  align-items: center;

}



.page-title {

  font-size: 34rpx;

  font-weight: 600;

  color: #fff;

}



.period-bar {

  display: flex;

  gap: 12rpx;

  padding: 16rpx 28rpx;

  background: #fff;

  border-bottom: 1rpx solid #e5e7eb;

}



.period-btn {

  flex: 1;

  padding: 16rpx 24rpx;

  border-radius: 12rpx;

  background: #f3f4f6;

  text-align: center;

  transition: all 0.2s;

}



.period-btn.active {

  background: linear-gradient(135deg, #1F3A8A, #1447E6);

}



.period-btn.active .period-text {

  color: #fff;

}



.period-text {

  font-size: 26rpx;

  font-weight: 500;

  color: #6b7280;

}



.custom-date-bar {

  display: flex;

  gap: 24rpx;

  padding: 20rpx 28rpx;

  background: #fff;

  border-bottom: 1rpx solid #e5e7eb;

}



.date-field {

  flex: 1;

  display: flex;

  flex-direction: column;

  gap: 8rpx;

}



.date-label {

  font-size: 24rpx;

  color: #6b7280;

  font-weight: 500;

}



.content {

  flex: 1;

  padding: 24rpx 28rpx 40rpx;

  box-sizing: border-box;

}



.state-block {

  padding: 80rpx 0;

  text-align: center;

}



.state-text {

  font-size: 28rpx;

  color: #6b7280;

}



.metrics-grid {

  display: grid;

  grid-template-columns: 1fr 1fr;

  gap: 20rpx;

  margin-bottom: 32rpx;

}



.metric-card {

  background: #fff;

  padding: 28rpx;

  border-radius: 20rpx;

  box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.04);

  border: 1rpx solid #e5e7eb;

}



.metric-label {

  font-size: 24rpx;

  color: #6b7280;

  display: block;

  margin-bottom: 12rpx;

  line-height: 1.5;

}



.metric-value {

  font-size: 38rpx;

  font-weight: 700;

  color: #111827;

  display: block;

  margin-bottom: 8rpx;

  letter-spacing: -0.02em;

}



.metric-trend {

  font-size: 24rpx;

  color: #6b7280;

}



.metric-trend.up {

  color: #16a34a;

  font-weight: 500;

}



.metric-trend.down {

  color: #dc2626;

  font-weight: 500;

}



.section {

  margin-bottom: 32rpx;

}



.section-title {

  font-size: 32rpx;

  font-weight: 600;

  color: #111827;

  display: block;

  margin-bottom: 8rpx;

}



.section-desc {

  font-size: 26rpx;

  color: #6b7280;

  display: block;

  margin-bottom: 24rpx;

  line-height: 1.5;

}



.empty-panel {

  background: #fff;

  padding: 48rpx 28rpx;

  border-radius: 20rpx;

  border: 1rpx solid #e5e7eb;

  text-align: center;

}



.empty-text {

  font-size: 26rpx;

  color: #9ca3af;

}



.bar-chart {

  background: #fff;

  padding: 28rpx;

  border-radius: 20rpx;

  box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.04);

  border: 1rpx solid #e5e7eb;

}



.bar-row {

  display: flex;

  align-items: center;

  gap: 16rpx;

  margin-bottom: 24rpx;

}



.bar-row:last-child {

  margin-bottom: 0;

}



.bar-label {

  width: 120rpx;

  font-size: 26rpx;

  color: #374151;

  flex-shrink: 0;

  font-weight: 500;

}



.bar-track {

  flex: 1;

  height: 36rpx;

  background: #f3f4f6;

  border-radius: 10rpx;

  overflow: hidden;

}



.bar-fill {

  height: 100%;

  background: linear-gradient(90deg, #1F3A8A, #1447E6);

  border-radius: 10rpx;

  transition: width 0.3s ease;

}



.bar-value {

  width: 88rpx;

  text-align: right;

  font-size: 26rpx;

  font-weight: 600;

  color: #111827;

}



.line-chart {

  background: #fff;

  padding: 28rpx;

  border-radius: 20rpx;

  box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.04);

  border: 1rpx solid #e5e7eb;

}



.chart-bars {

  display: flex;

  align-items: flex-end;

  justify-content: space-between;

  gap: 4rpx;

  height: 220rpx;

  margin-bottom: 20rpx;

}



.day-bar-wrap {

  flex: 1;

  display: flex;

  align-items: flex-end;

  justify-content: center;

  min-width: 0;

}



.day-bar {

  width: 100%;

  max-width: 52rpx;

  min-height: 12rpx;

  background: linear-gradient(180deg, #1F3A8A, #1447E6);

  border-radius: 10rpx 10rpx 0 0;

  transition: height 0.3s ease;

}



.chart-labels {

  display: flex;

  justify-content: space-between;

  gap: 4rpx;

}



.day-label {

  flex: 1;

  min-width: 0;

  padding: 0 2rpx;

  font-size: 20rpx;

  color: #6b7280;

  text-align: center;

  overflow: hidden;

  text-overflow: ellipsis;

  white-space: nowrap;

}



.product-table {

  background: #fff;

  border-radius: 20rpx;

  overflow: hidden;

  box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.04);

  border: 1rpx solid #e5e7eb;

}



.product-row {

  display: flex;

  padding: 24rpx 28rpx;

  border-bottom: 1rpx solid #e5e7eb;

  font-size: 28rpx;

}



.product-row:last-child {

  border-bottom: none;

}



.product-row.header {

  background: #fafbfc;

  font-weight: 600;

  color: #6b7280;

  font-size: 24rpx;

}



.product-row.empty-row {

  justify-content: center;

}



.empty-row-text {

  font-size: 26rpx;

  color: #9ca3af;

}



.col-name { flex: 1; min-width: 0; text-align: left; }

.col-cat { flex: 0 0 140rpx; text-align: left; }

.col-total { flex: 0 0 120rpx; text-align: left; }

.col-pct { flex: 0 0 88rpx; text-align: left; }



.product-row:not(.header) .col-name { color: #111827; font-weight: 500; }

.product-row:not(.header) .col-cat { color: #6b7280; }

.product-row:not(.header) .col-total { color: #111827; }

.product-row:not(.header) .col-pct { color: #1F3A8A; font-weight: 600; }

</style>

