<script setup lang="ts">
import { ReloadOutlined } from '@ant-design/icons-vue'
import type {
  DesktopAccountInfo,
  MonitoringHotQuestion,
  MonitoringPlatformAuthorizationStatus,
} from '@geo/shared-types'
import { aiPlatformCatalog } from '@geo/shared-types'
import { useMutation, useQuery } from '@tanstack/vue-query'
import { useStorage } from '@vueuse/core'
import { message } from 'ant-design-vue'
import dayjs from 'dayjs'
import { computed, ref, watch } from 'vue'
import { useI18n } from 'vue-i18n'
import { useRoute, useRouter } from 'vue-router'

import PageHero from '@/components/PageHero.vue'
import { brandsApi, monitoringApi, tenantAccountsApi } from '@/lib/api'
import { resolveAccountCheckedAt, resolveAccountHealth } from '@/lib/desktop-account-runtime'
import { formatDateTime } from '@/lib/display'
import { formatError } from '@/lib/errors'
import {
  isMonitoringPlatformId,
  normalizeMonitoringPlatformFilter,
  normalizeMonitoringPlatformId,
} from '@/lib/monitoring-platforms'
import { useCompanyStore } from '@/stores/company'

const { t } = useI18n()
const route = useRoute()
const router = useRouter()
const companyStore = useCompanyStore()

const trackingMaxHistoryDays = 30
const trackingBusinessTimeZone = 'Asia/Shanghai'
const trackingToday = formatTrackingBusinessDate(new Date())

type CitationRankingRow = {
  ai_platform_id: string
  platform_name: string
  cited_answer_count: number | null
  cited_article_count: number | null
  citation_source_count: number | null
  saas_source_count: number | null
  saas_source_rate: number | null
  citation_rate: number | null
  share: number
  color: string
  surface: string
  glyph: string
}

type AIPlatformStatusCard = {
  id: string
  label: string
  shortName: string
  accent: string
  description: string
  account: DesktopAccountInfo | null
  isClientOnline: boolean
  sampleStatus: string
  lastSampledAt: string | null
  actualSampleCount: number
}

function formatTrackingBusinessDate(value: Date): string {
  const parts = new Intl.DateTimeFormat('en-US', {
    timeZone: trackingBusinessTimeZone,
    year: 'numeric',
    month: '2-digit',
    day: '2-digit',
  }).formatToParts(value)

  const year = parts.find((part) => part.type === 'year')?.value
  const month = parts.find((part) => part.type === 'month')?.value
  const day = parts.find((part) => part.type === 'day')?.value
  if (!year || !month || !day) {
    throw new Error('tracking_business_date_format_failed')
  }

  return `${year}-${month}-${day}`
}

const platformAppearanceMap: Record<string, { color: string; surface: string; glyph: string }> = {
  doubao: { color: '#ff9348', surface: '#fff2e8', glyph: '豆' },
  deepseek: { color: '#5d72ff', surface: '#eef1ff', glyph: 'D' },
  qwen: { color: '#276ef1', surface: '#edf4ff', glyph: '通' },
  wenxin: { color: '#20c6d7', surface: '#ebfcff', glyph: '文' },
  yuanbao: { color: '#19bf6b', surface: '#eafbf1', glyph: '元' },
  kimi: { color: '#111827', surface: '#f3f4f6', glyph: 'K' },
}

const trackingPlatformOptions = [
  { label: '全部', value: 'all' },
  ...aiPlatformCatalog.map((platform) => ({
    label: platform.label,
    value: platform.id,
  })),
] as const
const allQuestionOptionValue = 'all'

const selectedQuestionId = useStorage<number | null>('tracking_selected_question', null)
const selectedPlatformId = useStorage<string>('tracking_selected_ai_platform_id', 'all')
const selectedBusinessDate = ref<string>(
  normalizeTrackingBusinessDate(route.query.business_date) ?? trackingToday,
)
const selectedCitationWindowDays = useStorage<number>('tracking_selected_citation_window_days', 7)

selectedPlatformId.value = normalizeMonitoringPlatformFilter(selectedPlatformId.value)
selectedCitationWindowDays.value = normalizeCitationWindowDays(selectedCitationWindowDays.value)

const selectedQuestionSetOptionValue = computed<string | number>({
  get: () => selectedQuestionId.value ?? allQuestionOptionValue,
  set: (value) => {
    selectedQuestionId.value =
      typeof value === 'number' && Number.isFinite(value) && value > 0 ? value : null
  },
})

const selectedBrandId = computed(() => companyStore.currentBrandId)
const selectedBrand = computed(() => companyStore.currentBrand)

const questionsQuery = useQuery({
  queryKey: computed(() => ['tracking', 'questions', selectedBrandId.value]),
  enabled: computed(() => Boolean(selectedBrandId.value)),
  queryFn: () => brandsApi.listQuestions(selectedBrandId.value as number),
})

const questionSetOptions = computed(() => [
  { label: t('tracking.allQuestionSets'), value: allQuestionOptionValue },
  ...(questionsQuery.data.value ?? []).map((item) => ({
    label: item.question_text,
    value: item.id,
  })),
])

watch(
  () => questionsQuery.data.value,
  (questions) => {
    const requestedQuestionId = parseNumericQuery(route.query.question_id)
    if (!questions?.length) {
      if (!requestedQuestionId) {
        selectedQuestionId.value = null
      }
      return
    }

    if (requestedQuestionId && questions.some((item) => item.id === requestedQuestionId)) {
      selectedQuestionId.value = requestedQuestionId
      return
    }

    if (
      selectedQuestionId.value &&
      questions.some((item) => item.id === selectedQuestionId.value)
    ) {
      return
    }

    selectedQuestionId.value = null
  },
  { immediate: true },
)

watch(selectedBrandId, (newId, oldId) => {
  if (oldId && newId !== oldId) {
    selectedQuestionId.value = null
  }
})

watch(
  () => route.query.business_date,
  (value) => {
    selectedBusinessDate.value = normalizeTrackingBusinessDate(value) ?? trackingToday
  },
  { immediate: true },
)

watch(
  () => route.query.ai_platform_id,
  (value) => {
    selectedPlatformId.value = normalizeMonitoringPlatformFilter(value)
  },
  { immediate: true },
)

