<template>
  <view :style="themePickerRootStyle">
    <AppNavbar title="月度统计" />

    <view class="page statistics-page">
      <view class="panel chart-panel">
        <view class="chart-toolbar">
          <view class="chart-legend">
            <view v-for="item in chartLegendItems" :key="item.name" class="legend-item">
              <text class="legend-dot" :style="{ backgroundColor: item.color }" />
              <text class="legend-text">{{ item.name }}</text>
            </view>
          </view>
          <ThemePicker
            class="year-picker"
            mode="selector"
            :range="yearOptionLabels"
            :value="selectedYearIndex"
            @change="setYearFromPicker"
          >
            <AtButton class="year-btn">{{ year }} 年</AtButton>
          </ThemePicker>
        </view>
        <canvas
          :canvas-id="chartCanvasId"
          :id="chartCanvasId"
          :width="chartSize.width"
          :height="chartSize.height"
          class="statistics-chart"
          :style="chartStyle"
          @touchstart="handleChartTouch"
        />
      </view>
      <AppTabBar />
    </view>
  </view>
</template>

<script setup lang="ts">
import UCharts from '@qiun/ucharts'
import Taro, { useDidShow, useReady } from '@tarojs/taro'
import { computed, reactive, ref } from 'vue'
import {
  getCollaborationMonthlyStatisticsApi,
  type CollaborationMonthlyStatisticsDTO
} from '@/api/collaboration'
import { isLoggedIn, redirectToLogin } from '@/utils/auth'
import AppNavbar from '@/components/AppNavbar.vue'
import ThemePicker from '@/components/ThemePicker.vue'
import { useThemePickerLockedRootStyle } from '@/components/themePickerLock'
import AppTabBar from '@/custom-tab-bar/index.vue'
import { themeTokens } from '@/theme/tokens'

type StatisticsAmountField =
  | 'purchasePrice'
  | 'expenditureAmount'
  | 'settledRemuneration'
  | 'settledTotal'

interface StatisticsSeriesDefinition {
  name: string
  field: StatisticsAmountField
  color: string
}

interface SelectorPickerChangeEvent {
  detail?: {
    value?: number | string
  }
}

const chartCanvasId = 'monthlyStatisticsChart'
const themePickerRootStyle = useThemePickerLockedRootStyle()
const minYear = 2013
const minChartHeight = 240
const minChartWidth = 280
const designWidth = 750
const defaultStatusBarHeight = 20
const defaultNavContentHeight = 44
const statisticsPageTopPadding = 24
const statisticsPageBottomPadding = 132
const chartToolbarHeight = 64
const h5RootDesignRatio = 40
const statisticSeriesDefinitions: StatisticsSeriesDefinition[] = [
  { name: '拍单费用', field: 'purchasePrice', color: themeTokens.color.warning },
  { name: '支出费用', field: 'expenditureAmount', color: themeTokens.color.danger },
  { name: '已结稿费', field: 'settledRemuneration', color: themeTokens.color.info },
  { name: '已结总费用', field: 'settledTotal', color: themeTokens.color.success }
]
const chartColors = statisticSeriesDefinitions.map(item => item.color)
const chartLegendItems = statisticSeriesDefinitions.map(({ name, color }) => ({ name, color }))
const chartCategories = Array.from({ length: 12 }, (_, index) => `${index + 1}月`)
const year = ref(new Date().getFullYear())
const statistics = ref<CollaborationMonthlyStatisticsDTO[]>([])
const isChartReady = ref(false)
const chartSize = reactive({ width: 320, height: minChartHeight })
let monthlyChart: UCharts | undefined

const yearOptions = computed(() => buildYearOptions(new Date().getFullYear()))
const yearOptionLabels = computed(() => yearOptions.value.map(item => item.text))
const selectedYearIndex = computed(() => getYearOptionIndex(year.value))
const chartStyle = computed(() => ({
  width: `${chartSize.width}px`,
  height: `${chartSize.height}px`
}))

