<script lang="ts" setup>
import type { EchartsUIType } from '@easyflow/plugins/echarts';

import type {
  DashboardAssistantTrendSeries,
  DashboardDistributionItem,
  DashboardOverviewQuery,
  DashboardOverviewResponse,
  DashboardRange,
  DashboardSummary,
  DashboardTrendItem,
  DashboardUserRankItem,
  DashboardUserRankQuery,
} from '#/api/dashboard';

import {
  computed,
  nextTick,
  onBeforeUnmount,
  onMounted,
  reactive,
  ref,
  watch,
} from 'vue';

import { AnalysisChartCard } from '@easyflow/common-ui';
import { EchartsUI, useEcharts } from '@easyflow/plugins/echarts';
import { useUserStore } from '@easyflow/stores';
import { convertToRgb, downloadFileFromBlob } from '@easyflow/utils';

import { RefreshRight } from '@element-plus/icons-vue';
import {
  ElButton,
  ElDatePicker,
  ElEmpty,
  ElOption,
  ElPopover,
  ElRadioButton,
  ElRadioGroup,
  ElSelect,
} from 'element-plus';

import {
  exportDashboardUserRanks,
  getDashboardOverview,
  getDashboardUserRanks,
} from '#/api/dashboard';
import { requestClient } from '#/api/request';

type DashboardTrendMode = 'assistantActive' | 'usage' | 'userActive';

interface AssistantTrendSelectionItem {
  assistantKey: string;
  color: string;
  isSelected: boolean;
  series: DashboardAssistantTrendSeries;
}

interface SummaryCardItem {
  available?: boolean;
  label: string;
  value: string;
}

interface AssistantOptionItem {
  label: string;
  value: string;
}

let greetingTimer: null | ReturnType<typeof setInterval> = null;
let userRankRequestId = 0;
const userStore = useUserStore();
const now = ref(new Date());

const filters = reactive<DashboardOverviewQuery>({
  range: '7d',
});
const customDateRange = ref<string[]>([]);

const overview = ref<DashboardOverviewResponse | null>(null);
const isLoading = ref(false);
const errorMessage = ref('');
const trendMode = ref<DashboardTrendMode>('usage');
const selectedAssistantTrendKeys = ref<string[]>([]);
const assistantOptions = ref<AssistantOptionItem[]>([
  { label: '全部智能体', value: '' },
]);
const assistantOptionsLoading = ref(false);
const selectedAssistantId = ref('');
const userRankItems = ref<DashboardUserRankItem[]>([]);
const userRankLoading = ref(false);
const userRankExportLoading = ref(false);
const userRankErrorMessage = ref('');

const trendChartRef = ref<EchartsUIType>();
const {
  getChartInstance: getTrendChartInstance,
  renderEcharts: renderTrendEcharts,
  resize: resizeTrendChart,
} = useEcharts(trendChartRef);

const rangeOptions: Array<{ label: string; value: DashboardRange }> = [
  { label: '今日', value: 'today' },
  { label: '近 7 天', value: '7d' },
  { label: '近 30 天', value: '30d' },
];

const trendModeOptions: Array<{ label: string; value: DashboardTrendMode }> = [
  { label: '使用量趋势', value: 'usage' },
  { label: '用户活跃', value: 'userActive' },
  { label: '智能体活跃', value: 'assistantActive' },
];

const emptySummary: DashboardSummary = {
  activeAssistantTotal: 0,
  activeUserTotal: 0,
  botTotal: 0,
  chatActiveUserTotal: 0,
  chatMessageTotal: 0,
  chatSessionTotal: 0,
  knowledgeBaseTotal: 0,
  userTotal: 0,
  workflowTotal: 0,
};

const summary = computed(() => overview.value?.summary ?? emptySummary);
const trends = computed<DashboardTrendItem[]>(
  () => overview.value?.trends ?? [],
);
const assistantTrends = computed<DashboardAssistantTrendSeries[]>(
  () => overview.value?.assistantTrends ?? [],
);
const distribution = computed<DashboardDistributionItem[]>(
  () => overview.value?.distribution ?? [],
);
const chatAvailable = computed(
  () => overview.value?.chatStatus?.available !== false,
);
const chatStatusMessage = computed(
  () => overview.value?.chatStatus?.message || '聊天数据不可用',
);
const isUsageTrend = computed(() => trendMode.value === 'usage');
const isUserActiveTrend = computed(() => trendMode.value === 'userActive');
const isAssistantActiveTrend = computed(
  () => trendMode.value === 'assistantActive',
);