watch(
  [
    selectedBrandId,
    selectedQuestionId,
    selectedPlatformId,
    selectedBusinessDate,
    () => questionsQuery.data.value,
  ],
  ([brandId, questionId, platformId, businessDate, questions]) => {
    const requestedQuestionId = parseNumericQuery(route.query.question_id)
    if (requestedQuestionId && !questionId && !Array.isArray(questions)) {
      return
    }

    const nextBrandId = brandId ? String(brandId) : undefined
    const nextQuestionId = questionId ? String(questionId) : undefined
    const nextPlatformId = platformId !== 'all' ? platformId : undefined
    const nextBusinessDate = normalizeTrackingBusinessDate(businessDate) ?? trackingToday
    const currentBrandId = normalizeQueryValue(route.query.brand_id) || undefined
    const currentQuestionId = normalizeQueryValue(route.query.question_id) || undefined
    const currentPlatformId = normalizeMonitoringPlatformFilter(route.query.ai_platform_id)
    const currentBusinessDate =
      normalizeTrackingBusinessDate(route.query.business_date) ?? trackingToday
    const hasLegacyCitationDaysQuery = normalizeQueryValue(route.query.citation_days) !== ''

    if (
      currentBrandId === nextBrandId &&
      currentQuestionId === nextQuestionId &&
      currentPlatformId === (nextPlatformId ?? 'all') &&
      currentBusinessDate === nextBusinessDate &&
      !hasLegacyCitationDaysQuery
    ) {
      return
    }

    void router.replace({
      name: 'tracking',
      query: {
        ...(nextBrandId ? { brand_id: nextBrandId } : {}),
        ...(nextQuestionId ? { question_id: nextQuestionId } : {}),
        ...(nextPlatformId ? { ai_platform_id: nextPlatformId } : {}),
        business_date: nextBusinessDate,
      },
    })
  },
)

const dashboardQuery = useQuery({
  queryKey: computed(() => [
    'tracking',
    'dashboard',
    selectedBrandId.value,
    selectedQuestionId.value,
    selectedPlatformId.value,
    selectedBusinessDate.value,
  ]),
  enabled: computed(() => Boolean(selectedBrandId.value)),
  queryFn: () =>
    monitoringApi.dashboardComposite({
      brand_id: selectedBrandId.value ?? undefined,
      question_id: selectedQuestionId.value,
      days: trackingMaxHistoryDays,
      ai_platform_id: selectedPlatformId.value !== 'all' ? selectedPlatformId.value : undefined,
      business_date: selectedBusinessDate.value,
    }),
})

const citationSummaryQuery = useQuery({
  queryKey: computed(() => [
    'tracking',
    'citation-summary',
    selectedBrandId.value,
    selectedQuestionId.value,
    selectedPlatformId.value,
    selectedBusinessDate.value,
    selectedCitationWindowDays.value,
  ]),
  enabled: computed(() => Boolean(selectedBrandId.value)),
  queryFn: () =>
    monitoringApi.citationSummary({
      brand_id: selectedBrandId.value ?? undefined,
      question_id: selectedQuestionId.value,
      business_date: selectedBusinessDate.value,
      ai_platform_id: selectedPlatformId.value !== 'all' ? selectedPlatformId.value : undefined,
      days: selectedCitationWindowDays.value,
    }),
})

const aiAccountsQuery = useQuery({
  queryKey: ['tracking', 'ai-platform-accounts'],
  queryFn: () => tenantAccountsApi.list(),
})

const collectNowMutation = useMutation({
  mutationFn: async () => {
    if (!selectedBrandId.value) {
      throw new Error('tracking_brand_required')
    }

    return monitoringApi.collectNow(selectedBrandId.value, {
      question_id: selectedQuestionId.value ?? undefined,
      platform_ids: selectedPlatformId.value !== 'all' ? [selectedPlatformId.value] : undefined,
    })
  },
  onSuccess: (collectNowResult) => {
    message.success(collectNowResult.message)
    void dashboardQuery.refetch()
  },
  onError: (error) => {
    if (error instanceof Error && error.message === 'tracking_brand_required') {
      message.warning(t('tracking.collectBrandRequired'))
      return
    }
    message.error(formatError(error))
  },
})

const currentUserClientOnline = computed(() => {
  return dashboardQuery.data.value?.runtime.current_user_client_online === true
})

const platformBreakdownRows = computed(() => {
  return dashboardQuery.data.value?.platform_breakdown ?? []
})

const platformAuthorizationStatus = computed<MonitoringPlatformAuthorizationStatus>(() => {
  return dashboardQuery.data.value?.runtime.platform_authorization_status ?? 'authorized'
})

const selectedPlatformAuthorized = computed(() => {
  if (selectedPlatformId.value === 'all') {
    return true
  }
  const authorizedPlatformIDs =
    dashboardQuery.data.value?.runtime.authorized_monitoring_platform_ids ?? []
  return authorizedPlatformIDs.some(
    (item) => normalizeMonitoringPlatformId(item) === selectedPlatformId.value,
  )
})

const selectedPlatformOnlineAuthorized = computed(() => {
  const onlinePlatformIDs =
    dashboardQuery.data.value?.runtime.online_authorized_monitoring_platform_ids ?? []
  if (selectedPlatformId.value === 'all') {
    return onlinePlatformIDs.length > 0
  }
  return onlinePlatformIDs.some(
    (item) => normalizeMonitoringPlatformId(item) === selectedPlatformId.value,
  )
})

const collectNowDisabledReason = computed(() => {
  if (!selectedBrandId.value) {
    return t('tracking.collectBrandRequired')
  }
  if (selectedBusinessDate.value !== trackingToday) {
    return t('tracking.collectTodayOnly')
  }
  if (dashboardQuery.isLoading.value && !dashboardQuery.data.value) {
    return t('tracking.collectClientChecking')
  }
  if (platformAuthorizationStatus.value === 'no_desktop_client') {
    return t('tracking.noDesktopClientCollectReason')
  }
  if (platformAuthorizationStatus.value === 'no_authorized_platforms') {
    return t('tracking.noAuthorizedPlatformsCollectReason')
  }
  if (
    selectedPlatformId.value !== 'all' &&
    dashboardQuery.data.value &&
    !selectedPlatformAuthorized.value
  ) {
    return t('tracking.collectPlatformUnauthorized')
  }
  if (!currentUserClientOnline.value) {
    return t('tracking.collectClientOnlineRequired')
  }
  if (dashboardQuery.data.value && !selectedPlatformOnlineAuthorized.value) {
    return t('tracking.collectClientOnlineRequired')
  }
  return null
})

const selectedDateHasData = computed(() => {
  return (dashboardQuery.data.value?.overview.actual_sample_count ?? 0) > 0
})

const hotQuestions = computed(() => {
  return dashboardQuery.data.value?.hot_questions ?? []
})

