import {
  ActionIcon,
  Alert,
  Anchor,
  Badge,
  Button,
  Card,
  Group,
  Input,
  Loader,
  Menu,
  NumberFormatter,
  SimpleGrid,
  Stack,
  Typography
} from '@tidbcloud/uikit'
import { MRT_ColumnDef, ProTable } from '@tidbcloud/uikit/biz'
import {
  IconArrowLeft,
  IconCalendar,
  IconChevronDown,
  IconChevronLeft,
  IconChevronRight,
  IconRefreshCw01
} from '@tidbcloud/uikit/icons'
import dayjs from 'dayjs'
import utc from 'dayjs/plugin/utc'
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
import { Link, useHistory, useLocation } from 'react-router-dom'

import {
  approvalControllerGetApproval,
  getTenant,
  operationControllerListInstances
} from 'apiClient/services/devops'
import {
  OperationInstance,
  OperationInstancePhase
} from 'apiClient/services/devops/interface'

dayjs.extend(utc)

const OPERATION = 'AddCreditsForTenant'
const PAGE_SIZE = 100
const APPROVAL_FETCH_BATCH_SIZE = 10
const MAX_REPORT_MONTHS = 12
const TENANT_FETCH_BATCH_SIZE = 10

const isValidReportMonth = (month: string) =>
  /^\d{4}-(0[1-9]|1[0-2])$/.test(month) &&
  !dayjs(month).isAfter(dayjs(), 'month')

const getReportRange = (search: string) => {
  const searchParams = new URLSearchParams(search)
  const currentMonth = dayjs().format('YYYY-MM')
  const legacyMonth = searchParams.get('month') || ''
  let startMonth = searchParams.get('start_month') || legacyMonth
  let endMonth = searchParams.get('end_month') || legacyMonth

  if (!isValidReportMonth(startMonth)) {
    startMonth = currentMonth
  }
  if (!isValidReportMonth(endMonth)) {
    endMonth = currentMonth
  }

  if (dayjs(startMonth).isAfter(dayjs(endMonth), 'month')) {
    const previousStartMonth = startMonth
    startMonth = endMonth
    endMonth = previousStartMonth
  }

  if (dayjs(endMonth).diff(dayjs(startMonth), 'month') >= MAX_REPORT_MONTHS) {
    startMonth = dayjs(endMonth)
      .subtract(MAX_REPORT_MONTHS - 1, 'month')
      .format('YYYY-MM')
  }

  return { endMonth, startMonth }
}

type AddCreditsRow = OperationInstance & {
  approvers?: string[]
  credits: number
  department: string
  tenantId?: string
  tenantName?: string
}

type DepartmentSummary = {
  credits: number
  department: string
  grantedCredits: number
  requests: number
  succeeded: number
}

type TenantSummary = {
  credits: number
  grantedCredits: number
  tenantId: string
  tenantName?: string
}

const PHASE_COLORS: Record<OperationInstancePhase, string> = {
  [OperationInstancePhase.approving]: 'yellow',
  [OperationInstancePhase.canceled]: 'gray',
  [OperationInstancePhase.created]: 'blue',
  [OperationInstancePhase.draft]: 'gray',
  [OperationInstancePhase.failed]: 'red',
  [OperationInstancePhase.pending]: 'orange',
  [OperationInstancePhase.running]: 'cyan',
  [OperationInstancePhase.succeeded]: 'green',
  [OperationInstancePhase.withdrawn]: 'gray'
}

const tableCommonProps = {
  enableColumnActions: false,
  enableColumnFilters: false,
  enableDensityToggle: false,
  enableFullScreenToggle: false,
  enableHiding: false,
  enableSorting: false,
  enableTopToolbar: false,
  mantineTableProps: {
    horizontalSpacing: 'md' as const,
    verticalSpacing: 'sm' as const
  }
}

const parseCredits = (value?: string) => {
  const parsed = Number((value || '').replace(/,/g, ''))
  return Number.isFinite(parsed) ? parsed : 0
}

const toAddCreditsRow = (instance: OperationInstance): AddCreditsRow => ({
  ...instance,
  credits: parseCredits(
    instance.params?.total_credits || instance.params?.credits
  ),
  department: instance.params?.department || 'Unspecified',
  tenantId: instance.params?.tenant_id
})