const summaryCards = computed<SummaryCardItem[]>(() => [
  {
    available: chatAvailable.value,
    label: 'AI活跃用户',
    value: formatOptionalCount(
      summary.value.chatActiveUserTotal,
      chatAvailable.value,
    ),
  },
  {
    available: chatAvailable.value,
    label: '活跃智能体',
    value: formatOptionalCount(
      summary.value.activeAssistantTotal,
      chatAvailable.value,
    ),
  },
  {
    available: chatAvailable.value,
    label: '聊天会话总数',
    value: formatOptionalCount(
      summary.value.chatSessionTotal,
      chatAvailable.value,
    ),
  },
  {
    available: chatAvailable.value,
    label: '聊天消息总数',
    value: formatOptionalCount(
      summary.value.chatMessageTotal,
      chatAvailable.value,
    ),
  },
  { label: '智能体总数', value: formatCount(summary.value.botTotal) },
  {
    label: '知识库总数',
    value: formatCount(summary.value.knowledgeBaseTotal),
  },
]);

const updatedAtText = computed(() => {
  if (!overview.value?.updatedAt) {
    return '尚未获取';
  }
  return formatDateTime(overview.value.updatedAt);
});

const displayName = computed(() => {
  return (
    userStore.userInfo?.nickname?.trim() ||
    userStore.userInfo?.loginName?.trim() ||
    '同学'
  );
});

const greetingText = computed(() => {
  const hour = now.value.getHours();
  if (hour < 11) {
    return '上午好';
  }
  if (hour < 14) {
    return '中午好';
  }
  if (hour < 18) {
    return '下午好';
  }
  return '晚上好';
});

const greetingTitle = computed(
  () => `${greetingText.value}，${displayName.value}`,
);

const trendDescription = computed(() => {
  if (isUsageTrend.value) {
    return '消息与会话趋势';
  }
  if (isUserActiveTrend.value) {
    return '用户活跃趋势';
  }
  return '智能体活跃趋势';
});

const selectedAssistantTrendSet = computed(
  () => new Set(selectedAssistantTrendKeys.value),
);

const assistantTrendColors = computed(() =>
  buildAssistantTrendPalette(assistantTrends.value.length),
);

const assistantTrendSelectionItems = computed<AssistantTrendSelectionItem[]>(
  () =>
    assistantTrends.value.map((series, index) => {
      const assistantKey = getAssistantTrendKey(
        series.assistantId,
        series.label,
      );
      return {
        assistantKey,
        color:
          assistantTrendColors.value[index] || getChartTokenColor('--primary'),
        isSelected: selectedAssistantTrendSet.value.has(assistantKey),
        series,
      };
    }),
);

const selectedAssistantTrends = computed<AssistantTrendSelectionItem[]>(() =>
  assistantTrendSelectionItems.value.filter((item) => item.isSelected),
);

const selectedAssistantTrendCount = computed(
  () => selectedAssistantTrends.value.length,
);

const selectedAssistantTrendPreviewItems = computed(() =>
  selectedAssistantTrends.value.slice(0, 3),
);

const assistantTrendSelectorLabel = computed(() => {
  const total = assistantTrendSelectionItems.value.length;
  if (total === 0) {
    return '无可选智能体';
  }
  return `${selectedAssistantTrendCount.value}/${total} 已选`;
});

const assistantTrendSelectorSummary = computed(() => {
  const count = selectedAssistantTrendCount.value;
  if (count === 0) {
    return '未选择智能体';
  }
  if (count === 1) {
    return selectedAssistantTrends.value[0]?.series.label || '已选择 1 个';
  }
  return `${selectedAssistantTrends.value[0]?.series.label || '已选择'} 等 ${count} 个`;
});

const showAssistantTrendNoData = computed(
  () =>
    isAssistantActiveTrend.value &&
    assistantTrendSelectionItems.value.length === 0,
);

const showAssistantTrendEmptySelection = computed(
  () =>
    isAssistantActiveTrend.value &&
    assistantTrendSelectionItems.value.length > 0 &&
    selectedAssistantTrends.value.length === 0,
);

const showTrendChart = computed(() => chatAvailable.value);
const showUserRankLoading = computed(
  () => userRankLoading.value && userRankItems.value.length === 0,
);

async function loadOverview() {
  isLoading.value = true;
  errorMessage.value = '';

  try {
    const [data] = await Promise.all([
      getDashboardOverview(buildOverviewQuery()),
      loadAssistantOptions().catch(() => undefined),
    ]);
    overview.value = data;
    resetAssistantTrendSelection();
    await renderCharts();
    if (data.chatStatus?.available === false) {
      resetUserRanks();
    } else {
      await loadUserRanks();
    }
  } catch (error) {
    overview.value = null;
    resetUserRanks();
    errorMessage.value =
      (error as Error)?.message || '工作台数据加载失败，请稍后重试。';
  } finally {
    isLoading.value = false;
  }
}