const aiPlatformStatusCards = computed<AIPlatformStatusCard[]>(() => {
  const accountGroups = new Map<string, DesktopAccountInfo[]>()
  for (const account of aiAccountsQuery.data.value ?? []) {
    const platformId = normalizeMonitoringPlatformId(account.platform)
    if (!isMonitoringPlatformId(platformId) || account.deleted_at) {
      continue
    }
    const list = accountGroups.get(platformId) ?? []
    list.push(account)
    accountGroups.set(platformId, list)
  }

  const breakdownMap = new Map(
    (dashboardQuery.data.value?.platform_breakdown ?? []).map((item) => [
      normalizeMonitoringPlatformId(item.ai_platform_id),
      item,
    ]),
  )
  const onlineAuthorizedPlatformIDs = new Set(
    (dashboardQuery.data.value?.runtime.online_authorized_monitoring_platform_ids ?? [])
      .map((item) => normalizeMonitoringPlatformId(item))
      .filter((item): item is string => Boolean(item)),
  )

  return aiPlatformCatalog.map((platform) => {
    const matchedAccounts = [...(accountGroups.get(platform.id) ?? [])].sort((left, right) => {
      const leftOnline = left.client_online === true ? 1 : 0
      const rightOnline = right.client_online === true ? 1 : 0
      if (leftOnline !== rightOnline) {
        return rightOnline - leftOnline
      }
      const leftAt = Date.parse(resolveAccountCheckedAt(left) ?? '') || 0
      const rightAt = Date.parse(resolveAccountCheckedAt(right) ?? '') || 0
      return rightAt - leftAt
    })
    const breakdown = breakdownMap.get(platform.id)

    return {
      id: platform.id,
      label: platform.label,
      shortName: platform.shortName,
      accent: platform.accent,
      description: platform.description,
      account: matchedAccounts[0] ?? null,
      isClientOnline:
        onlineAuthorizedPlatformIDs.has(platform.id) ||
        (!dashboardQuery.data.value &&
          matchedAccounts.some((account) => account.client_online === true)),
      sampleStatus: breakdown?.platform_sample_status ?? 'pending',
      lastSampledAt: breakdown?.last_sampled_at ?? null,
      actualSampleCount: breakdown?.actual_sample_count ?? 0,
    }
  })
})

const selectedMetricCards = computed(() => {
  const overview = dashboardQuery.data.value?.overview
  return [
    {
      key: 'mention',
      title: t('tracking.metrics.mentionRate'),
      value: overview?.mention_rate ?? null,
      previous: overview?.prev_snapshot_mention_rate ?? null,
    },
    {
      key: 'top1',
      title: t('tracking.metrics.top1MentionRate'),
      value: overview?.top1_mention_rate ?? null,
      previous: overview?.prev_snapshot_top1_mention_rate ?? null,
    },
    {
      key: 'first',
      title: t('tracking.metrics.firstRecommendRate'),
      value: overview?.first_recommend_rate ?? null,
      previous: overview?.prev_snapshot_first_recommend_rate ?? null,
    },
    {
      key: 'positive',
      title: t('tracking.metrics.positiveMentionRate'),
      value: overview?.positive_mention_rate ?? null,
      previous: overview?.prev_snapshot_positive_mention_rate ?? null,
    },
  ]
})

const citationWindowOptions = computed(() => [
  { label: t('tracking.citationWindow7'), value: 7 },
  { label: t('tracking.citationWindow30'), value: 30 },
])

const citationRankingRows = computed<CitationRankingRow[]>(() => {
  const ranking = citationSummaryQuery.data.value?.citation_ranking ?? []
  const order = new Map<string, number>()
  const rows = new Map<string, CitationRankingRow>()

  aiPlatformCatalog.forEach((item, index) => {
    const platformId = normalizeMonitoringPlatformId(item.id) || item.id
    order.set(platformId, index)
    rows.set(platformId, {
      ai_platform_id: platformId,
      platform_name: item.label,
      cited_answer_count: null,
      cited_article_count: null,
      citation_source_count: null,
      saas_source_count: null,
      saas_source_rate: null,
      citation_rate: null,
      share: 0,
      ...platformAppearance(platformId, item.label),
    })
  })

  ranking.forEach((item, index) => {
    const platformId = normalizeMonitoringPlatformId(item.ai_platform_id) || item.ai_platform_id
    if (!order.has(platformId)) {
      order.set(platformId, aiPlatformCatalog.length + index)
    }

    const existing = rows.get(platformId)
    rows.set(platformId, {
      ai_platform_id: platformId,
      platform_name: item.platform_name || existing?.platform_name || platformId,
      cited_answer_count: (existing?.cited_answer_count ?? 0) + (item.cited_answer_count ?? 0),
      cited_article_count: (existing?.cited_article_count ?? 0) + (item.cited_article_count ?? 0),
      citation_source_count:
        (existing?.citation_source_count ?? 0) + (item.citation_source_count ?? 0),
      saas_source_count: (existing?.saas_source_count ?? 0) + (item.saas_source_count ?? 0),
      saas_source_rate: item.saas_source_rate ?? existing?.saas_source_rate ?? null,
      citation_rate: item.citation_rate ?? existing?.citation_rate ?? null,
      share: 0,
      ...platformAppearance(
        platformId,
        item.platform_name || existing?.platform_name || platformId,
      ),
    })
  })

  const list = Array.from(rows.values())
  const totalAppearances = list.reduce(
    (sum, item) => sum + Math.max(item.saas_source_count ?? item.cited_answer_count ?? 0, 0),
    0,
  )
  const enriched = list.map((item) => ({
    ...item,
    share:
      totalAppearances > 0
        ? Math.max(item.saas_source_count ?? item.cited_answer_count ?? 0, 0) / totalAppearances
        : 0,
  }))
  const hasCitationData = enriched.some(
    (item) => (item.saas_source_count ?? item.cited_answer_count ?? 0) > 0,
  )

  return enriched.sort((left, right) => {
    if (hasCitationData) {
      const countDiff =
        (right.saas_source_count ?? right.cited_answer_count ?? 0) -
        (left.saas_source_count ?? left.cited_answer_count ?? 0)
      if (countDiff !== 0) {
        return countDiff
      }
    }
    return (order.get(left.ai_platform_id) ?? 0) - (order.get(right.ai_platform_id) ?? 0)
  })
})

const visibleCitedArticles = computed(() => {
  return citationSummaryQuery.data.value?.cited_articles ?? []
})