useReady(() => {
  syncChartSize()
  isChartReady.value = true
  renderMonthlyChart()
})

useDidShow(() => {
  if (!isLoggedIn()) {
    redirectToLogin()
    return
  }
  loadStatistics()
})

async function loadStatistics() {
  try {
    const { data } = await getCollaborationMonthlyStatisticsApi(year.value)
    statistics.value = normalizeStatistics(data || [])
    renderMonthlyChart()
  } catch (error) {
    Taro.showToast({ title: '统计加载失败', icon: 'none' })
    throw error
  }
}

function setYearFromPicker(event: SelectorPickerChangeEvent) {
  const selectedYear = getYearFromPicker(event)
  if (!selectedYear || selectedYear === year.value) return
  year.value = selectedYear
  void loadStatistics()
}

function buildYearOptions(currentYear: number) {
  return Array.from({ length: currentYear - minYear + 1 }, (_, index) => {
    const optionYear = currentYear - index
    return { text: `${optionYear}年`, value: optionYear }
  })
}

function getYearOptionIndex(value: number) {
  return Math.max(yearOptions.value.findIndex(item => item.value === value), 0)
}

function getYearFromPicker(event: SelectorPickerChangeEvent) {
  const index = Number(event.detail?.value ?? selectedYearIndex.value)
  return yearOptions.value[index]?.value
}

function normalizeStatistics(data: CollaborationMonthlyStatisticsDTO[]) {
  const statisticsMap = new Map(data.map(item => [item.month, item]))
  return chartCategories.map((_, index) => {
    const month = index + 1
    return statisticsMap.get(month) || createEmptyMonth(month)
  })
}

function createEmptyMonth(month: number): CollaborationMonthlyStatisticsDTO {
  return { month, purchasePrice: 0, expenditureAmount: 0, settledRemuneration: 0, settledTotal: 0 }
}

function syncChartSize() {
  const systemInfo = Taro.getSystemInfoSync()
  chartSize.width = Math.max(systemInfo.windowWidth, minChartWidth)
  chartSize.height = getChartHeight(systemInfo)
}

function getChartHeight(systemInfo) {
  const availableHeight = getViewportHeight(systemInfo) - getUsedPageHeight(systemInfo)
  return Math.max(Math.floor(availableHeight), minChartHeight)
}

function getViewportHeight(systemInfo) {
  if (process.env.TARO_ENV === 'h5') return window.innerHeight
  return systemInfo.windowHeight
}

function getUsedPageHeight(systemInfo) {
  if (process.env.TARO_ENV === 'h5') return getH5UsedPageHeight(systemInfo)
  return getNavbarHeight() + getDesignPx(getDesignUsedHeight(), systemInfo)
}

function getH5UsedPageHeight(systemInfo) {
  return getElementHeight('.app-navbar-placeholder')
    + getH5PageVerticalPadding(systemInfo)
    + getElementHeight('.chart-toolbar')
}

function getH5PageVerticalPadding(systemInfo) {
  const page = document.querySelector('.statistics-page')
  if (!page) return getDesignPx(statisticsPageTopPadding + statisticsPageBottomPadding, systemInfo)
  const style = getComputedStyle(page)
  return parseCssPixel(style.paddingTop) + parseCssPixel(style.paddingBottom)
}

function getElementHeight(selector: string) {
  const element = document.querySelector(selector)
  return element?.getBoundingClientRect().height || 0
}

function parseCssPixel(value: string) {
  return Number.parseFloat(value) || 0
}

function getDesignUsedHeight() {
  return statisticsPageTopPadding + statisticsPageBottomPadding + chartToolbarHeight
}

function getDesignPx(designPx: number, systemInfo) {
  if (process.env.TARO_ENV !== 'h5') return designPx * systemInfo.windowWidth / designWidth
  const rootFontSize = parseCssPixel(getComputedStyle(document.documentElement).fontSize)
  return designPx / h5RootDesignRatio * rootFontSize
}