async function loadAssistantOptions() {
  assistantOptionsLoading.value = true;
  try {
    const bots = await requestClient.get<
      Array<{ id?: number | string; title?: string }>
    >('/api/v1/bot/list', {
      params: { status: 1 },
    });
    const nextOptions: AssistantOptionItem[] = [
      { label: '全部智能体', value: '' },
      ...(bots || []).map((item) => ({
        label: item.title?.trim() || '未命名智能体',
        value: item.id === undefined || item.id === null ? '' : String(item.id),
      })),
    ];
    assistantOptions.value = nextOptions;
    if (!nextOptions.some((item) => item.value === selectedAssistantId.value)) {
      selectedAssistantId.value = '';
    }
  } catch (error) {
    assistantOptions.value = [{ label: '全部智能体', value: '' }];
    selectedAssistantId.value = '';
    throw error;
  } finally {
    assistantOptionsLoading.value = false;
  }
}

async function loadUserRanks() {
  if (!overview.value || chatAvailable.value === false) {
    resetUserRanks();
    return;
  }
  const currentRequestId = ++userRankRequestId;
  userRankLoading.value = true;
  userRankErrorMessage.value = '';
  userRankItems.value = [];

  try {
    const data = await getDashboardUserRanks(buildUserRankQuery());
    if (currentRequestId !== userRankRequestId) {
      return;
    }
    userRankItems.value = data || [];
  } catch (error) {
    if (currentRequestId !== userRankRequestId) {
      return;
    }
    userRankItems.value = [];
    userRankErrorMessage.value =
      (error as Error)?.message || '用户活跃榜加载失败，请稍后重试。';
  } finally {
    if (currentRequestId === userRankRequestId) {
      userRankLoading.value = false;
    }
  }
}

function resetUserRanks() {
  userRankRequestId += 1;
  userRankItems.value = [];
  userRankLoading.value = false;
  userRankErrorMessage.value = '';
}

function buildOverviewQuery(): DashboardOverviewQuery {
  return {
    endDate: filters.range === 'custom' ? filters.endDate : undefined,
    range: filters.range,
    startDate: filters.range === 'custom' ? filters.startDate : undefined,
  };
}

function buildUserRankQuery(): DashboardUserRankQuery {
  return {
    ...buildOverviewQuery(),
    assistantId: selectedAssistantId.value || undefined,
  };
}

function handleUserRankAssistantChange(
  value: boolean | number | string | undefined,
) {
  selectedAssistantId.value =
    value === undefined || value === null ? '' : String(value);
  void loadUserRanks();
}

async function handleUserRankExport() {
  if (userRankExportLoading.value) {
    return;
  }
  userRankExportLoading.value = true;
  try {
    const blob = await exportDashboardUserRanks(buildUserRankQuery());
    downloadFileFromBlob({
      fileName: 'dashboard_user_ranks.xlsx',
      source: blob,
    });
  } finally {
    userRankExportLoading.value = false;
  }
}

async function renderCharts() {
  await nextTick();
  if (!showTrendChart.value) {
    return;
  }
  renderTrendChart();
}

