<script setup lang="ts">
import { ref, reactive, computed, onMounted, watch, onUnmounted, shallowRef } from 'vue'
import { Card } from '@/components/ui/card'
import {
  Select,
  SelectTrigger,
  SelectContent,
  SelectItem,
  SelectValue,
} from '@/components/ui/select'
import { Tabs, TabsList, TabsTrigger } from '@/components/ui/tabs'
import { Input } from '@/components/ui/input'
import { API } from '@/Api'
import ChartRenderer from '@/components/charts/ChartRenderer.vue'
import type { AnyChartInput } from '@/types/chart'

import {
  useVueTable,
  createColumnHelper,
  getCoreRowModel,
  FlexRender,
  type SortingState,
  type ColumnDef,
  type Column,
} from '@tanstack/vue-table'

const usageChartRef = ref<any>(null)
const feedbackChartRef = ref<any>(null)

type AgentLite = { id: string; name: string }
const myAgents = ref<AgentLite[]>([])
const agentId = ref<'all' | string>('all')
const bucket = ref<'day' | 'week' | 'month'>('month')

// --- Project Owner scope controls ---
const isProjectAdmin = ref<boolean>(false)
type OwnerInfo = { id: string; displayName?: string; email?: string; agentCount?: number }
const owners = ref<OwnerInfo[]>([])
const agentType = ref<'all' | 'user' | 'enterprise'>('all')
const ownerId = ref<string>('') // empty === any owner
const ALL_OWNERS_VALUE = '__ALL__' // sentinel for the Select

const ownerIdModel = computed<string>({
  get: () => (ownerId.value ? ownerId.value : ALL_OWNERS_VALUE),
  set: (v) => {
    ownerId.value = v === ALL_OWNERS_VALUE ? '' : v
  },
})

function scopeParams() {
  const p: any = {}
  if (isProjectAdmin.value) {
    p.agentType = agentType.value
    if (ownerId.value) p.ownerId = ownerId.value
  }
  return p
}

// keep semantics aligned with backend:
// - selecting an owner forces 'user' scope
// - switching to enterprise clears ownerId and resets agentId to 'all'
watch(ownerId, (v) => {
  if (v) agentType.value = 'user'
})
watch(agentType, (t) => {
  if (t === 'enterprise') {
    ownerId.value = ''
    agentId.value = 'all'
  }
})

const fmtUTC = (d: Date) =>
  new Date(Date.UTC(d.getFullYear(), d.getMonth(), d.getDate())).toISOString().slice(0, 10)
const today = new Date()
const to = ref(fmtUTC(today))
const from = ref(fmtUTC(new Date(today.getFullYear(), today.getMonth(), today.getDate() - 56)))

const rangeError = ref<string | null>(null)
const isValidRange = () => {
  const a = Date.parse(from.value)
  const b = Date.parse(to.value)
  const ok = Number.isFinite(a) && Number.isFinite(b) && a <= b
  rangeError.value = ok ? null : '“From” must be earlier than or equal to “To” (UTC).'
  return ok
}
const debounce = (fn: Function, ms = 200) => {
  let t: number | undefined
  return (...a: any[]) => {
    if (t) clearTimeout(t)
    t = window.setTimeout(() => fn(...a), ms)
  }
}

type Tiles = {
  inProgress: number
  live: number
  myAgents: number
  sharedUsersDistinct: number
  shared?: number
  typeBreakdown?: {
    user: { count: number; live: number; inProgress: number }
    enterprise: { count: number }
    total: number
  }
}

const tiles = ref<Tiles | null>(null)

const usageAll = ref<AnyChartInput | null>(null)
const usageAvg = ref<number | null>(null)
const usageSeriesRaw = ref<Array<{ periodStart: string; count: number }>>([])

const feedbackPie = ref<AnyChartInput | null>(null)
const feedbackRaw = ref<{ positive: number; negative: number; none: number } | null>(null)

type ActivityRow = {
  agentId: string
  agentName: string
  user: string
  questions: number
  avgFeedback: number | null
}
const rows = ref<ActivityRow[]>([])
const total = ref(0)

const entCount = computed(() => tiles.value?.typeBreakdown?.enterprise?.count ?? 0)
const userLive = computed(() => tiles.value?.typeBreakdown?.user?.live ?? tiles.value?.live ?? 0)
const userDrafts = computed(
  () => tiles.value?.typeBreakdown?.user?.inProgress ?? tiles.value?.inProgress ?? 0
)
const userSharedAgents = computed(() => tiles.value?.shared ?? 0)

const loading = reactive({ tiles: false, usage: false, feedback: false, activity: false })
const exporting = reactive({ usageCsv: false, feedbackCsv: false, activityAll: false })

let tTok = 0,
  uTok = 0,
  fTok = 0,
  aTok = 0

let tilesAbort: AbortController | null = null
let usageAbort: AbortController | null = null
let feedbackAbort: AbortController | null = null
let activityAbort: AbortController | null = null