const fetchTenantNames = async (
  tenantIds: string[],
  cachedNames: Record<string, string>
) => {
  const tenantNames = { ...cachedNames }
  const missingTenantIds = tenantIds.filter(
    (tenantId) => !tenantNames[tenantId]
  )

  for (
    let index = 0;
    index < missingTenantIds.length;
    index += TENANT_FETCH_BATCH_SIZE
  ) {
    const batch = missingTenantIds.slice(index, index + TENANT_FETCH_BATCH_SIZE)
    const entries = await Promise.all(
      batch.map(async (tenantId) => {
        try {
          const response = await getTenant(tenantId)
          return [
            tenantId,
            response.data.name || response.data.alias || ''
          ] as const
        } catch {
          return [tenantId, ''] as const
        }
      })
    )

    entries.forEach(([tenantId, tenantName]) => {
      if (tenantName) {
        tenantNames[tenantId] = tenantName
      }
    })
  }

  return tenantNames
}

const fetchApprovalApprovers = async (
  approvalIds: number[],
  cachedApprovers: Record<number, string[]>
) => {
  const approvalApprovers = { ...cachedApprovers }
  const missingApprovalIds = approvalIds.filter(
    (approvalId) =>
      !Object.prototype.hasOwnProperty.call(approvalApprovers, approvalId)
  )

  for (
    let index = 0;
    index < missingApprovalIds.length;
    index += APPROVAL_FETCH_BATCH_SIZE
  ) {
    const batch = missingApprovalIds.slice(
      index,
      index + APPROVAL_FETCH_BATCH_SIZE
    )
    const entries = await Promise.all(
      batch.map(async (approvalId) => {
        try {
          const response = await approvalControllerGetApproval(approvalId)
          const approvers = Array.from(
            new Set(
              (response.data.approval?.levels || [])
                .flatMap((level) => level.nodes || [])
                .flatMap((node) => node.tasks || [])
                .map((task) => task.user_email)
                .filter((email): email is string => Boolean(email))
            )
          )
          return [approvalId, approvers] as const
        } catch {
          return [approvalId, undefined] as const
        }
      })
    )

    entries.forEach(([approvalId, approvers]) => {
      if (approvers !== undefined) {
        approvalApprovers[approvalId] = approvers
      }
    })
  }

  return approvalApprovers
}

const formatCreatedAt = (value?: number) =>
  value ? dayjs.unix(value).utc().format('YYYY-MM-DD HH:mm:ss') : '-'

const CreditsValue = ({ value }: { value: number }) => (
  <NumberFormatter
    value={value}
    decimalScale={2}
    fixedDecimalScale
    thousandSeparator
  />
)

const PhaseBadge = ({ phase }: { phase: OperationInstancePhase }) => (
  <Badge color={PHASE_COLORS[phase]} variant="light">
    {phase}
  </Badge>
)

const TenantDisplay = ({
  tenantId,
  tenantName
}: {
  tenantId?: string
  tenantName?: string
}) => {
  if (!tenantId || tenantId === 'Unspecified') {
    return '-'
  }

  return (
    <Stack gap={0}>
      <Anchor component={Link} to={`/orgs/${tenantId}`}>
        {tenantName || 'Unknown tenant'}
      </Anchor>
      <Typography variant="body-sm" c="dimmed">
        {tenantId}
      </Typography>
    </Stack>
  )
}

const MetricCard = ({
  label,
  value,
  credits = false
}: {
  credits?: boolean
  label: string
  value: number
}) => (
  <Card p="lg" shadow="xs" withBorder>
    <Stack gap={4}>
      <Typography variant="label-lg" c="dimmed">
        {label}
      </Typography>
      <Typography variant="headline-lg">
        {credits ? <CreditsValue value={value} /> : value}
      </Typography>
    </Stack>
  </Card>
)