function renderTrendChart() {
  const primaryColor = getChartTokenColor('--primary');
  const successColor = getChartTokenColor('--success');
  const warningColor = getChartTokenColor('--warning');
  const destructiveColor = getChartTokenColor('--destructive');
  const axisColor = getChartTokenColor('--border');
  const tooltipLineColor = getChartTokenColor('--accent');
  const textColor = getChartTokenColor('--foreground');

  if (isAssistantActiveTrend.value) {
    const xAxisData =
      assistantTrendSelectionItems.value[0]?.series.points.map(
        (point) => point.label,
      ) ?? [];
    const assistantSeries = assistantTrendSelectionItems.value.map((item) => ({
      data: item.series.points.map((point) => point.sessionTotal),
      emphasis: {
        focus: 'series' as const,
      },
      itemStyle: {
        borderColor: item.color,
        borderWidth: 2,
        color: '#ffffff',
      },
      lineStyle: {
        color: item.color,
        width: 3,
      },
      name: item.series.label,
      smooth: true,
      showSymbol: false,
      symbol: 'circle',
      symbolSize: 8,
      type: 'line' as const,
    }));

    renderTrendEcharts({
      color: assistantTrendSelectionItems.value.map((item) => item.color),
      grid: {
        bottom: 18,
        containLabel: true,
        left: 12,
        right: 12,
        top: 12,
      },
      legend: {
        data: assistantTrendSelectionItems.value.map(
          (item) => item.series.label,
        ),
        selected: buildAssistantTrendSelectedMap(),
        show: false,
      },
      tooltip: {
        axisPointer: {
          lineStyle: {
            color: tooltipLineColor,
            width: 1,
          },
          type: 'line',
        },
        trigger: 'axis',
      },
      xAxis: {
        axisLine: {
          lineStyle: {
            color: axisColor,
          },
        },
        axisTick: {
          show: false,
        },
        boundaryGap: false,
        data: xAxisData,
        type: 'category',
      },
      yAxis: {
        axisLine: {
          show: false,
        },
        axisTick: {
          show: false,
        },
        splitLine: {
          lineStyle: {
            color: axisColor,
            type: 'dashed',
          },
        },
        type: 'value',
      },
      series: assistantSeries,
    });
    return;
  }

  const xAxisData = trends.value.map((item) => item.label);
  const messageData = trends.value.map((item) => item.chatMessageTotal);
  const sessionData = trends.value.map((item) => item.chatSessionTotal);
  const activeUserData = trends.value.map((item) => item.activeUserTotal);

  const usageSeries = [
    {
      data: messageData,
      emphasis: {
        focus: 'none' as const,
        itemStyle: {
          borderColor: '#ffffff',
          borderWidth: 3,
          color: primaryColor,
        },
        scale: true,
      },
      itemStyle: {
        borderColor: primaryColor,
        borderWidth: 2,
        color: '#ffffff',
      },
      lineStyle: {
        color: primaryColor,
        width: 3,
      },
      name: '消息数',
      smooth: true,
      showSymbol: false,
      symbol: 'circle',
      symbolSize: 9,
      type: 'line' as const,
    },
    {
      data: sessionData,
      emphasis: {
        focus: 'none' as const,
        itemStyle: {
          borderColor: '#ffffff',
          borderWidth: 3,
          color: successColor,
        },
        scale: true,
      },
      itemStyle: {
        borderColor: successColor,
        borderWidth: 2,
        color: '#ffffff',
      },
      lineStyle: {
        color: successColor,
        width: 3,
      },
      name: '会话数',
      smooth: true,
      showSymbol: false,
      symbol: 'circle',
      symbolSize: 9,
      type: 'line' as const,
    },
  ];

  const activeSeries = [
    {
      data: activeUserData,
      emphasis: {
        focus: 'none' as const,
      },
      itemStyle: {
        borderColor: primaryColor,
        borderWidth: 2,
        color: '#ffffff',
      },
      lineStyle: {
        color: primaryColor,
        width: 3,
      },
      name: '活跃用户数',
      smooth: true,
      showSymbol: false,
      symbol: 'circle',
      symbolSize: 9,
      type: 'line' as const,
    },
  ];

  renderTrendEcharts({
    color: isUsageTrend.value
      ? [primaryColor, successColor]
      : [primaryColor, warningColor, destructiveColor],
    grid: {
      bottom: 18,
      containLabel: true,
      left: 12,
      right: 12,
      top: 24,
    },
    legend: {
      icon: 'circle',
      itemGap: 24,
      itemHeight: 10,
      itemWidth: 10,
      padding: [4, 12, 8, 12],
      textStyle: {
        color: textColor,
        fontSize: 14,
        fontWeight: 500,
      },
      top: 4,
    },
    tooltip: {
      axisPointer: {
        lineStyle: {
          color: tooltipLineColor,
          width: 1,
        },
        type: 'line',
      },
      trigger: 'axis',
    },
    xAxis: {
      axisLine: {
        lineStyle: {
          color: axisColor,
        },
      },
      axisTick: {
        show: false,
      },
      boundaryGap: false,
      data: xAxisData,
      type: 'category',
    },
    yAxis: {
      axisLine: {
        show: false,
      },
      axisTick: {
        show: false,
      },
      splitLine: {
        lineStyle: {
          color: axisColor,
          type: 'dashed',
        },
      },
      type: 'value',
    },
    series: isUsageTrend.value ? usageSeries : activeSeries,
  });
}

function handleRangeChange(value: boolean | number | string | undefined) {
  if (value !== 'today' && value !== '7d' && value !== '30d') {
    return;
  }
  filters.range = value;
  customDateRange.value = [];
  filters.startDate = undefined;
  filters.endDate = undefined;
  void loadOverview();
}