const sortClick = (col: Column<any, unknown>, e: MouseEvent) => {
  col.toggleSorting(col.getIsSorted() === 'asc', e.shiftKey)
}
function toCSV(headers: string[], rows: Array<Array<string | number | null | undefined>>): string {
  const esc = (v: any) => {
    if (v == null) return ''
    const s = String(v)
    return /[",\n]/.test(s) ? `"${s.replace(/"/g, '""')}"` : s
  }
  const lines = [headers.map(esc).join(',')]
  for (const r of rows) lines.push(r.map(esc).join(','))
  return lines.join('\n')
}
function downloadCSV(filename: string, csv: string) {
  const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' })
  const url = URL.createObjectURL(blob)
  const a = document.createElement('a')
  a.href = url
  a.download = filename
  a.click()
  URL.revokeObjectURL(url)
}
function filename(base: string) {
  const agent = agentId.value === 'all' ? 'all' : agentId.value
  return `${base}_${bucket.value}_${from.value}_${to.value}_${agent}.csv`
}

async function exportUsageCSV() {
  exporting.usageCsv = true
  try {
    const csv = toCSV(
      ['periodStart', 'count', 'bucket', 'avgUsage', 'from', 'to', 'agentId'],
      usageSeriesRaw.value.map((r) => [
        r.periodStart,
        r.count,
        bucket.value,
        usageAvg.value ?? '',
        from.value,
        to.value,
        agentId.value,
      ])
    )
    downloadCSV(filename('usage'), csv)
  } finally {
    exporting.usageCsv = false
  }
}
async function exportFeedbackCSV() {
  exporting.feedbackCsv = true
  try {
    const fb = feedbackRaw.value ?? { positive: 0, negative: 0, none: 0 }
    const csv = toCSV(
      ['label', 'count', 'from', 'to', 'agentId'],
      [
        ['positive', fb.positive, from.value, to.value, agentId.value],
        ['negative', fb.negative, from.value, to.value, agentId.value],
        ['none', fb.none, from.value, to.value, agentId.value],
      ]
    )
    downloadCSV(filename('feedback'), csv)
  } finally {
    exporting.feedbackCsv = false
  }
}

async function exportActivityAllCSV() {
  exporting.activityAll = true
  try {
    const s = (sorting.value && sorting.value[0]) || null
    const base: any = { from: from.value, to: to.value, ...scopeParams() }
    if (agentId.value !== 'all') base.agentId = String(agentId.value)
    if (activitySearch.value.trim()) base.q = activitySearch.value.trim()
    if (s && s.id) {
      base.sortBy = s.id
      base.sortDir = s.desc ? 'desc' : 'asc'
    }
    if (groupBy.value !== 'none') base.groupBy = groupBy.value
    const headers = ['agentId', 'agentName', 'user', 'questions', 'avgFeedback']
    const out: Array<Array<string | number | null | undefined>> = []
    let offset = 0
    const limit = 500
    for (;;) {
      const params = { ...base, limit, offset }
      const { data } = await API.getDashboardActivity(params)
      const list = data?.rows ?? []
      for (const r of list) {
        out.push([
          r.agentId ?? '',
          r.agentName ?? '',
          r.user ?? '',
          r.questions ?? '',
          r.avgFeedback ?? '',
        ])
      }
      offset += list.length
      const totalRemote = data?.total ?? 0
      if (!list.length || offset >= totalRemote) break
    }
    const csv = toCSV(headers, out)
    downloadCSV(filename('activity_all'), csv)
  } finally {
    exporting.activityAll = false
  }
}

async function loadMyAgents() {
  const params: any = isProjectAdmin.value && ownerId.value ? { ownerId: ownerId.value } : undefined
  const { data } = await API.getDashboardMyAgents(params)
  myAgents.value = data?.agents ?? []
  // ensure selected agentId is still valid under new owner scope
  if (
    agentId.value !== 'all' &&
    !myAgents.value.some((a) => String(a.id) === String(agentId.value))
  ) {
    agentId.value = 'all'
  }
}

async function loadTiles() {
  if (!isValidRange()) return
  const token = ++tTok
  loading.tiles = true

  tilesAbort?.abort()
  const controller = new AbortController()
  tilesAbort = controller

  try {
    const { data } = await API.getDashboardTiles(
      { from: from.value, to: to.value, ...scopeParams() },
      { signal: controller.signal }
    )
    if (token === tTok) tiles.value = data as Tiles
  } catch (err: any) {
  } finally {
    if (token === tTok && !controller.signal.aborted) loading.tiles = false
  }
}

function buildUsageInput(series: Array<{ periodStart: string; count: number }>): AnyChartInput {
  const x = series.map((s) => s.periodStart)
  const y = series.map((s) => Number(s.count || 0))
  const avgLine = usageAvg.value ?? undefined

  if (bucket.value === 'day') {
    return {
      kind: 'line',
      xIsDate: true,
      x,
      series: [{ name: 'Replies', data: y }],
      yUnit: 'Assistant messages',
      xAxisName: 'Day',
      yAxisName: 'Assistant messages',
      avgLine,
    } as any as AnyChartInput
  }
  return {
    kind: 'bar',
    x,
    series: [{ name: 'Replies', data: y }],
    yUnit: 'Assistant messages',
    xAxisName: bucket.value === 'week' ? 'Week' : 'Month',
    yAxisName: 'Assistant messages',
    avgLine,
  } as any as AnyChartInput
}

async function loadUsage() {
  if (!isValidRange()) return
  const token = ++uTok
  loading.usage = true

  usageAbort?.abort()
  const controller = new AbortController()
  usageAbort = controller

  try {
    const params: any = { bucket: bucket.value, from: from.value, to: to.value, ...scopeParams() }
    if (agentId.value !== 'all') params.agentId = String(agentId.value)
    const { data } = await API.getDashboardUsage(params, { signal: controller.signal })
    const series = data?.series ?? []
    if (token === uTok) {
      usageSeriesRaw.value = series
      usageAvg.value = typeof data?.avgUsage === 'number' ? data.avgUsage : null
      usageAll.value = buildUsageInput(series)
    }
  } catch (err: any) {
  } finally {
    if (token === uTok && !controller.signal.aborted) loading.usage = false
  }
}

async function loadFeedback() {
  if (!isValidRange()) return
  const token = ++fTok
  loading.feedback = true

  feedbackAbort?.abort()
  const controller = new AbortController()
  feedbackAbort = controller

  try {
    const params: any = { from: from.value, to: to.value, ...scopeParams() }
    if (agentId.value !== 'all') params.agentId = String(agentId.value)
    const { data } = await API.getDashboardFeedback(params, { signal: controller.signal })
    if (token === fTok) {
      feedbackRaw.value = {
        positive: data?.positive ?? 0,
        negative: data?.negative ?? 0,
        none: data?.none ?? 0,
      }
      feedbackPie.value = {
        kind: 'pie',
        series: [
          { name: 'Positive', value: feedbackRaw.value.positive },
          { name: 'Negative', value: feedbackRaw.value.negative },
          { name: 'None', value: feedbackRaw.value.none },
        ],
      } as AnyChartInput
    }
  } catch (err: any) {
  } finally {
    if (token === fTok && !controller.signal.aborted) loading.feedback = false
  }
}

const activitySearch = ref('')
const groupBy = ref<'none' | 'agent' | 'user'>('none')

const pagination = reactive({ pageIndex: 0, pageSize: 15 })
const pageCount = computed(() => Math.max(1, Math.ceil((total.value || 0) / pagination.pageSize)))
const pageSizeModel = computed<string>({
  get: () => String(pagination.pageSize),
  set: (v) => {
    pagination.pageSize = Number(v) || 15
  },
})

const sorting = shallowRef<SortingState>([{ id: 'questions', desc: true }])

const columnHelper = createColumnHelper<ActivityRow>()
const columns = [
  columnHelper.accessor('agentName', { header: 'Agent', cell: (info) => info.getValue() }),
  columnHelper.accessor('user', { header: 'User', cell: (info) => info.getValue() }),
  columnHelper.accessor('questions', { header: 'Questions', cell: (info) => info.getValue() }),
  columnHelper.accessor('avgFeedback', {
    header: 'Avg feedback',
    cell: (info) => {
      const v = info.getValue()
      return v == null ? '—' : Number(v).toFixed(2)
    },
  }),
] as ColumnDef<ActivityRow, any>[]

const table = useVueTable({
  get data() {
    return rows.value
  },
  get columns() {
    return columns
  },
  getCoreRowModel: getCoreRowModel(),
  manualPagination: true,
  manualSorting: true,
  manualFiltering: true,
  state: {
    get sorting() {
      return sorting.value
    },
    get pagination() {
      return pagination
    },
  },
  get pageCount() {
    return pageCount.value
  },
  onSortingChange: (updater: any) => {
    const next = typeof updater === 'function' ? updater(sorting.value ?? []) : updater
    sorting.value = Array.isArray(next) ? next.map((s: any) => ({ ...s })) : []
  },
})

const showColumnsMenu = ref(false)
function toggleColumn(id: 'agentName' | 'user' | 'questions' | 'avgFeedback', v: boolean) {
  table.getColumn(id)?.toggleVisibility(v)
}

async function loadActivity() {
  if (!isValidRange()) return
  const token = ++aTok
  loading.activity = true

  activityAbort?.abort()
  const controller = new AbortController()
  activityAbort = controller

  try {
    const s = sorting.value?.[0]
    const params: any = {
      from: from.value,
      to: to.value,
      limit: pagination.pageSize,
      offset: pagination.pageIndex * pagination.pageSize,
      ...scopeParams(),
    }
    if (agentId.value !== 'all') params.agentId = String(agentId.value)
    if (activitySearch.value.trim()) params.q = activitySearch.value.trim()
    if (s?.id) {
      params.sortBy = s.id
      params.sortDir = s.desc ? 'desc' : 'asc'
    }
    if (groupBy.value !== 'none') params.groupBy = groupBy.value

    const { data } = await API.getDashboardActivity(params, { signal: controller.signal })
    if (token === aTok) {
      rows.value = data?.rows ?? []
      total.value = data?.total ?? 0
    }
  } catch (err: any) {
  } finally {
    if (token === aTok && !controller.signal.aborted) loading.activity = false
  }
}

let activityTimer: number | undefined
function scheduleActivityLoad() {
  if (activityTimer) window.clearTimeout(activityTimer)
  activityTimer = window.setTimeout(() => {
    loadActivity()
  }, 120)
}

const refreshForRange = debounce(() => {
  loadTiles()
  loadUsage()
  loadFeedback()
  pagination.pageIndex = 0
  scheduleActivityLoad()
}, 220)
watch([from, to], refreshForRange)

watch([agentType, ownerId], () => {
  pagination.pageIndex = 0
  loadTiles()
  loadUsage()
  loadFeedback()
  scheduleActivityLoad()
})
watch(ownerId, async () => {
  await loadMyAgents()
})

watch(agentId, () => {
  pagination.pageIndex = 0
  loadUsage()
  loadFeedback()
  scheduleActivityLoad()
})
watch(bucket, () => {
  loadUsage()
})
watch(
  sorting,
  () => {
    pagination.pageIndex = 0
    scheduleActivityLoad()
  },
  { deep: false }
)
watch(() => pagination.pageIndex, scheduleActivityLoad)
watch(
  () => pagination.pageSize,
  () => {
    pagination.pageIndex = 0
    scheduleActivityLoad()
  }
)
watch(
  activitySearch,
  debounce(() => {
    pagination.pageIndex = 0
    scheduleActivityLoad()
  }, 300)
)
watch(groupBy, () => {
  pagination.pageIndex = 0
  scheduleActivityLoad()
})

async function loadCurrentUserAndOwners() {
  try {
    const me = await API.getCurrentUser()
    isProjectAdmin.value = !!me?.data?.isProjectAdmin
    if (isProjectAdmin.value) {
      const resp = await API.listAgentOwners()
      owners.value = resp?.data?.owners ?? []
    } else {
      owners.value = []
    }
  } catch (e) {
    // ignore
  }
}

onMounted(async () => {
  await loadCurrentUserAndOwners()
  await loadMyAgents()
  await Promise.all([loadTiles(), loadUsage(), loadFeedback(), loadActivity()])
})

onUnmounted(() => {
  tilesAbort?.abort()
  usageAbort?.abort()
  feedbackAbort?.abort()
  activityAbort?.abort()
})
</script>

<template>
  <div class="p-4 sm:p-6 overflow-x-hidden">
    <div class="text-center mb-6 sm:pt-14">
      <h1 class="text-3xl font-bold text-primary-hover mb-2">Monitoring</h1>
      <p class="text-foreground max-w-2xl mx-auto text-base sm:text-lg">
        {{
          isProjectAdmin
            ? 'Usage, feedback and activity across agents'
            : 'Usage, feedback and activity across your agents'
        }}
      </p>
    </div>

    <!-- Project owner meta filters (collapsible, same styling) -->
    <div v-if="isProjectAdmin" class="mx-auto max-w-4xl mb-10">
      <!-- Title -->
      <p class="text-sm text-foreground text-center mb-4">
        As an Agent Hub admin, use the below filters to drill down into Agent Hub activities by
        agent type and users.
      </p>

      <!-- Filters -->
      <div class="grid grid-cols-1 sm:grid-cols-2 gap-3">
        <!-- Monitoring scope -->
        <div class="w-full sm:min-w-[220px]">
          <label class="block text-xs text-muted-foreground mb-1">Monitoring scope</label>
          <Select v-model="agentType" aria-label="Agent scope">
            <SelectTrigger class="w-full">
              <SelectValue placeholder="All (Enterprise + User)" />
            </SelectTrigger>
            <SelectContent>
              <SelectItem value="all">All (Enterprise + User)</SelectItem>
              <SelectItem value="user">User agents</SelectItem>
              <SelectItem value="enterprise">Enterprise agents</SelectItem>
            </SelectContent>
          </Select>
        </div>

        <!-- User agent owner -->
        <div class="w-full sm:min-w-[260px]">
          <label class="block text-xs text-muted-foreground mb-1">User agent owner</label>
          <Select
            v-model="ownerIdModel"
            aria-label="Filter by owner"
            :disabled="agentType === 'enterprise'"
          >
            <SelectTrigger class="w-full">
              <SelectValue placeholder="All owners" />
            </SelectTrigger>
            <SelectContent>
              <SelectItem :value="ALL_OWNERS_VALUE">All owners</SelectItem>
              <SelectItem v-for="o in owners" :key="o.id" :value="o.id">
                {{ o.displayName || o.id }}
                <span v-if="o.displayName" class="text-muted-foreground"> ({{ o.id }})</span>
                — {{ o.agentCount ?? 0 }}
              </SelectItem>
            </SelectContent>
          </Select>
        </div>
      </div>
    </div>

    <div
      class="mx-auto mb-10 max-w-full"
      :class="isProjectAdmin ? 'sm:max-w-[calc((5*20rem+1rem)/3)]' : 'sm:max-w-[20rem]'"
    >
      <template v-if="isProjectAdmin">
        <div class="grid grid-cols-1 sm:grid-cols-5 gap-2 mb-1">
          <div class="sm:col-span-1 flex items-center gap-2">
            <i class="dku-icon-briefcase-20 text-primary-alpha-dark-70"></i>
            <h3 class="text-sm font-medium whitespace-nowrap">Enterprise agents</h3>
          </div>

          <div class="sm:col-span-3 sm:col-start-3 flex items-center gap-2 mt-2 sm:mt-0">
            <i class="dku-icon-user-20 text-primary-alpha-dark-70"></i>
            <h3 class="text-sm font-medium whitespace-nowrap">User agents</h3>
          </div>
        </div>

        <div class="grid grid-cols-1 sm:grid-cols-5 gap-2">
          <Card
            class="sm:col-span-1 bg-[var(--color-white)] border border-gray-200 py-2 rounded-[var(--radius)]"
          >
            <div class="p-2 text-center">
              <div class="text-xs text-muted-foreground mb-1">Total</div>
              <div class="text-xl font-bold text-teal-600">
                {{ loading.tiles ? '…' : tiles ? entCount : '—' }}
              </div>
            </div>
          </Card>

          <Card
            class="sm:col-span-2 sm:col-start-3 bg-[var(--color-white)] border border-gray-200 py-2 rounded-[var(--radius)]"
          >
            <div class="grid grid-cols-2 divide-x divide-gray-200">
              <div class="p-2 text-center">
                <div class="text-xs text-muted-foreground mb-1">Live</div>
                <div class="text-xl font-bold text-teal-600">
                  {{ loading.tiles ? '…' : tiles ? userLive : '—' }}
                </div>
              </div>
              <div class="p-2 text-center">
                <div class="text-xs text-muted-foreground mb-1">Shared</div>
                <div class="text-xl font-bold text-teal-600">
                  {{ loading.tiles ? '…' : tiles ? userSharedAgents : '—' }}
                </div>
              </div>
            </div>
          </Card>

          <Card
            class="sm:col-span-1 sm:col-start-5 bg-[var(--color-white)] border border-gray-200 py-2 rounded-[var(--radius)]"
          >
            <div class="p-2 text-center">
              <div class="text-xs text-muted-foreground mb-1">Drafts</div>
              <div class="text-xl font-bold text-teal-600">
                {{ loading.tiles ? '…' : tiles ? userDrafts : '—' }}
              </div>
            </div>
          </Card>
        </div>
      </template>

      <template v-else>
        <div class="grid grid-cols-3 gap-2">
          <Card
            class="col-span-2 bg-[var(--color-white)] border border-gray-200 py-2 rounded-[var(--radius)]"
          >
            <div class="grid grid-cols-2 divide-x divide-gray-200">
              <div class="p-2 text-center">
                <div class="text-xs text-muted-foreground mb-1">Live</div>
                <div class="text-xl font-bold text-teal-600">
                  {{ loading.tiles ? '…' : tiles ? userLive : '—' }}
                </div>
              </div>
              <div class="p-2 text-center">
                <div class="text-xs text-muted-foreground mb-1">Shared</div>
                <div class="text-xl font-bold text-teal-600">
                  {{ loading.tiles ? '…' : tiles ? userSharedAgents : '—' }}
                </div>
              </div>
            </div>
          </Card>

          <Card class="bg-[var(--color-white)] border border-gray-200 py-2 rounded-[var(--radius)]">
            <div class="p-2 text-center">
              <div class="text-xs text-muted-foreground mb-1">Drafts</div>
              <div class="text-xl font-bold text-teal-600">
                {{ loading.tiles ? '…' : tiles ? userDrafts : '—' }}
              </div>
            </div>
          </Card>
        </div>
      </template>
    </div>

    <div class="flex flex-wrap items-end gap-2 sm:gap-3 mb-4">
      <div class="w-full sm:w-auto sm:min-w-[220px]">
        <label class="block text-sm text-muted-foreground mb-1">By agent</label>
        <Select
          v-model="agentId"
          aria-label="Filter by agent"
          :disabled="isProjectAdmin && agentType === 'enterprise'"
        >
          <SelectTrigger
            data-size="sm"
            class="w-full !h-8 px-2 pr-6 text-sm cursor-pointer !py-0 leading-[32px]"
          >
            <SelectValue placeholder="All my agents" />
          </SelectTrigger>
          <SelectContent>
            <SelectItem value="all">All my agents</SelectItem>
            <SelectItem v-for="a in myAgents" :key="a.id" :value="a.id">{{ a.name }}</SelectItem>
          </SelectContent>
        </Select>
      </div>

      <div>
        <label class="block text-xs text-muted-foreground mb-1">From</label>
        <Input
          type="date"
          v-model="from"
          aria-label="From date"
          class="w-[120px] sm:w-[140px] h-8 px-2 pr-1 text-sm cursor-pointer"
        />
      </div>
      <div>
        <label class="block text-xs text-muted-foreground mb-1">To</label>
        <Input
          type="date"
          v-model="to"
          aria-label="To date"
          class="w-[120px] sm:w-[140px] h-8 px-2 pr-1 text-sm cursor-pointer"
        />
      </div>

      <p v-if="rangeError" class="text-xs text-red-600 ml-auto">{{ rangeError }}</p>
    </div>

    <div class="grid grid-cols-1 lg:grid-cols-3 gap-4">
      <Card
        class="lg:col-span-2 bg-[var(--color-white)] border border-gray-200 rounded-[var(--radius)] pb-0 sm:pb-0"
      >
        <div class="p-1 sm:p-5 pb-0 sm:pb-0 sm:pt-1">
          <div class="flex flex-col mb-2 sm:mb-2">
            <div class="flex flex-wrap items-center justify-between gap-2 sm:gap-3 -mb-1">
              <h3 class="font-semibold">Number of Agents messages</h3>

              <div class="flex items-center gap-2">
                <button
                  type="button"
                  class="p-1.5 rounded border border-gray-200 hover:bg-muted text-muted-foreground"
                  :disabled="exporting.usageCsv || !usageSeriesRaw.length"
                  @click.stop.prevent="exportUsageCSV()"
                  title="Export CSV"
                >
                  <i class="dku-icon-arrow-download-16"></i>
                  <span class="sr-only">Export CSV</span>
                </button>
                <button
                  type="button"
                  class="p-1.5 rounded border border-gray-200 hover:bg-muted text-muted-foreground"
                  :disabled="!usageAll"
                  @click.stop.prevent="usageChartRef?.saveImage?.()"
                  title="Save image"
                >
                  <i class="dku-icon-image-16"></i><span class="sr-only">Save image</span>
                </button>
              </div>
            </div>
            <p class="text-xs text-muted-foreground mb-4 mt-4">
              Count of assistant messages attributed to your agents per
              {{ bucket === 'day' ? 'day' : bucket === 'week' ? 'week' : 'month' }}. Each message is
              counted once per bucket.
            </p>

            <div class="flex items-center gap-1.5 sm:gap-2">
              <Tabs v-model="bucket">
                <TabsList class="h-9">
                  <TabsTrigger value="day">Daily</TabsTrigger>
                  <TabsTrigger value="week">Weekly</TabsTrigger>
                  <TabsTrigger value="month">Monthly</TabsTrigger>
                </TabsList>
              </Tabs>
              <div
                class="rounded-full px-3 py-1 text-xs sm:text-sm font-semibold bg-[var(--primary-alpha-light-20)] text-[var(--primary-hover)]"
                :title="`Average per ${bucket}`"
              >
                Avg per {{ bucket === 'day' ? 'day' : bucket === 'week' ? 'week' : 'month' }}:
                <span>{{ usageAvg == null ? '—' : usageAvg }}</span>
              </div>
            </div>
          </div>
          <div class="flex items-center gap-1.5 mb-1">
            <button
              type="button"
              class="p-1.5 rounded border border-gray-200 hover:bg-muted text-muted-foreground"
              :disabled="!usageAll"
              @click.stop.prevent="usageChartRef?.restore?.()"
              title="Reset view"
            >
              <i class="dku-icon-arrow-circular-16"></i><span class="sr-only">Reset</span>
            </button>
          </div>
          <div v-if="loading.usage" class="text-sm text-muted-foreground py-10 text-center">
            Loading…
          </div>
          <div
            v-else-if="
              !usageAll ||
              !usageSeriesRaw.length ||
              usageSeriesRaw.every((s) => Number(s.count || 0) === 0)
            "
            class="py-8 mb-4 rounded-md border border-gray-200 bg-muted/30 grid place-items-center text-center"
          >
            <div>
              <div class="text-sm font-medium text-foreground mb-1">No data available</div>
              <p class="text-xs text-muted-foreground">
                Try widening the date range, switching the bucket, or selecting “All my agents”.
              </p>
            </div>
          </div>
          <ChartRenderer v-else ref="usageChartRef" :data="usageAll" />
        </div>
      </Card>

      <Card
        class="bg-[var(--color-white)] border border-gray-200 rounded-[var(--radius)] pb-0 sm:pb-0"
      >
        <div class="p-1 sm:p-5 pb-0 sm:pb-0 sm:pt-1">
          <div class="flex flex-wrap items-center justify-between gap-2 sm:gap-3 -mb-1">
            <h3 class="font-semibold">Feedback</h3>
            <div class="flex items-center gap-2">
              <button
                type="button"
                class="p-1.5 rounded border border-gray-200 hover:bg-muted text-muted-foreground"
                :disabled="exporting.feedbackCsv || !feedbackRaw"
                @click.stop.prevent="exportFeedbackCSV()"
                title="Export CSV"
              >
                <i class="dku-icon-arrow-download-16"></i>
                <span class="sr-only">Export CSV</span>
              </button>
              <button
                type="button"
                class="p-1.5 rounded border border-gray-200 hover:bg-muted text-muted-foreground"
                :disabled="!feedbackPie"
                @click.stop.prevent="feedbackChartRef?.saveImage?.()"
                title="Save image"
              >
                <i class="dku-icon-image-16"></i><span class="sr-only">Save image</span>
              </button>
            </div>
          </div>
          <p class="text-xs text-muted-foreground mb-4 mt-4">
            Feedback split on queries made to your agents over the selected period. "None" means no
            feedback was left.
          </p>
          <div class="flex items-center gap-1.5 mb-1">
            <button
              type="button"
              class="p-1.5 rounded border border-gray-200 hover:bg-muted text-muted-foreground"
              :disabled="!feedbackPie"
              @click.stop.prevent="feedbackChartRef?.restore?.()"
              title="Reset view"
            >
              <i class="dku-icon-arrow-circular-16"></i><span class="sr-only">Reset</span>
            </button>
          </div>
          <div v-if="loading.feedback" class="text-sm text-muted-foreground py-10 text-center">
            Loading…
          </div>
          <div
            v-else-if="
              !feedbackPie ||
              !feedbackRaw ||
              feedbackRaw.positive + feedbackRaw.negative + feedbackRaw.none === 0
            "
            class="py-8 mb-4 rounded-md border border-gray-200 bg-muted/30 grid place-items-center text-center"
          >
            <div>
              <div class="text-sm font-medium text-foreground mb-1">No data available</div>
              <p class="text-xs text-muted-foreground">
                Try widening the date range or choosing another agent.
              </p>
            </div>
          </div>
          <ChartRenderer v-else ref="feedbackChartRef" :data="feedbackPie" />
        </div>
      </Card>
    </div>

    <div class="mt-4">
      <Card
        class="bg-[var(--color-white)] border border-gray-200 rounded-[var(--radius)] py-0 sm:py-0"
      >
        <div class="p-4 sm:p-5">
          <div class="flex flex-wrap items-center justify-between gap-2 sm:gap-3 mb-2">
            <h3 class="font-semibold">Activity</h3>
            <div class="flex flex-wrap items-center gap-2">
              <div class="w-full sm:w-56">
                <Input
                  v-model="activitySearch"
                  placeholder="Search user or agent…"
                  aria-label="Search activity"
                  @keydown.enter.prevent
                />
              </div>

              <div class="relative">
                <button
                  type="button"
                  class="p-1.5 rounded hover:bg-muted text-muted-foreground"
                  @click.stop.prevent="showColumnsMenu = !showColumnsMenu"
                  title="Columns"
                >
                  ☰ <span class="sr-only">Columns</span>
                </button>
                <div
                  v-if="showColumnsMenu"
                  class="absolute right-0 mt-2 z-10 bg-[var(--color-white)] border border-gray-200 rounded shadow p-2 w-48"
                >
                  <label class="flex items-center gap-2 py-1 text-sm">
                    <input
                      type="checkbox"
                      :checked="table.getColumn('agentName')?.getIsVisible()"
                      @change="
                        toggleColumn('agentName', ($event.target as HTMLInputElement).checked)
                      "
                    />
                    Agent
                  </label>
                  <label class="flex items-center gap-2 py-1 text-sm">
                    <input
                      type="checkbox"
                      :checked="table.getColumn('user')?.getIsVisible()"
                      @change="toggleColumn('user', ($event.target as HTMLInputElement).checked)"
                    />
                    User
                  </label>
                  <label class="flex items-center gap-2 py-1 text-sm">
                    <input
                      type="checkbox"
                      :checked="table.getColumn('questions')?.getIsVisible()"
                      @change="
                        toggleColumn('questions', ($event.target as HTMLInputElement).checked)
                      "
                    />
                    Questions
                  </label>
                  <label class="flex items-center gap-2 py-1 text-sm">
                    <input
                      type="checkbox"
                      :checked="table.getColumn('avgFeedback')?.getIsVisible()"
                      @change="
                        toggleColumn('avgFeedback', ($event.target as HTMLInputElement).checked)
                      "
                    />
                    Avg feedback
                  </label>
                </div>
              </div>

              <div class="w-full sm:w-40">
                <Select v-model="groupBy" aria-label="Group rows">
                  <SelectTrigger class="w-full"
                    ><SelectValue placeholder="Group by"
                  /></SelectTrigger>
                  <SelectContent>
                    <SelectItem value="none">No grouping</SelectItem>
                    <SelectItem value="agent">Group by agent</SelectItem>
                    <SelectItem value="user">Group by user</SelectItem>
                  </SelectContent>
                </Select>
              </div>

              <button
                type="button"
                class="p-1.5 rounded hover:bg-muted text-muted-foreground"
                :disabled="exporting.activityAll"
                @click.stop.prevent="exportActivityAllCSV()"
                title="Export all (CSV)"
              >
                <i class="dku-icon-arrow-download-16"></i>
                <span class="sr-only">Export all</span>
              </button>
            </div>
          </div>

          <div class="relative h-[420px] rounded-md border border-gray-200">
            <div
              v-if="loading.activity"
              class="absolute inset-0 z-10 grid place-items-center bg-[var(--color-white)]/60 backdrop-blur-[1px]"
            >
              <span class="text-sm text-muted-foreground">Loading…</span>
            </div>

            <div class="h-full overflow-y-auto" @click="showColumnsMenu = false">
              <table class="w-full text-sm">
                <thead class="sticky top-0 bg-[var(--color-white)]">
                  <tr
                    v-for="hg in table.getHeaderGroups()"
                    :key="hg.id"
                    class="text-left text-muted-foreground border-b"
                  >
                    <th
                      v-for="h in hg.headers"
                      :key="h.id"
                      class="py-2 px-3 font-medium select-none"
                    >
                      <button
                        type="button"
                        class="inline-flex items-center gap-1 cursor-pointer"
                        @click.stop.prevent="sortClick(h.column, $event)"
                        :aria-sort="
                          h.column.getIsSorted()
                            ? h.column.getIsSorted() === 'asc'
                              ? 'ascending'
                              : 'descending'
                            : 'none'
                        "
                      >
                        <FlexRender :render="h.column.columnDef.header" :props="h.getContext()" />
                        <span class="text-xs">
                          {{
                            h.column.getIsSorted() === 'asc'
                              ? '▲'
                              : h.column.getIsSorted() === 'desc'
                              ? '▼'
                              : ''
                          }}
                        </span>
                      </button>
                    </th>
                  </tr>
                </thead>

                <tbody>
                  <tr
                    v-for="row in table.getRowModel().rows"
                    :key="row.id"
                    class="border-b last:border-0"
                  >
                    <td v-for="cell in row.getVisibleCells()" :key="cell.id" class="py-2 px-3">
                      <FlexRender :render="cell.column.columnDef.cell" :props="cell.getContext()" />
                    </td>
                  </tr>
                  <tr v-if="!table.getRowModel().rows.length">
                    <td :colspan="table.getHeaderGroups()[0].headers.length" class="px-3">
                      <div
                        class="my-6 py-8 mb-4 text-center text-sm text-muted-foreground rounded-md border border-gray-200 bg-muted/30"
                      >
                        No data available.
                      </div>
                    </td>
                  </tr>
                </tbody>
              </table>
            </div>
          </div>

          <div class="flex items-center justify-between mt-3">
            <div class="text-xs text-muted-foreground">
              Page {{ pagination.pageIndex + 1 }} of {{ pageCount }}
              • Rows
              {{ Math.min(total, pagination.pageIndex * pagination.pageSize + 1) }}–{{
                Math.min(total, (pagination.pageIndex + 1) * pagination.pageSize)
              }}
              of {{ total }}
            </div>
            <div class="flex items-center gap-2">
              <button
                type="button"
                class="px-2 py-1 border rounded disabled:opacity-50"
                :disabled="pagination.pageIndex === 0"
                @click.stop.prevent="pagination.pageIndex = Math.max(0, pagination.pageIndex - 1)"
                title="Previous page"
              >
                <i class="dku-icon-arrow-previous-16"></i>
                <span class="sr-only">Previous</span>
              </button>
              <button
                type="button"
                class="px-2 py-1 border rounded disabled:opacity-50"
                :disabled="pagination.pageIndex + 1 >= pageCount"
                @click.stop.prevent="
                  pagination.pageIndex = Math.min(pageCount - 1, pagination.pageIndex + 1)
                "
                title="Next page"
              >
                <i class="dku-icon-arrow-next-16"></i>
                <span class="sr-only">Next</span>
              </button>

              <Select v-model="pageSizeModel" aria-label="Rows per page">
                <SelectTrigger class="w-[120px]"
                  ><SelectValue placeholder="Rows per page"
                /></SelectTrigger>
                <SelectContent>
                  <SelectItem value="10">10 / page</SelectItem>
                  <SelectItem value="15">15 / page</SelectItem>
                  <SelectItem value="25">25 / page</SelectItem>
                  <SelectItem value="50">50 / page</SelectItem>
                </SelectContent>
              </Select>
            </div>
          </div>
        </div>
      </Card>
    </div>
  </div>
</template>