const citationPieSlices = computed(() => {
  const segments = citationRankingRows.value.filter(
    (item) => (item.saas_source_count ?? item.cited_answer_count ?? 0) > 0,
  )

  if (!segments.length) {
    return []
  }

  const cx = 100
  const cy = 100
  const r = 100

  let offset = 0

  return segments.map((item) => {
    const share = item.share

    if (share === 1) {
      return {
        ...item,
        isFull: true,
        path: '',
      }
    }

    const startAngle = offset * 2 * Math.PI - Math.PI / 2
    const endAngle = (offset + share) * 2 * Math.PI - Math.PI / 2

    const x1 = cx + r * Math.cos(startAngle)
    const y1 = cy + r * Math.sin(startAngle)
    const x2 = cx + r * Math.cos(endAngle)
    const y2 = cy + r * Math.sin(endAngle)

    const largeArcFlag = share > 0.5 ? 1 : 0
    const path = `M ${cx} ${cy} L ${x1} ${y1} A ${r} ${r} 0 ${largeArcFlag} 1 ${x2} ${y2} Z`

    offset += share

    return {
      ...item,
      isFull: false,
      path,
    }
  })
})

const hoveredSlice = ref<string | null>(null)
const tooltipPos = ref({ x: 0, y: 0 })

function onPieMouseMove(e: MouseEvent) {
  const target = e.currentTarget as HTMLElement
  if (!target) return
  const rect = target.getBoundingClientRect()
  tooltipPos.value = {
    x: e.clientX - rect.left + 15,
    y: e.clientY - rect.top + 15,
  }
}

const hoveredSliceInfo = computed(() => {
  if (!hoveredSlice.value) return null
  return citationPieSlices.value.find((s) => s.ai_platform_id === hoveredSlice.value) ?? null
})

const citationChartStyle = computed(() => {
  return {
    background: 'linear-gradient(180deg, #eef4ff 0%, #e5ecff 100%)',
  }
})

const heroDescription = computed(() => {
  const overview = dashboardQuery.data.value?.overview
  if (!overview?.last_sampled_at) {
    return `${selectedBusinessDate.value} 暂无抓取数据`
  }
  return `最近一次采集数据：${formatDateTime(overview.last_sampled_at)}`
})

function openQuestion(question: MonitoringHotQuestion): void {
  if (!selectedBrandId.value) {
    return
  }

  void router.push({
    name: 'tracking-question-detail',
    params: {
      brandId: String(selectedBrandId.value),
      questionId: String(question.question_id),
    },
    query: {
      business_date: selectedBusinessDate.value,
      ...(selectedPlatformId.value !== 'all' ? { ai_platform_id: selectedPlatformId.value } : {}),
    },
    state: {
      tracking_question_hash: question.question_hash,
      tracking_question_text: question.question_text,
    },
  })
}

function filterQuestionOption(input: string, option?: { label?: string }): boolean {
  const keyword = input.trim().toLowerCase()
  if (!keyword) {
    return true
  }
  return String(option?.label ?? '')
    .toLowerCase()
    .includes(keyword)
}

function formatPercent(value: number | null | undefined): string {
  if (value === null || value === undefined) {
    return '--'
  }
  return `${(value * 100).toFixed(value < 0.1 ? 1 : 0)}%`
}

function normalizeCitationWindowDays(value: unknown): number {
  const numeric = Number(value)
  return numeric === 30 ? 30 : 7
}

function accountAuthLabel(account: DesktopAccountInfo | null): string {
  if (!account) {
    return '未绑定'
  }

  switch (resolveAccountHealth(account)) {
    case 'live':
      return '授权正常'
    case 'captcha':
      return '待处理'
    case 'expired':
      return '授权过期'
    default:
      return '风险观察'
  }
}

function accountAuthColor(account: DesktopAccountInfo | null): string {
  if (!account) {
    return 'default'
  }

  switch (resolveAccountHealth(account)) {
    case 'live':
      return 'green'
    case 'captcha':
      return 'gold'
    case 'expired':
      return 'red'
    default:
      return 'orange'
  }
}

function desktopStatusLabel(account: DesktopAccountInfo | null, isClientOnline: boolean): string {
  if (!account?.client_id) {
    return '未绑定桌面端'
  }

  return isClientOnline ? '客户端在线' : '客户端离线'
}

function formatCount(value: number | null | undefined): string {
  if (value === null || value === undefined) {
    return '--'
  }
  return String(value)
}

function formatDelta(
  current: number | null | undefined,
  previous: number | null | undefined,
): string | null {
  if (current === null || current === undefined || previous === null || previous === undefined) {
    return null
  }
  const diff = current - previous
  if (Math.abs(diff) < 0.001) {
    return t('tracking.noChange')
  }
  const prefix = diff > 0 ? '+' : ''
  return `${prefix}${(diff * 100).toFixed(1)}%`
}

function statusTagColor(status: string): string {
  switch (status) {
    case 'sampled':
      return 'green'
    case 'pending':
      return 'gold'
    case 'not_logged_in':
      return 'default'
    case 'unavailable':
      return 'red'
    default:
      return 'default'
  }
}

function statusLabel(status: string): string {
  return t(`tracking.status.${status}`)
}

function platformAppearance(aiPlatformId: string, platformName: string) {
  const normalizedId =
    normalizeMonitoringPlatformId(aiPlatformId) ||
    aiPlatformId.toLowerCase().replace(/[^a-z0-9]/g, '')
  const matched = platformAppearanceMap[normalizedId]

  if (matched) {
    return matched
  }

  const glyph = platformName.trim().slice(0, 1).toUpperCase() || '?'
  return {
    color: '#f5b13d',
    surface: '#fff7e8',
    glyph,
  }
}

function parseNumericQuery(value: unknown): number | null {
  const raw = Array.isArray(value) ? value[0] : value
  const parsed = Number(raw)
  if (!Number.isFinite(parsed) || parsed <= 0) {
    return null
  }
  return parsed
}

function normalizeQueryValue(value: unknown): string {
  return String(Array.isArray(value) ? (value[0] ?? '') : (value ?? '')).trim()
}

function normalizeTrackingBusinessDate(value: unknown): string | null {
  const normalized = normalizeQueryValue(value)
  if (!normalized) {
    return null
  }
  const parsed = dayjs(normalized)
  if (!parsed.isValid() || parsed.format('YYYY-MM-DD') !== normalized) {
    return null
  }

  const today = dayjs(trackingToday).startOf('day')
  const earliestAllowed = today.subtract(trackingMaxHistoryDays - 1, 'day')
  if (parsed.isAfter(today, 'day') || parsed.isBefore(earliestAllowed, 'day')) {
    return null
  }
  return normalized
}

function disableTrackingDate(current: dayjs.Dayjs): boolean {
  const today = dayjs(trackingToday).endOf('day')
  const earliestAllowed = dayjs(trackingToday)
    .subtract(trackingMaxHistoryDays - 1, 'day')
    .startOf('day')
  return current.isAfter(today) || current.isBefore(earliestAllowed)
}
</script>