function handleCustomRangeChange(value: string[] | undefined) {
  if (!value || value.length !== 2 || !value[0] || !value[1]) {
    customDateRange.value = [];
    filters.range = '7d';
    filters.startDate = undefined;
    filters.endDate = undefined;
    void loadOverview();
    return;
  }
  filters.range = 'custom';
  filters.startDate = value[0];
  filters.endDate = value[1];
  void loadOverview();
}

function handleTrendModeChange(value: boolean | number | string | undefined) {
  if (
    value !== 'usage' &&
    value !== 'userActive' &&
    value !== 'assistantActive'
  ) {
    return;
  }
  trendMode.value = value;
}

function resetAssistantTrendSelection() {
  selectedAssistantTrendKeys.value = assistantTrends.value.map((series) =>
    getAssistantTrendKey(series.assistantId, series.label),
  );
}

function toggleAssistantTrend(assistantKey: string) {
  const currentItem = assistantTrendSelectionItems.value.find(
    (item) => item.assistantKey === assistantKey,
  );
  if (!currentItem) {
    return;
  }
  const selectedKeys = new Set(selectedAssistantTrendKeys.value);
  let actionType: 'legendSelect' | 'legendUnSelect' = 'legendSelect';
  if (selectedKeys.has(assistantKey)) {
    selectedKeys.delete(assistantKey);
    actionType = 'legendUnSelect';
  } else {
    selectedKeys.add(assistantKey);
  }
  selectedAssistantTrendKeys.value = [...selectedKeys];
  if (!isAssistantActiveTrend.value) {
    return;
  }
  void nextTick(() => {
    const chartInstance = getTrendChartInstance();
    if (!chartInstance) {
      return;
    }
    chartInstance.dispatchAction({
      name: currentItem.series.label,
      type: actionType,
    });
  });
}

function selectAllAssistantTrends() {
  selectedAssistantTrendKeys.value = assistantTrendSelectionItems.value.map(
    (item) => item.assistantKey,
  );
  if (!isAssistantActiveTrend.value) {
    return;
  }
  void nextTick(() => {
    renderTrendChart();
    resizeTrendChart();
  });
}

function clearAssistantTrendSelection() {
  const previousItems = [...selectedAssistantTrends.value];
  selectedAssistantTrendKeys.value = [];
  if (!isAssistantActiveTrend.value) {
    return;
  }
  void nextTick(() => {
    const chartInstance = getTrendChartInstance();
    if (!chartInstance) {
      return;
    }
    for (const item of previousItems) {
      chartInstance.dispatchAction({
        name: item.series.label,
        type: 'legendUnSelect',
      });
    }
  });
}

function buildAssistantTrendSelectedMap() {
  return Object.fromEntries(
    assistantTrendSelectionItems.value.map((item) => [
      item.series.label,
      item.isSelected,
    ]),
  );
}

watch(
  [trendMode, chatAvailable, trends, assistantTrends],
  () => {
    if (!showTrendChart.value) {
      return;
    }
    void renderCharts();
  },
  {
    flush: 'post',
  },
);

function formatCount(value?: number) {
  return Number(value || 0).toLocaleString('zh-CN');
}

function formatOptionalCount(value: number | undefined, available: boolean) {
  return available ? formatCount(value) : '--';
}

function getChartTokenColor(variableName: string) {
  return convertToRgb(`hsl(${getChartTokenHsl(variableName)})`);
}

function getChartTokenHsl(variableName: string) {
  if (typeof window === 'undefined') {
    return '211 100% 50%';
  }
  const value = getComputedStyle(document.documentElement)
    .getPropertyValue(variableName)
    .trim();
  return value || '211 100% 50%';
}

function buildAssistantTrendPalette(total: number) {
  const palette = [
    getChartTokenColor('--primary'),
    getChartTokenColor('--success'),
    getChartTokenColor('--warning'),
    getChartTokenColor('--destructive'),
  ];
  if (total <= palette.length) {
    return palette.slice(0, total);
  }
  const primaryHue = extractHue(getChartTokenHsl('--primary')) ?? 211;
  const derivedHues = [46, 92, 138, 184, 230, 276].map(
    (offset) => `hsl(${normalizeHue(primaryHue + offset)} 68% 52%)`,
  );
  return [...palette, ...derivedHues].slice(0, total);
}

function getAssistantTrendKey(
  assistantId: number | string | undefined,
  label: string,
) {
  return assistantId === undefined
    ? `label:${label}`
    : `assistant:${assistantId}`;
}