const MonthPickerControl = ({
  label,
  value,
  onChange
}: {
  label: string
  onChange: (value: string) => void
  value: string
}) => {
  const selectedMonth = dayjs(value, 'YYYY-MM')
  const [opened, setOpened] = useState(false)
  const [displayYear, setDisplayYear] = useState(selectedMonth.year())
  const currentYear = dayjs().year()

  const handleOpenedChange = (nextOpened: boolean) => {
    setOpened(nextOpened)
    if (nextOpened) {
      setDisplayYear(selectedMonth.year())
    }
  }

  return (
    <Stack gap={6}>
      <Typography variant="label-sm">{label}</Typography>
      <Menu
        opened={opened}
        position="bottom-end"
        shadow="sm"
        transitionProps={{ duration: 0 }}
        onChange={handleOpenedChange}
      >
        <Menu.Target>
          <Input
            component="button"
            leftSection={<IconCalendar size={16} />}
            rightSection={<IconChevronDown size={16} />}
            styles={{
              input: { cursor: 'pointer', minWidth: 180, textAlign: 'left' },
              section: { pointerEvents: 'none' }
            }}
            onClick={() => handleOpenedChange(!opened)}
          >
            {selectedMonth.format('MMMM YYYY')}
          </Input>
        </Menu.Target>
        <Menu.Dropdown p="md">
          <Stack gap="sm" w={280}>
            <Group justify="space-between">
              <ActionIcon
                aria-label="Previous year"
                variant="subtle"
                onClick={() => setDisplayYear((year) => year - 1)}
              >
                <IconChevronLeft size={16} />
              </ActionIcon>
              <Typography variant="label-lg">{displayYear}</Typography>
              <ActionIcon
                aria-label="Next year"
                disabled={displayYear >= currentYear}
                variant="subtle"
                onClick={() => setDisplayYear((year) => year + 1)}
              >
                <IconChevronRight size={16} />
              </ActionIcon>
            </Group>
            <SimpleGrid cols={3} spacing="xs">
              {Array.from({ length: 12 }, (_, index) => {
                const candidate = dayjs(
                  `${displayYear}-${String(index + 1).padStart(2, '0')}-01`
                )
                const isSelected = candidate.isSame(selectedMonth, 'month')
                const isFuture = candidate.isAfter(dayjs(), 'month')

                return (
                  <Button
                    key={candidate.format('YYYY-MM')}
                    disabled={isFuture}
                    size="xs"
                    variant={isSelected ? 'filled' : 'subtle'}
                    onClick={() => {
                      onChange(candidate.format('YYYY-MM'))
                      setOpened(false)
                    }}
                  >
                    {candidate.format('MMM')}
                  </Button>
                )
              })}
            </SimpleGrid>
          </Stack>
        </Menu.Dropdown>
      </Menu>
    </Stack>
  )
}