<template>
  <section class="tracking-view">
    <PageHero :title="t('route.tracking.title')" :description="heroDescription">
      <template #actions>
        <a-space wrap align="center" class="tracking-actions-wrap">
          <div class="tracking-action-item">
            <span class="tracking-action-label">平台</span>
            <a-select
              v-model:value="selectedPlatformId"
              class="tracking-select"
              :options="trackingPlatformOptions"
            />
          </div>
          <div class="tracking-action-item">
            <span class="tracking-action-label">关键词库（搜索词）</span>
            <a-select
              v-model:value="selectedQuestionSetOptionValue"
              show-search
              class="tracking-select"
              option-filter-prop="label"
              :filter-option="filterQuestionOption"
              :not-found-content="t('tracking.noQuestions')"
              :placeholder="t('tracking.keywordPlaceholder')"
              :options="questionSetOptions"
            />
          </div>
          <div class="tracking-action-item">
            <span class="tracking-action-label">日期</span>
            <a-date-picker
              v-model:value="selectedBusinessDate"
              class="tracking-date-picker"
              format="YYYY-MM-DD"
              value-format="YYYY-MM-DD"
              :allow-clear="false"
              :disabled-date="disableTrackingDate"
            />
          </div>
          <a-tooltip :title="collectNowDisabledReason ?? undefined">
            <span>
              <a-button
                type="primary"
                :disabled="Boolean(collectNowDisabledReason)"
                :loading="collectNowMutation.isPending.value"
                @click="collectNowMutation.mutate()"
              >
                <template #icon><ReloadOutlined /></template>
                {{ t('tracking.collectNow') }}
              </a-button>
            </span>
          </a-tooltip>
        </a-space>
      </template>
    </PageHero>

    <a-alert
      v-if="dashboardQuery.error.value"
      type="error"
      show-icon
      :message="formatError(dashboardQuery.error.value)"
      class="tracking-view__alert"
    />

    <div class="tracking-grid tracking-grid--top">
      <a-card
        class="tracking-panel tracking-panel--overview"
        :loading="dashboardQuery.isLoading.value"
      >
        <div class="tracking-panel__header">
          <h3 class="panel-title">{{ selectedBrand?.name ?? t('common.noData') }}</h3>
          <a-tag
            :color="
              selectedDateHasData
                ? dashboardQuery.data.value?.overview.confidence_level === 'high'
                  ? 'green'
                  : dashboardQuery.data.value?.overview.confidence_level === 'medium'
                    ? 'gold'
                    : 'default'
                : 'default'
            "
          >
            {{
              selectedDateHasData
                ? t(
                    `tracking.confidence.${dashboardQuery.data.value?.overview.confidence_level ?? 'low'}`,
                  )
                : '暂无抓取'
            }}
          </a-tag>
        </div>

        <div class="metric-grid tracking-metric-grid">
          <article v-for="card in selectedMetricCards" :key="card.key" class="metric-card">
            <p class="metric-card__label">{{ card.title }}</p>
            <div class="metric-card__value-row">
              <strong>{{ formatPercent(card.value) }}</strong>
              <span
                v-if="formatDelta(card.value, card.previous)"
                :class="[
                  'metric-card__delta',
                  (card.value ?? 0) >= (card.previous ?? 0)
                    ? 'metric-card__delta--up'
                    : 'metric-card__delta--down',
                ]"
              >
                {{ formatDelta(card.value, card.previous) }}
              </span>
            </div>
          </article>
        </div>
      </a-card>

      <a-card class="tracking-panel" :loading="dashboardQuery.isLoading.value">
        <div class="tracking-panel__header">
          <h3 class="panel-title">{{ t('tracking.platformMatrixTitle') }}</h3>
        </div>

        <div v-if="platformBreakdownRows.length" class="platform-table">
          <div class="platform-table__head">
            <span>{{ t('tracking.columns.platform') }}</span>
            <span>{{ t('tracking.metrics.mentionRate') }}</span>
            <span>{{ t('tracking.metrics.top1MentionRate') }}</span>
            <span>{{ t('common.status') }}</span>
          </div>

          <div
            v-for="item in platformBreakdownRows"
            :key="item.ai_platform_id"
            class="platform-table__row"
          >
            <div class="platform-table__platform">
              <strong>{{ item.platform_name }}</strong>
              <span>{{ item.actual_sample_count }} {{ t('tracking.samples') }}</span>
            </div>
            <span>
              {{
                item.platform_sample_status === 'sampled' ? formatPercent(item.mention_rate) : '--'
              }}
            </span>
            <span>
              {{
                item.platform_sample_status === 'sampled'
                  ? formatPercent(item.top1_mention_rate)
                  : '--'
              }}
            </span>
            <a-tag :color="statusTagColor(item.platform_sample_status)">
              {{ statusLabel(item.platform_sample_status) }}
            </a-tag>
          </div>
        </div>
        <a-empty
          v-else
          :description="t('tracking.noPlatformBreakdown')"
          class="tracking-panel__empty"
        />
      </a-card>
    </div>

    <a-card
      class="tracking-panel tracking-panel--ai-platforms"
      :loading="dashboardQuery.isLoading.value || aiAccountsQuery.isLoading.value"
    >
      <div class="tracking-panel__header">
        <div>
          <h3 class="panel-title">AI 平台状态</h3>
          <span class="tracking-panel__helper">
            只读展示 desktop-client
            的绑定、授权和当前采样状态。授权入口放在桌面端，抓取过程静默执行。
          </span>
        </div>
      </div>

      <div class="ai-platform-status-grid">
        <article
          v-for="platform in aiPlatformStatusCards"
          :key="platform.id"
          class="ai-platform-status-card"
        >
          <div class="ai-platform-status-card__head">
            <div class="ai-platform-status-card__identity">
              <span
                class="ai-platform-status-card__badge"
                :style="{
                  backgroundColor: `${platform.accent}14`,
                  color: platform.accent,
                  borderColor: `${platform.accent}30`,
                }"
              >
                {{ platform.shortName }}
              </span>
              <div>
                <strong>{{ platform.label }}</strong>
                <p>{{ platform.description }}</p>
              </div>
            </div>

            <a-tag :color="accountAuthColor(platform.account)">
              {{ accountAuthLabel(platform.account) }}
            </a-tag>
          </div>

          <div class="ai-platform-status-card__meta">
            <div class="ai-platform-status-card__row">
              <span>绑定状态</span>
              <strong>{{ platform.account ? '已绑定' : '未绑定' }}</strong>
            </div>
            <div class="ai-platform-status-card__row">
              <span>客户端</span>
              <strong>{{ desktopStatusLabel(platform.account, platform.isClientOnline) }}</strong>
            </div>
            <div class="ai-platform-status-card__row">
              <span>采样状态</span>
              <a-tag :color="statusTagColor(platform.sampleStatus)">
                {{ statusLabel(platform.sampleStatus) }}
              </a-tag>
            </div>
            <div class="ai-platform-status-card__row">
              <span>最近采样</span>
              <strong>
                {{ platform.lastSampledAt ? formatDateTime(platform.lastSampledAt) : '--' }}
              </strong>
            </div>
            <div class="ai-platform-status-card__row">
              <span>样本数</span>
              <strong>{{ formatCount(platform.actualSampleCount) }}</strong>
            </div>
            <div v-if="platform.account" class="ai-platform-status-card__row">
              <span>账号</span>
              <strong>{{ platform.account.display_name }}</strong>
            </div>
          </div>
        </article>
      </div>
    </a-card>

    <div class="tracking-grid tracking-grid--middle">
      <a-card
        class="tracking-panel tracking-panel--citation"
        :loading="citationSummaryQuery.isLoading.value"
      >
        <div class="tracking-citation-section">
          <div class="tracking-citation-header">
            <div>
              <h3 class="tracking-citation-title">{{ t('tracking.citationRankingTitle') }}</h3>
              <p class="tracking-citation-desc">{{ t('tracking.citationRankingHint') }}</p>
            </div>
            <a-radio-group
              v-model:value="selectedCitationWindowDays"
              class="citation-window-switch"
              size="small"
              button-style="solid"
            >
              <a-radio-button
                v-for="item in citationWindowOptions"
                :key="item.value"
                :value="item.value"
              >
                {{ item.label }}
              </a-radio-button>
            </a-radio-group>
          </div>

          <div class="citation-ranking-layout">
            <div class="citation-ranking-visual">
              <div
                class="citation-ranking-visual__canvas"
                @mouseleave="hoveredSlice = null"
                @mousemove="onPieMouseMove"
              >
                <svg v-if="citationPieSlices.length" viewBox="0 0 200 200" class="citation-pie-svg">
                  <template v-for="slice in citationPieSlices" :key="slice.ai_platform_id">
                    <circle
                      v-if="slice.isFull"
                      cx="100"
                      cy="100"
                      r="100"
                      :fill="slice.color"
                      class="citation-pie-slice"
                      :class="{ 'is-hovered': hoveredSlice === slice.ai_platform_id }"
                      @mouseenter="hoveredSlice = slice.ai_platform_id"
                    />
                    <path
                      v-else
                      :d="slice.path"
                      :fill="slice.color"
                      class="citation-pie-slice"
                      :class="{
                        'is-hovered': hoveredSlice === slice.ai_platform_id,
                        'is-dimmed': hoveredSlice && hoveredSlice !== slice.ai_platform_id,
                      }"
                      @mouseenter="hoveredSlice = slice.ai_platform_id"
                    />
                  </template>
                </svg>
                <div v-else class="citation-ranking-visual__circle" :style="citationChartStyle" />

                <div
                  v-if="hoveredSliceInfo"
                  class="citation-pie-tooltip"
                  :style="{ left: `${tooltipPos.x}px`, top: `${tooltipPos.y}px` }"
                >
                  <div
                    class="citation-pie-tooltip__marker"
                    :style="{ background: hoveredSliceInfo.color }"
                  ></div>
                  <span class="citation-pie-tooltip__label">
                    {{ hoveredSliceInfo.platform_name }}
                  </span>
                  <strong class="citation-pie-tooltip__value">
                    {{ formatPercent(hoveredSliceInfo.share) }}
                  </strong>
                </div>
              </div>

              <div v-if="citationRankingRows.length" class="citation-ranking-legend">
                <div
                  v-for="item in citationRankingRows"
                  :key="`legend-${item.ai_platform_id}`"
                  class="citation-ranking-legend__item"
                >
                  <span
                    class="citation-ranking-legend__swatch"
                    :style="{ background: item.color }"
                  />
                  <span class="citation-platform__mini">
                    <span
                      class="citation-platform__mini-badge"
                      :style="{ background: item.surface, color: item.color }"
                    >
                      {{ item.glyph }}
                    </span>
                    <span>{{ item.platform_name }}</span>
                  </span>
                </div>
              </div>

              <a-empty v-else :description="t('tracking.noCitationRanking')" />
            </div>

            <div class="citation-ranking-sheet">
              <div class="citation-ranking-sheet__head">
                <span>{{ t('tracking.columns.platform') }}</span>
                <span>{{ t('tracking.columns.appearances') }}</span>
                <span>{{ t('tracking.columns.saasSourceRate') }}</span>
                <span>{{ t('tracking.columns.citationRate') }}</span>
              </div>

              <div
                v-for="item in citationRankingRows"
                :key="item.ai_platform_id"
                class="citation-ranking-sheet__row"
              >
                <div class="citation-platform__mini">
                  <span
                    class="citation-platform__mini-badge"
                    :style="{ background: item.surface, color: item.color }"
                  >
                    {{ item.glyph }}
                  </span>
                  <strong>{{ item.platform_name }}</strong>
                </div>
                <span class="citation-ranking-sheet__count">
                  {{ formatCount(item.saas_source_count ?? item.cited_answer_count) }}
                  {{ item.saas_source_count != null ? t('tracking.citations') : '' }}
                </span>
                <strong class="citation-ranking-sheet__rate">
                  {{ formatPercent(item.saas_source_rate) }}
                </strong>
                <strong class="citation-ranking-sheet__rate">
                  {{ formatPercent(item.citation_rate) }}
                </strong>
              </div>

              <a-empty
                v-if="!citationRankingRows.length"
                :description="t('tracking.noCitationRanking')"
              />
            </div>
          </div>
        </div>
      </a-card>

      <a-card class="tracking-panel" :loading="dashboardQuery.isLoading.value">
        <div class="tracking-panel__header">
          <h3 class="panel-title">{{ t('tracking.hotQuestionsTitle') }}</h3>
          <span class="tracking-panel__helper">{{ t('tracking.hotQuestionsHint') }}</span>
        </div>

        <div v-if="hotQuestions.length" class="question-list">
          <button
            v-for="question in hotQuestions"
            :key="`${question.question_id}-${question.question_hash}`"
            type="button"
            class="question-list__item"
            @click="openQuestion(question)"
          >
            <div>
              <strong>{{ question.question_text }}</strong>
              <p>
                {{ t('tracking.metrics.mentionRate') }} {{ formatPercent(question.mention_rate) }}
              </p>
            </div>
            <span class="question-list__time">
              {{ question.last_sampled_at ? formatDateTime(question.last_sampled_at) : '--' }}
            </span>
          </button>
        </div>

        <a-empty v-else :description="t('tracking.noQuestions')" />
      </a-card>
    </div>

    <div class="tracking-grid tracking-grid--bottom">
      <a-card class="tracking-panel" :loading="citationSummaryQuery.isLoading.value">
        <div class="tracking-panel__header">
          <h3 class="panel-title">{{ t('tracking.citedArticlesTitle') }}</h3>
          <span class="tracking-panel__helper">
            {{ t('tracking.citationWindowLabel', { days: selectedCitationWindowDays }) }}
          </span>
        </div>

        <div class="article-list">
          <div
            v-for="item in visibleCitedArticles"
            :key="item.article_id"
            class="article-list__item"
          >
            <div>
              <strong>{{ item.article_title }}</strong>
              <p>{{ item.publish_platform }}</p>
            </div>
            <div class="article-list__meta">
              <span>{{ item.citation_count }} {{ t('tracking.citations') }}</span>
              <span>{{ t('tracking.columns.share') }} {{ formatPercent(item.source_share) }}</span>
              <strong>{{ formatPercent(item.citation_rate) }}</strong>
            </div>
          </div>
          <a-empty
            v-if="!visibleCitedArticles.length"
            :description="t('tracking.noCitedArticles')"
          />
        </div>
      </a-card>
    </div>
  </section>