function extractHue(hslValue: string) {
  const [hue] = hslValue.split(/\s+/);
  const parsed = Number.parseFloat(hue || '');
  return Number.isFinite(parsed) ? parsed : null;
}

function normalizeHue(value: number) {
  const normalized = value % 360;
  return normalized < 0 ? normalized + 360 : normalized;
}

function formatAvg(value?: number) {
  const safeValue = Number(value || 0);
  return safeValue.toLocaleString('zh-CN', {
    maximumFractionDigits: 1,
    minimumFractionDigits: safeValue > 0 && safeValue < 10 ? 1 : 0,
  });
}

function formatDateTime(value: string) {
  const date = new Date(value);
  if (Number.isNaN(date.getTime())) {
    return value;
  }
  return date.toLocaleString('zh-CN', {
    hour12: false,
  });
}

onMounted(async () => {
  greetingTimer = setInterval(() => {
    now.value = new Date();
  }, 60 * 1000);
  await loadOverview();
});

onBeforeUnmount(() => {
  if (greetingTimer) {
    clearInterval(greetingTimer);
    greetingTimer = null;
  }
});
</script>

<template>
  <div class="space-y-6 px-5 pb-5 pt-1">
    <section>
      <div
        class="flex flex-col gap-4 lg:flex-row lg:items-start lg:justify-between"
      >
        <div>
          <div class="text-3xl font-semibold tracking-tight lg:text-4xl">
            {{ greetingTitle }}
          </div>
        </div>
        <div
          class="flex flex-col gap-3 sm:flex-row sm:flex-wrap sm:items-center sm:justify-end"
        >
          <ElDatePicker
            v-model="customDateRange"
            class="w-full sm:w-[280px]"
            type="daterange"
            unlink-panels
            value-format="YYYY-MM-DD"
            start-placeholder="开始日期"
            end-placeholder="结束日期"
            @change="handleCustomRangeChange"
          />
          <ElRadioGroup
            :model-value="filters.range"
            size="default"
            @update:model-value="handleRangeChange"
          >
            <ElRadioButton
              v-for="item in rangeOptions"
              :key="item.value"
              :value="item.value"
              :label="item.label"
            >
              {{ item.label }}
            </ElRadioButton>
          </ElRadioGroup>

          <ElButton :icon="RefreshRight" @click="loadOverview">刷新</ElButton>
        </div>
      </div>

      <div class="text-muted-foreground mt-4 text-sm">
        最新更新时间：{{ updatedAtText }}
      </div>
    </section>

    <section
      v-if="isLoading && !overview"
      class="grid gap-4 md:grid-cols-2 xl:grid-cols-3"
    >
      <div
        v-for="item in 6"
        :key="item"
        class="border-border bg-muted/50 h-28 animate-pulse rounded-3xl border"
      ></div>
    </section>

    <section
      v-else-if="errorMessage"
      class="border-border bg-card rounded-3xl border border-dashed p-10"
    >
      <ElEmpty description="工作台加载失败">
        <template #default>
          <div class="space-y-3 text-center">
            <p class="text-muted-foreground text-sm">{{ errorMessage }}</p>
            <ElButton type="primary" @click="loadOverview">重新加载</ElButton>
          </div>
        </template>
      </ElEmpty>
    </section>

    <template v-else>
      <section class="grid gap-4 sm:grid-cols-2 xl:grid-cols-3">
        <div
          v-for="item in summaryCards"
          :key="item.label"
          class="border-border/70 bg-card rounded-3xl border px-5 py-5 transition-all duration-200 hover:-translate-y-0.5 hover:shadow-sm"
        >
          <div class="text-muted-foreground text-xs font-medium">
            {{ item.label }}
          </div>
          <div
            class="text-foreground mt-3 text-3xl font-semibold tracking-tight"
          >
            {{ item.value }}
          </div>
          <div
            v-if="item.available === false"
            class="text-muted-foreground mt-2 text-xs"
          >
            {{ chatStatusMessage }}
          </div>
        </div>
      </section>

      <section
        class="grid gap-4 xl:grid-cols-[minmax(0,2fr)_minmax(320px,1fr)]"
      >
        <AnalysisChartCard title="趋势概览">
          <template v-if="chatAvailable">
            <div class="space-y-4">
              <div
                class="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between"
              >
                <div class="text-muted-foreground text-sm">
                  {{ trendDescription }}
                </div>
                <div class="flex flex-wrap items-center justify-end gap-2">
                  <ElPopover
                    v-if="
                      isAssistantActiveTrend &&
                      assistantTrendSelectionItems.length > 0
                    "
                    placement="bottom-end"
                    trigger="click"
                    :width="340"
                  >
                    <template #reference>
                      <button
                        type="button"
                        class="border-border/60 bg-background/88 hover:border-border hover:bg-muted/20 text-foreground inline-flex h-9 max-w-[260px] items-center gap-2 rounded-2xl border px-3.5 text-sm transition-[border-color,background-color,box-shadow] duration-200"
                      >
                        <span
                          v-if="selectedAssistantTrendPreviewItems.length > 0"
                          class="flex shrink-0 items-center -space-x-1.5"
                        >
                          <span
                            v-for="item in selectedAssistantTrendPreviewItems"
                            :key="item.assistantKey"
                            class="border-background inline-block h-2.5 w-2.5 rounded-full border"
                            :style="{ backgroundColor: item.color }"
                          ></span>
                        </span>
                        <span class="min-w-0 flex-1 truncate font-medium">
                          {{ assistantTrendSelectorSummary }}
                        </span>
                        <span
                          class="bg-muted text-muted-foreground shrink-0 rounded-full px-2 py-0.5 text-[11px] font-medium"
                        >
                          {{ assistantTrendSelectorLabel }}
                        </span>
                      </button>
                    </template>
                    <div class="space-y-3">
                      <div class="flex items-center justify-between gap-3">
                        <div class="text-sm font-semibold">智能体</div>
                        <div class="flex items-center gap-2">
                          <button
                            type="button"
                            class="text-primary text-xs font-medium"
                            @click="selectAllAssistantTrends"
                          >
                            全选
                          </button>
                          <button
                            type="button"
                            class="text-muted-foreground text-xs font-medium"
                            @click="clearAssistantTrendSelection"
                          >
                            清空
                          </button>
                        </div>
                      </div>
                      <div class="grid max-h-64 gap-2 overflow-y-auto">
                        <button
                          v-for="item in assistantTrendSelectionItems"
                          :key="item.assistantKey"
                          type="button"
                          class="border-border/60 bg-background hover:border-border flex items-center gap-3 rounded-2xl border px-3 py-2 text-left transition-colors"
                          :class="
                            item.isSelected
                              ? 'border-primary/40 bg-primary/5'
                              : 'text-muted-foreground'
                          "
                          @click="toggleAssistantTrend(item.assistantKey)"
                        >
                          <span
                            class="h-2.5 w-2.5 shrink-0 rounded-full"
                            :style="{ backgroundColor: item.color }"
                          ></span>
                          <span
                            class="min-w-0 flex-1 truncate text-sm font-medium"
                          >
                            {{ item.series.label }}
                          </span>
                          <span class="text-muted-foreground shrink-0 text-xs">
                            {{ formatCount(item.series.totalSessionCount) }}
                          </span>
                        </button>
                      </div>
                    </div>
                  </ElPopover>
                  <ElRadioGroup
                    :model-value="trendMode"
                    size="small"
                    @update:model-value="handleTrendModeChange"
                  >
                    <ElRadioButton
                      v-for="item in trendModeOptions"
                      :key="item.value"
                      :value="item.value"
                      :label="item.label"
                    >
                      {{ item.label }}
                    </ElRadioButton>
                  </ElRadioGroup>
                </div>
              </div>
              <div class="relative min-h-[360px]">
                <div
                  v-if="showAssistantTrendNoData"
                  class="bg-background/92 absolute inset-0 z-10 flex items-center justify-center"
                >
                  <ElEmpty description="暂无智能体活跃数据" />
                </div>
                <div
                  v-else-if="showAssistantTrendEmptySelection"
                  class="bg-background/92 absolute inset-0 z-10 flex items-center justify-center"
                >
                  <ElEmpty description="请选择智能体" />
                </div>
                <EchartsUI ref="trendChartRef" height="360px" />
              </div>
            </div>
          </template>
          <div v-else class="flex min-h-[360px] items-center justify-center">
            <ElEmpty :description="chatStatusMessage" />
          </div>
        </AnalysisChartCard>

        <AnalysisChartCard title="智能体使用榜">
          <template v-if="chatAvailable">
            <div v-if="distribution.length > 0" class="space-y-3">
              <div
                v-for="(item, index) in distribution"
                :key="item.key || item.label"
                class="border-border/60 bg-muted/20 flex items-start justify-between rounded-2xl border px-4 py-4"
              >
                <div class="min-w-0 flex-1">
                  <div class="flex items-center gap-3">
                    <div
                      class="bg-primary/10 text-primary flex h-8 w-8 shrink-0 items-center justify-center rounded-full text-sm font-semibold"
                    >
                      {{ index + 1 }}
                    </div>
                    <div class="min-w-0">
                      <div class="truncate text-sm font-semibold">
                        {{ item.label }}
                      </div>
                      <div class="text-muted-foreground mt-1 text-xs">
                        用户 {{ formatCount(item.userTotal) }} · 消息
                        {{ formatCount(item.messageTotal) }}
                      </div>
                    </div>
                  </div>
                </div>
                <div class="text-right">
                  <div class="text-foreground text-lg font-semibold">
                    {{ formatCount(item.sessionTotal) }}
                  </div>
                  <div class="text-muted-foreground mt-1 text-xs">
                    会话数 · 人均 {{ formatAvg(item.avgSessionPerUser) }}
                  </div>
                </div>
              </div>
            </div>
            <div v-else class="flex min-h-[360px] items-center justify-center">
              <ElEmpty description="暂无智能体使用数据" />
            </div>
          </template>
          <div v-else class="flex min-h-[360px] items-center justify-center">
            <ElEmpty :description="chatStatusMessage" />
          </div>
        </AnalysisChartCard>
      </section>

      <section>
        <AnalysisChartCard title="用户活跃榜">
          <template #extra v-if="chatAvailable">
            <div class="flex w-full items-center justify-end gap-2 sm:w-auto">
              <ElSelect
                :model-value="selectedAssistantId"
                class="w-[220px]"
                :clearable="false"
                filterable
                placeholder="筛选智能体"
                :loading="assistantOptionsLoading"
                @update:model-value="handleUserRankAssistantChange"
              >
                <ElOption
                  v-for="item in assistantOptions"
                  :key="item.value || item.label"
                  :label="item.label"
                  :value="item.value"
                />
              </ElSelect>
              <ElButton
                :loading="userRankExportLoading"
                :disabled="userRankLoading"
                @click="handleUserRankExport"
              >
                导出
              </ElButton>
            </div>
          </template>
          <template v-if="chatAvailable">
            <div v-if="showUserRankLoading" class="space-y-3">
              <div
                v-for="item in 2"
                :key="item"
                class="border-border/60 bg-muted/25 h-[104px] animate-pulse rounded-2xl border"
              ></div>
            </div>
            <div v-else-if="userRankErrorMessage" class="flex min-h-[220px] items-center justify-center">
              <ElEmpty description="用户活跃榜加载失败">
                <template #default>
                  <div class="space-y-3 text-center">
                    <p class="text-muted-foreground text-sm">
                      {{ userRankErrorMessage }}
                    </p>
                    <ElButton type="primary" @click="loadUserRanks">
                      重新加载
                    </ElButton>
                  </div>
                </template>
              </ElEmpty>
            </div>
            <div v-else-if="userRankItems.length > 0" class="space-y-3">
              <div
                v-for="(item, index) in userRankItems"
                :key="item.userId || item.label"
                class="border-border/60 bg-card flex flex-col gap-4 rounded-2xl border px-4 py-4 md:flex-row md:items-center md:justify-between"
              >
                <div class="flex min-w-0 items-center gap-3">
                  <div
                    class="bg-primary/10 text-primary flex h-8 w-8 shrink-0 items-center justify-center rounded-full text-sm font-semibold"
                  >
                    {{ index + 1 }}
                  </div>
                  <div class="min-w-0">
                    <div class="truncate text-sm font-semibold">
                      {{ item.label }}
                    </div>
                  </div>
                </div>
                <div class="grid grid-cols-2 gap-3">
                  <div class="bg-muted/30 rounded-2xl px-4 py-3 text-right">
                    <div class="text-foreground text-base font-semibold">
                      {{ formatCount(item.sessionTotal) }}
                    </div>
                    <div class="text-muted-foreground mt-1 text-xs">会话数</div>
                  </div>
                  <div
                    class="bg-muted/30 rounded-2xl px-4 py-3 text-right"
                  >
                    <div class="text-foreground text-base font-semibold">
                      {{ formatCount(item.messageTotal) }}
                    </div>
                    <div class="text-muted-foreground mt-1 text-xs">消息数</div>
                  </div>
                </div>
              </div>
            </div>
            <div v-else class="flex min-h-[220px] items-center justify-center">
              <ElEmpty description="暂无用户活跃数据" />
            </div>
          </template>
          <div v-else class="flex min-h-[220px] items-center justify-center">
            <ElEmpty :description="chatStatusMessage" />
          </div>
        </AnalysisChartCard>
      </section>
    </template>
  </div>
</template>