export default function TenantCreditsMonthlyReport() {
  const history = useHistory()
  const location = useLocation()
  const { endMonth, startMonth } = useMemo(
    () => getReportRange(location.search),
    [location.search]
  )
  const [rows, setRows] = useState<AddCreditsRow[]>([])
  const [approversLoading, setApproversLoading] = useState(false)
  const [loading, setLoading] = useState(false)
  const [error, setError] = useState('')
  const requestIdRef = useRef(0)
  const approvalApproversCacheRef = useRef<Record<number, string[]>>({})
  const tenantNameCacheRef = useRef<Record<string, string>>({})

  useEffect(() => {
    const searchParams = new URLSearchParams(location.search)
    if (
      searchParams.get('start_month') === startMonth &&
      searchParams.get('end_month') === endMonth &&
      !searchParams.has('month')
    ) {
      return
    }

    searchParams.delete('month')
    searchParams.set('start_month', startMonth)
    searchParams.set('end_month', endMonth)
    history.replace({
      ...location,
      search: searchParams.toString()
    })
  }, [endMonth, history, location, startMonth])

  const updateReportRange = useCallback(
    (nextStartMonth: string, nextEndMonth: string) => {
      const searchParams = new URLSearchParams(location.search)
      searchParams.delete('month')
      searchParams.set('start_month', nextStartMonth)
      searchParams.set('end_month', nextEndMonth)
      history.push({
        ...location,
        search: searchParams.toString()
      })
    },
    [history, location]
  )

  const handleStartMonthChange = useCallback(
    (nextStartMonth: string) => {
      let nextEndMonth = endMonth

      if (dayjs(nextStartMonth).isAfter(dayjs(nextEndMonth), 'month')) {
        nextEndMonth = nextStartMonth
      } else if (
        dayjs(nextEndMonth).diff(dayjs(nextStartMonth), 'month') >=
        MAX_REPORT_MONTHS
      ) {
        nextEndMonth = dayjs(nextStartMonth)
          .add(MAX_REPORT_MONTHS - 1, 'month')
          .format('YYYY-MM')
      }

      updateReportRange(nextStartMonth, nextEndMonth)
    },
    [endMonth, updateReportRange]
  )

  const handleEndMonthChange = useCallback(
    (nextEndMonth: string) => {
      let nextStartMonth = startMonth

      if (dayjs(nextEndMonth).isBefore(dayjs(nextStartMonth), 'month')) {
        nextStartMonth = nextEndMonth
      } else if (
        dayjs(nextEndMonth).diff(dayjs(nextStartMonth), 'month') >=
        MAX_REPORT_MONTHS
      ) {
        nextStartMonth = dayjs(nextEndMonth)
          .subtract(MAX_REPORT_MONTHS - 1, 'month')
          .format('YYYY-MM')
      }

      updateReportRange(nextStartMonth, nextEndMonth)
    },
    [startMonth, updateReportRange]
  )

  const loadData = useCallback(async () => {
    const requestId = ++requestIdRef.current
    const utcStartMonth = dayjs.utc(startMonth, 'YYYY-MM')
    const utcEndMonth = dayjs.utc(endMonth, 'YYYY-MM')
    const commonParams = {
      create_after: utcStartMonth.startOf('month').unix(),
      create_before: utcEndMonth.endOf('month').unix(),
      operation: OPERATION,
      per_page: PAGE_SIZE
    }

    setLoading(true)
    setApproversLoading(false)
    setError('')

    try {
      const firstResponse = await operationControllerListInstances({
        ...commonParams,
        page: 1
      })
      const total = firstResponse.data.total || 0
      const pageCount = Math.ceil(total / PAGE_SIZE)
      const remainingResponses = await Promise.all(
        Array.from({ length: Math.max(0, pageCount - 1) }, (_, index) =>
          operationControllerListInstances({
            ...commonParams,
            page: index + 2
          })
        )
      )

      if (requestId !== requestIdRef.current) {
        return
      }

      const instances = [
        ...(firstResponse.data.items || []),
        ...remainingResponses.flatMap((response) => response.data.items || [])
      ]
      const operationRows = instances.map(toAddCreditsRow)
      const tenantIds = Array.from(
        new Set(
          operationRows
            .map((row) => row.tenantId)
            .filter((tenantId): tenantId is string => Boolean(tenantId))
        )
      )
      const approvalIds = Array.from(
        new Set(
          operationRows
            .map((row) => row.approval_id)
            .filter((approvalId): approvalId is number => Boolean(approvalId))
        )
      )
      const tenantNames = await fetchTenantNames(
        tenantIds,
        tenantNameCacheRef.current
      )

      if (requestId !== requestIdRef.current) {
        return
      }

      tenantNameCacheRef.current = tenantNames
      const rowsWithTenantNames = operationRows.map((row) => ({
        ...row,
        tenantName: row.tenantId ? tenantNames[row.tenantId] : undefined
      }))
      setRows(rowsWithTenantNames)
      setApproversLoading(true)

      void fetchApprovalApprovers(
        approvalIds,
        approvalApproversCacheRef.current
      )
        .then((approvalApprovers) => {
          if (requestId !== requestIdRef.current) {
            return
          }

          approvalApproversCacheRef.current = approvalApprovers
          setRows((currentRows) =>
            currentRows.map((row) => ({
              ...row,
              approvers: row.approval_id
                ? approvalApprovers[row.approval_id]
                : undefined
            }))
          )
        })
        .finally(() => {
          if (requestId === requestIdRef.current) {
            setApproversLoading(false)
          }
        })
    } catch (e) {
      if (requestId !== requestIdRef.current) {
        return
      }
      setRows([])
      setApproversLoading(false)
      setError(
        e?.response?.data?.errmsg ||
          e?.message ||
          'Failed to load AddCreditsForTenant operations.'
      )
    } finally {
      if (requestId === requestIdRef.current) {
        setLoading(false)
      }
    }
  }, [endMonth, startMonth])

  useEffect(() => {
    loadData()
    return () => {
      requestIdRef.current += 1
    }
  }, [loadData])

  const summary = useMemo(() => {
    const succeededRows = rows.filter(
      (row) => row.phase === OperationInstancePhase.succeeded
    )

    return {
      credits: rows.reduce((total, row) => total + row.credits, 0),
      grantedCredits: succeededRows.reduce(
        (total, row) => total + row.credits,
        0
      ),
      requests: rows.length,
      succeeded: succeededRows.length
    }
  }, [rows])

  const departmentSummary = useMemo(() => {
    const grouped = rows.reduce<Record<string, DepartmentSummary>>(
      (result, row) => {
        const department = row.department
        const current = result[department] || {
          credits: 0,
          department,
          grantedCredits: 0,
          requests: 0,
          succeeded: 0
        }

        current.credits += row.credits
        current.requests += 1
        if (row.phase === OperationInstancePhase.succeeded) {
          current.grantedCredits += row.credits
          current.succeeded += 1
        }
        result[department] = current
        return result
      },
      {}
    )

    return Object.values(grouped).sort((a, b) => b.credits - a.credits)
  }, [rows])

  const tenantSummary = useMemo(() => {
    const grouped = rows.reduce<Record<string, TenantSummary>>(
      (result, row) => {
        const tenantId = row.tenantId || 'Unspecified'
        const current = result[tenantId] || {
          credits: 0,
          grantedCredits: 0,
          tenantId,
          tenantName: row.tenantName
        }

        current.credits += row.credits
        if (row.phase === OperationInstancePhase.succeeded) {
          current.grantedCredits += row.credits
        }
        result[tenantId] = current
        return result
      },
      {}
    )

    return Object.values(grouped).sort((a, b) => b.credits - a.credits)
  }, [rows])

  const detailColumns = useMemo<MRT_ColumnDef<AddCreditsRow>[]>(
    () => [
      {
        accessorKey: 'id',
        enableSorting: false,
        header: 'ID',
        size: 90,
        Cell: ({ cell }) => {
          const id = cell.getValue<number | undefined>()
          return id ? (
            <Anchor component={Link} to={`/operations/${id}`}>
              {id}
            </Anchor>
          ) : (
            '-'
          )
        }
      },
      {
        accessorKey: 'tenantId',
        enableSorting: false,
        header: 'Tenant',
        size: 240,
        Cell: ({ row }) => (
          <TenantDisplay
            tenantId={row.original.tenantId}
            tenantName={row.original.tenantName}
          />
        )
      },
      {
        accessorKey: 'credits',
        enableSorting: true,
        header: 'Credits',
        size: 130,
        Cell: ({ cell }) => <CreditsValue value={cell.getValue<number>()} />,
        mantineTableBodyCellProps: { align: 'right' },
        mantineTableHeadCellProps: { align: 'right' }
      },
      {
        accessorKey: 'department',
        enableSorting: false,
        header: 'Department',
        size: 120
      },
      {
        accessorKey: 'applicant',
        enableSorting: false,
        header: 'Applicant',
        size: 220
      },
      {
        accessorKey: 'approvers',
        enableSorting: false,
        header: 'Approvers',
        size: 240,
        Cell: ({ row }) => {
          if (!row.original.approval_id) {
            return '-'
          }
          if (row.original.approvers === undefined) {
            return approversLoading ? <Loader size="xs" /> : '-'
          }
          if (row.original.approvers.length === 0) {
            return '-'
          }

          const approvers = row.original.approvers.join(', ')
          return (
            <Typography lineClamp={2} title={approvers}>
              {approvers}
            </Typography>
          )
        }
      },
      {
        accessorKey: 'phase',
        enableSorting: false,
        header: 'Phase',
        size: 110,
        Cell: ({ cell }) => (
          <PhaseBadge phase={cell.getValue<OperationInstancePhase>()} />
        )
      },
      {
        accessorKey: 'created_at',
        enableSorting: false,
        header: 'Created At (UTC)',
        size: 170,
        Cell: ({ cell }) => formatCreatedAt(cell.getValue<number | undefined>())
      },
      {
        accessorKey: 'reason',
        enableSorting: false,
        header: 'Reason',
        size: 240,
        Cell: ({ cell }) => {
          const reason = cell.getValue<string | undefined>()
          return (
            <Typography lineClamp={1} title={reason}>
              {reason || '-'}
            </Typography>
          )
        }
      }
    ],
    [approversLoading]
  )

  const departmentColumns = useMemo<MRT_ColumnDef<DepartmentSummary>[]>(
    () => [
      {
        accessorKey: 'department',
        header: 'Department'
      },
      {
        accessorKey: 'requests',
        header: 'Requests',
        mantineTableBodyCellProps: { align: 'right' },
        mantineTableHeadCellProps: { align: 'right' }
      },
      {
        accessorKey: 'succeeded',
        header: 'Succeeded',
        mantineTableBodyCellProps: { align: 'right' },
        mantineTableHeadCellProps: { align: 'right' }
      },
      {
        accessorKey: 'credits',
        header: 'Requested Credits',
        Cell: ({ cell }) => <CreditsValue value={cell.getValue<number>()} />,
        mantineTableBodyCellProps: { align: 'right' },
        mantineTableHeadCellProps: { align: 'right' }
      },
      {
        accessorKey: 'grantedCredits',
        header: 'Granted Credits',
        Cell: ({ cell }) => <CreditsValue value={cell.getValue<number>()} />,
        mantineTableBodyCellProps: { align: 'right' },
        mantineTableHeadCellProps: { align: 'right' }
      }
    ],
    []
  )

  const tenantColumns = useMemo<MRT_ColumnDef<TenantSummary>[]>(
    () => [
      {
        accessorKey: 'tenantId',
        header: 'Tenant',
        Cell: ({ row }) => (
          <TenantDisplay
            tenantId={row.original.tenantId}
            tenantName={row.original.tenantName}
          />
        )
      },
      {
        accessorKey: 'credits',
        header: 'Requested Credits',
        Cell: ({ cell }) => <CreditsValue value={cell.getValue<number>()} />,
        mantineTableBodyCellProps: { align: 'right' },
        mantineTableHeadCellProps: { align: 'right' }
      },
      {
        accessorKey: 'grantedCredits',
        header: 'Granted Credits',
        Cell: ({ cell }) => <CreditsValue value={cell.getValue<number>()} />,
        mantineTableBodyCellProps: { align: 'right' },
        mantineTableHeadCellProps: { align: 'right' }
      }
    ],
    []
  )

  return (
    <Stack gap="lg">
      <Group justify="space-between" align="flex-end" wrap="wrap">
        <Group align="flex-start" wrap="nowrap">
          <Button
            aria-label="Back to operations"
            component={Link}
            to="/operations"
            variant="subtle"
          >
            <IconArrowLeft size={18} />
          </Button>
          <Stack gap={2}>
            <Typography variant="headline-lg">
              Tenant Credits Monthly Report
            </Typography>
            <Typography c="dimmed">
              Statistics for {OPERATION}. Month range boundaries use UTC and may
              include up to 12 months.
            </Typography>
          </Stack>
        </Group>

        <Group align="flex-end">
          <MonthPickerControl
            label="Start Month"
            value={startMonth}
            onChange={handleStartMonthChange}
          />
          <MonthPickerControl
            label="End Month"
            value={endMonth}
            onChange={handleEndMonthChange}
          />
          <Button
            leftSection={<IconRefreshCw01 size={16} />}
            loading={loading}
            onClick={loadData}
            variant="default"
          >
            Reload
          </Button>
        </Group>
      </Group>

      {error && (
        <Alert color="red" title={error}>
          Please retry or select another month range.
        </Alert>
      )}

      <SimpleGrid cols={{ base: 1, sm: 2, xl: 4 }} spacing="md">
        <MetricCard label="Requests" value={summary.requests} />
        <MetricCard label="Succeeded" value={summary.succeeded} />
        <MetricCard credits label="Requested Credits" value={summary.credits} />
        <MetricCard
          credits
          label="Granted Credits"
          value={summary.grantedCredits}
        />
      </SimpleGrid>

      <Card p="lg" shadow="xs" withBorder>
        <Stack gap="md">
          <Typography variant="headline-sm">Credits by Department</Typography>
          <ProTable<DepartmentSummary>
            {...tableCommonProps}
            columns={departmentColumns}
            data={departmentSummary}
            enableBottomToolbar={false}
            enablePagination={false}
            getRowId={(row) => row.department}
            loading={loading}
          />
        </Stack>
      </Card>

      <Card p="lg" shadow="xs" withBorder>
        <Stack gap="md">
          <Typography variant="headline-sm">Credits by Tenant</Typography>
          <ProTable<TenantSummary>
            {...tableCommonProps}
            columns={tenantColumns}
            data={tenantSummary}
            enablePagination
            getRowId={(row) => row.tenantId}
            initialState={{
              pagination: { pageIndex: 0, pageSize: 10 }
            }}
            loading={loading}
            pagination={{
              rowsPerPageOptions: ['10'],
              showRowsPerPage: false,
              showTotal: true
            }}
            rowCount={tenantSummary.length}
          />
        </Stack>
      </Card>

      <Card p="lg" shadow="xs" withBorder>
        <Stack gap="md">
          <Typography variant="headline-sm">Operation Details</Typography>
          <ProTable<AddCreditsRow>
            {...tableCommonProps}
            columns={detailColumns}
            data={rows}
            enablePagination
            enableSorting
            getRowId={(row, index) =>
              String(row.id || `${row.tenantId}-${row.created_at}-${index}`)
            }
            initialState={{
              pagination: { pageIndex: 0, pageSize: 20 }
            }}
            loading={loading}
            pagination={{
              rowsPerPageOptions: ['20'],
              showRowsPerPage: false,
              showTotal: true
            }}
            rowCount={rows.length}
          />
        </Stack>
      </Card>
    </Stack>
  )
}