</template>

<style scoped>
.tracking-view {
  display: flex;
  flex-direction: column;
  gap: 20px;
}

.tracking-actions-wrap {
  align-items: center;
}

.tracking-view__alert {
  margin-bottom: 4px;
}

.tracking-action-item {
  display: flex;
  align-items: center;
  gap: 8px;
}

.tracking-action-label {
  font-size: 14px;
  color: #1f2937;
  font-weight: 500;
}

.tracking-select {
  min-width: 180px;
}

.tracking-date-picker {
  min-width: 168px;
}

.tracking-grid {
  display: grid;
  gap: 20px;
}

.tracking-grid--top {
  grid-template-columns: minmax(0, 1.6fr) minmax(0, 1fr);
}

.tracking-grid--middle {
  grid-template-columns: minmax(0, 1.6fr) minmax(0, 1fr);
}

.tracking-grid--bottom {
  grid-template-columns: minmax(0, 1fr);
}

.tracking-panel--ai-platforms {
  overflow: hidden;
}

.ai-platform-status-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 16px;
  margin-top: 12px;
}

.ai-platform-status-card {
  display: flex;
  flex-direction: column;
  gap: 14px;
  padding: 16px;
  border-radius: 16px;
  border: 1px solid #e6edf5;
  background: linear-gradient(180deg, #ffffff 0%, #fbfdff 100%);
}

.ai-platform-status-card__head {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  align-items: flex-start;
}

.ai-platform-status-card__identity {
  display: flex;
  gap: 12px;
  align-items: flex-start;
}

.ai-platform-status-card__identity strong {
  display: block;
  color: #111827;
  font-size: 16px;
  line-height: 1.2;
}

.ai-platform-status-card__identity p {
  margin: 6px 0 0;
  color: #667085;
  line-height: 1.5;
  font-size: 12px;
}

.ai-platform-status-card__badge {
  width: 42px;
  height: 42px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 14px;
  border: 1px solid transparent;
  font-size: 16px;
  font-weight: 700;
  flex-shrink: 0;
}

.ai-platform-status-card__meta {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.ai-platform-status-card__row {
  display: flex;
  justify-content: space-between;
  gap: 16px;
  align-items: center;
  padding: 10px 12px;
  border-radius: 12px;
  background: #f8fafc;
}

.ai-platform-status-card__row span {
  color: #667085;
  font-size: 12px;
}

.ai-platform-status-card__row strong {
  color: #111827;
  font-size: 13px;
  text-align: right;
  word-break: break-all;
}

.tracking-citation-section {
  display: flex;
  flex-direction: column;
  padding: 0;
  margin-top: 10px;
}

.tracking-citation-section.is-loading {
  opacity: 0.6;
  pointer-events: none;
}

.tracking-citation-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 24px;
}

.tracking-citation-title {
  margin: 0;
  font-size: 16px;
  font-weight: 700;
  color: #1a1a1a;
}

.tracking-citation-desc {
  margin: 4px 0 0;
  color: #8c8c8c;
  font-size: 13px;
}

.tracking-panel {
  border-radius: 12px;
  background: #ffffff;
}

.tracking-panel--citation {
  overflow: hidden;
}

.citation-window-switch {
  flex: 0 0 auto;
}

.tracking-panel__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 20px;
}