function getNavbarHeight() {
  const statusBarHeight = Taro.getSystemInfoSync().statusBarHeight || defaultStatusBarHeight
  const menuButtonRect = getMenuButtonRect()
  const contentHeight = menuButtonRect
    ? menuButtonRect.height + (menuButtonRect.top - statusBarHeight) * 2
    : defaultNavContentHeight
  return statusBarHeight + contentHeight
}

function getMenuButtonRect() {
  if (!Taro.getMenuButtonBoundingClientRect) return undefined
  const rect = Taro.getMenuButtonBoundingClientRect()
  if (!rect || rect.height <= 0) return undefined
  return rect
}

function renderMonthlyChart() {
  if (!isChartReady.value) return
  const chartData = buildChartData()
  if (monthlyChart) {
    monthlyChart.updateData(chartData)
    return
  }
  monthlyChart = createMonthlyChart(chartData)
}

function createMonthlyChart(chartData) {
  const context = getChartContext()
  if (!context) return undefined
  return new UCharts({
    ...createChartOptions(),
    ...chartData,
    context,
    canvasId: chartCanvasId
  })
}

function getChartContext() {
  if (process.env.TARO_ENV !== 'h5') return Taro.createCanvasContext(chartCanvasId)
  const canvas = getH5CanvasElement()
  return canvas?.getContext('2d')
}

function getH5CanvasElement() {
  const element = document.getElementById(chartCanvasId)
  if (element instanceof HTMLCanvasElement) return element
  return element?.querySelector('canvas') || null
}

function buildChartData() {
  return {
    categories: chartCategories,
    series: statisticSeriesDefinitions.map(buildSeries)
  }
}

function buildSeries(definition: StatisticsSeriesDefinition) {
  return {
    name: definition.name,
    data: statistics.value.map(item => Number(item[definition.field] || 0))
  }
}

function createChartOptions() {
  return {
    type: 'column',
    width: chartSize.width,
    height: chartSize.height,
    color: chartColors,
    background: themeTokens.color.page,
    padding: [12, 12, 6, 12],
    dataLabel: false,
    legend: { show: false },
    xAxis: { disableGrid: true, fontSize: 10, fontColor: themeTokens.color.textSecondary },
    yAxis: { splitNumber: 4, gridColor: themeTokens.color.primaryLight, fontColor: themeTokens.color.textSecondary },
    extra: { column: { type: 'group', width: 8, seriesGap: 2, categoryGap: 6 } }
  }
}

function handleChartTouch(event) {
  monthlyChart?.showToolTip(event, { showCategory: true })
}
</script>

<style lang="scss">
.statistics-page {
  overflow: hidden;
}

.year-picker {
  flex: none;
}

.year-btn.at-button {
  width: 148px;
  height: 52px;
  font-size: $font-sm;
  line-height: 52px;
  color: $color-primary;
  white-space: nowrap;
  background: $bg-page !important;
  border: 1px solid $color-primary;
  border-radius: $radius-md;
}

.year-btn.at-button .at-button__warp {
  white-space: nowrap;
}

.chart-panel {
  padding: 0;
  margin-right: calc(-1 * #{$space-xl});
  margin-bottom: 0;
  margin-left: calc(-1 * #{$space-xl});
  overflow: hidden;
  background: $bg-page !important;
  border: 0;
}

.chart-toolbar {
  display: flex;
  gap: 16px;
  align-items: center;
  justify-content: space-between;
  padding: 0 $space-xl 12px;
}

.chart-legend {
  display: flex;
  flex: 1;
  gap: 8px 14px;
  align-items: center;
  min-width: 0;
  overflow-x: auto;
  white-space: nowrap;
}

.legend-item {
  display: flex;
  flex: none;
  align-items: center;
}

.legend-dot {
  width: 14px;
  height: 14px;
  margin-right: 6px;
  border-radius: 50%;
}

.legend-text {
  font-size: $font-xs;
  line-height: 28px;
  color: $text-regular;
  white-space: nowrap;
}

.statistics-chart {
  display: block;
}
</style>