.tracking-panel__header-left {
  display: flex;
  flex-direction: column;
}

.panel-title {
  margin: 0;
  font-size: 16px;
  font-weight: 700;
  color: #1a1a1a;
  display: flex;
  align-items: center;
}

.panel-title::before {
  content: '';
  display: inline-block;
  width: 4px;
  height: 14px;
  background: #1f5cff;
  border-radius: 2px;
  margin-right: 8px;
}

.tracking-panel__description {
  margin: 10px 0 0 12px;
  color: #a3a3a3;
  font-size: 13px;
}

.tracking-panel__helper {
  color: var(--muted);
  font-size: 13px;
}

.tracking-panel__empty {
  padding: 28px 0 16px;
}

.tracking-metric-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 16px;
}

.metric-card {
  background: #f7f9fc;
  border: 1px solid #f0f3fa;
  border-radius: 12px;
  padding: 16px;
}

.metric-card__label {
  margin: 0;
  color: #8c8c8c;
  font-size: 13px;
}

.metric-card__value-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  margin-top: 10px;
}

.metric-card__value-row strong {
  font-size: 24px;
  font-weight: 800;
  color: #141414;
}

.metric-card__delta {
  font-size: 13px;
  font-weight: 700;
}

.metric-card__delta--up {
  color: #15803d;
}

.metric-card__delta--down {
  color: #dc2626;
}

.platform-table,
.citation-table {
  display: flex;
  flex-direction: column;
  gap: 0;
}

.platform-table__head,
.platform-table__row,
.citation-table__head,
.citation-table__row {
  display: grid;
  grid-template-columns: minmax(0, 1.5fr) repeat(3, minmax(0, 1fr));
  align-items: center;
  gap: 12px;
}

.platform-table__head,
.citation-table__head {
  background: #fafafa;
  color: #8c8c8c;
  font-weight: 500;
  font-size: 13px;
  padding: 12px 16px;
  border-bottom: 1px solid #f0f0f0;
}

.platform-table__row,
.citation-table__row {
  padding: 16px;
  border-bottom: 1px solid #f9f9f9;
  background: #ffffff;
}

.platform-table__row:last-child,
.citation-table__row:last-child {
  border-bottom: none;
}

.platform-table__platform span {
  display: block;
  margin-top: 4px;
  color: var(--muted);
  font-size: 12px;
}

.citation-ranking-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(400px, 1fr);
  gap: 40px;
  align-items: flex-start;
}

.citation-ranking-visual {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 32px;
  padding: 0;
}

.citation-ranking-visual__canvas {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
}

.citation-pie-svg {
  width: min(32vw, 420px);
  height: min(32vw, 420px);
  min-width: 280px;
  min-height: 280px;
  border-radius: 999px;
  overflow: visible;
  filter: drop-shadow(0 4px 6px rgba(0, 0, 0, 0.05));
}

.citation-pie-slice {
  transition:
    transform 0.25s cubic-bezier(0.34, 1.56, 0.64, 1),
    opacity 0.25s;
  transform-origin: 100px 100px;
  cursor: pointer;
  stroke: #ffffff;
  stroke-width: 1.5px;
  stroke-linejoin: round;
}

.citation-pie-slice.is-hovered {
  transform: scale(1.05);
  z-index: 2;
}

.citation-pie-slice.is-dimmed {
  opacity: 0.4;
}

.citation-pie-tooltip {
  position: absolute;
  pointer-events: none;
  background: rgba(255, 255, 255, 0.95);
  backdrop-filter: blur(4px);
  border: 1px solid #e5e7eb;
  padding: 8px 12px;
  border-radius: 8px;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
  display: flex;
  align-items: center;
  gap: 8px;
  z-index: 10;
  font-size: 13px;
  white-space: nowrap;
  transition: opacity 0.2s;
}

.citation-pie-tooltip__marker {
  width: 8px;
  height: 8px;
  border-radius: 50%;
}

.citation-pie-tooltip__label {
  color: #4b5563;
}

.citation-pie-tooltip__value {
  color: #111827;
  font-weight: 600;
}

.citation-ranking-visual__circle {
  width: min(32vw, 420px);
  height: min(32vw, 420px);
  min-width: 280px;
  min-height: 280px;
  border-radius: 999px;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.85);
}

.citation-ranking-legend {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 16px 24px;
}

.citation-ranking-legend__item {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  color: #4b5563;
  font-size: 14px;
}

.citation-ranking-legend__swatch {
  width: 12px;
  height: 12px;
  border-radius: 4px;
  flex: 0 0 auto;
}

.citation-platform__mini {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
}

.citation-platform__mini-badge {
  display: inline-flex;
  width: 20px;
  height: 20px;
  border-radius: 999px;
  align-items: center;
  justify-content: center;
  font-size: 11px;
  font-weight: 700;
  flex: 0 0 auto;
}

.citation-ranking-sheet {
  border-radius: 12px;
  border: 1px solid #f0f3fa;
  background: #ffffff;
  overflow: hidden;
}

.citation-ranking-sheet__head,
.citation-ranking-sheet__row {
  display: grid;
  grid-template-columns: minmax(0, 1.3fr) minmax(0, 0.72fr) minmax(0, 0.72fr) minmax(0, 0.72fr);
  align-items: center;
  gap: 16px;
  padding: 20px 32px;
  min-width: 560px;
}

.citation-ranking-sheet__head {
  background: #fafafa;
  color: #4b5563;
  font-size: 13px;
  font-weight: 500;
  border-bottom: 1px solid #f0f0f0;
}

.citation-ranking-sheet__row {
  border-bottom: 1px solid #f9f9f9;
  color: #4b5563;
  font-size: 14px;
}

.citation-ranking-sheet__row:last-child {
  border-bottom: none;
}

.citation-ranking-sheet__row strong {
  color: #111827;
  font-size: 14px;
}

.citation-ranking-sheet__row > span,
.citation-ranking-sheet__row > strong {
  justify-self: start;
}

.citation-ranking-sheet__count {
  color: #374151;
}

.citation-ranking-sheet__rate {
  color: #111827;
}

.question-list,
.article-list,
.detail-citation-list {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.question-list__item,
.article-list__item,
.detail-citation-list__item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  width: 100%;
  padding: 16px;
  border: 1px solid #f0f3fa;
  border-radius: 12px;
  background: #f7f9fc;
  text-align: left;
  transition: all 0.2s;
}

.question-list__item:hover,
.article-list__item:hover,
.detail-citation-list__item:hover {
  background: #ffffff;
  border-color: #e5eaf2;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
}

.question-list__item {
  cursor: pointer;
}

.question-list__item strong,
.article-list__item strong,
.detail-citation-list__item strong {
  display: block;
}

.question-list__item p,
.article-list__item p,
.detail-citation-list__item p {
  margin: 4px 0 0;
  color: var(--muted);
}

.question-list__time,
.article-list__meta {
  color: var(--muted);
  font-size: 12px;
}

.article-list__meta {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 6px;
}

.detail-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-bottom: 16px;
}

.detail-tabs__item {
  padding: 8px 14px;
  border: 1px solid #fed7aa;
  border-radius: 999px;
  background: #fff7ed;
  cursor: pointer;
}

.detail-tabs__item--active {
  border-color: #f97316;
  background: #f97316;
  color: #fff;
}

.detail-tabs__item--muted {
  opacity: 0.55;
}

.detail-grid {
  display: grid;
  grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr);
  gap: 16px;
}

.detail-grid--bottom {
  margin-top: 16px;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
}

.detail-meta {
  display: flex;
  gap: 12px;
  margin-top: 16px;
  color: var(--muted);
  font-size: 12px;
}

@media (max-width: 1080px) {
  .tracking-grid--top,
  .tracking-grid--middle,
  .tracking-grid--bottom,
  .detail-grid,
  .detail-grid--bottom {
    grid-template-columns: minmax(0, 1fr);
  }

  .citation-ranking-layout {
    grid-template-columns: minmax(0, 1fr);
  }

  .citation-ranking-visual {
    min-height: auto;
    padding: 0;
  }

  .citation-ranking-visual__canvas {
    min-height: 280px;
  }

  .citation-ranking-visual__circle {
    width: min(72vw, 360px);
    height: min(72vw, 360px);
  }

  .citation-ranking-sheet__head,
  .citation-ranking-sheet__row {
    padding: 22px 20px;
  }
}

@media (max-width: 640px) {
  .tracking-citation-header {
    flex-direction: column;
  }

  .citation-ranking-sheet__head,
  .citation-ranking-sheet__row {
    grid-template-columns: minmax(0, 1.2fr) minmax(0, 0.7fr) minmax(0, 0.7fr) minmax(0, 0.7fr);
    gap: 10px;
    font-size: 13px;
  }

  .citation-ranking-sheet__row strong,
  .citation-ranking-sheet__row {
    font-size: 14px;
  }

  .citation-ranking-legend {
    gap: 12px 18px;
    padding-left: 0;
  }
}
</style>
