import { useQuery } from "@tanstack/react-query";
import type { AxiosError } from "axios";
import {
  Activity,
  AlertTriangle,
  BarChart3,
  CheckCircle2,
  Layers3,
  ShieldCheck,
} from "lucide-react";
import { useMemo, useState } from "react";
import { useAuth } from "react-oidc-context";
import { useNavigate } from "react-router-dom";
import {
  type ClientSummary,
  type RPUsageDailyMetric,
  type RPUsagePeriod,
  fetchClients,
  fetchDevRPUsageDaily,
  fetchDevStats,
  fetchDeveloperRequestStatus,
} from "../../lib/devApi";
import { t } from "../../lib/i18n";
import { resolveProfileRole } from "../../lib/role";
import {
  OverviewAxisNotes,
  OverviewMetric,
  OverviewSelectionChips,
} from "../../../../common/core/components/overview";

type ClientDistribution = {
  activeClients: number;
  headlessClients: number;
  pkceClients: number;
  privateClients: number;
};

type DailyPoint = {
  date: string;
  loginRequests: number;
  otherRequests: number;
};

type SeriesSummary = {
  key: string;
  clientLabel: string;
  loginRequests: number;
  otherRequests: number;
  uniqueSubjects: number;
};

type MultiLineSeries = {
  key: string;
  clientLabel: string;
  color: UsageChartPalette;
  points: DailyPoint[];
};

type ClientFilterOption = {
  id: string;
  label: string;
};

type UsageChartPalette = {
  bar: string;
  line: string;
  point: string;
};

const usageChartPalettes: UsageChartPalette[] = [
  { bar: "#7dd3fc", line: "#10b981", point: "#059669" },
  { bar: "#f9a8d4", line: "#f97316", point: "#ea580c" },
  { bar: "#c4b5fd", line: "#6366f1", point: "#4f46e5" },
  { bar: "#86efac", line: "#14b8a6", point: "#0f766e" },
  { bar: "#fdba74", line: "#ef4444", point: "#dc2626" },
  { bar: "#93c5fd", line: "#8b5cf6", point: "#7c3aed" },
];

function buildClientDistribution(clients: ClientSummary[]): ClientDistribution {
  return clients.reduce<ClientDistribution>(
    (summary, client) => {
      if (client.status === "active") {
        summary.activeClients += 1;
      }

      if (client.metadata?.headless_login_enabled === true) {
        summary.headlessClients += 1;
      }

      if (client.type === "pkce") {
        summary.pkceClients += 1;
      } else {
        summary.privateClients += 1;
      }

      return summary;
    },
    {
      activeClients: 0,
      headlessClients: 0,
      pkceClients: 0,
      privateClients: 0,
    },
  );
}

function summarizeDaily(rows: RPUsageDailyMetric[]): DailyPoint[] {
  const byDate = new Map<string, DailyPoint>();
  for (const row of rows) {
    const current =
      byDate.get(row.date) ??
      ({
        date: row.date,
        loginRequests: 0,
        otherRequests: 0,
      } satisfies DailyPoint);
    current.loginRequests += row.loginRequests;
    current.otherRequests += row.otherRequests;
    byDate.set(row.date, current);
  }
  return Array.from(byDate.values()).sort((left, right) =>
    left.date.localeCompare(right.date),
  );
}

function summarizeSeries(rows: RPUsageDailyMetric[]): SeriesSummary[] {
  const bySeries = new Map<string, SeriesSummary>();
  for (const row of rows) {
    const key = row.clientId;
    const current =
      bySeries.get(key) ??
      ({
        key,
        clientLabel: row.clientName || row.clientId,
        loginRequests: 0,
        otherRequests: 0,
        uniqueSubjects: 0,
      } satisfies SeriesSummary);
    current.loginRequests += row.loginRequests;
    current.otherRequests += row.otherRequests;
    current.uniqueSubjects = Math.max(
      current.uniqueSubjects,
      row.uniqueSubjects,
    );
    bySeries.set(key, current);
  }
  return Array.from(bySeries.values()).sort(
    (left, right) =>
      right.loginRequests +
      right.otherRequests -
      (left.loginRequests + left.otherRequests),
  );
}

function buildMultiLineSeries(rows: RPUsageDailyMetric[]): MultiLineSeries[] {
  const dates = summarizeDaily(rows).map((point) => point.date);
  const byClient = new Map<
    string,
    {
      clientLabel: string;
      byDate: Map<string, DailyPoint>;
    }
  >();

  for (const row of rows) {
    const current = byClient.get(row.clientId) ?? {
      clientLabel: row.clientName || row.clientId,
      byDate: new Map<string, DailyPoint>(),
    };
    const point =
      current.byDate.get(row.date) ??
      ({
        date: row.date,
        loginRequests: 0,
        otherRequests: 0,
      } satisfies DailyPoint);
    point.loginRequests += row.loginRequests;
    point.otherRequests += row.otherRequests;
    current.byDate.set(row.date, point);
    byClient.set(row.clientId, current);
  }

  return Array.from(byClient.entries())
    .sort((left, right) =>
      left[1].clientLabel.localeCompare(right[1].clientLabel),
    )
    .map(([clientId, entry], index) => ({
      key: clientId,
      clientLabel: entry.clientLabel,
      color: usageChartPalettes[index % usageChartPalettes.length],
      points: dates.map(
        (date) =>
          entry.byDate.get(date) ??
          ({
            date,
            loginRequests: 0,
            otherRequests: 0,
          } satisfies DailyPoint),
      ),
    }));
}

function parseDateParts(date: string) {
  const parts = date.split("-");
  if (parts.length === 3) {
    return {
      year: Number(parts[0]),
      month: Number(parts[1]),
      day: Number(parts[2]),
      monthText: parts[1],
      dayText: parts[2],
    };
  }
  return null;
}

function getISOWeekNumber(year: number, month: number, day: number) {
  const date = new Date(Date.UTC(year, month - 1, day));
  const dayOfWeek = date.getUTCDay() || 7;
  date.setUTCDate(date.getUTCDate() + 4 - dayOfWeek);
  const yearStart = new Date(Date.UTC(date.getUTCFullYear(), 0, 1));
  return Math.ceil(((date.getTime() - yearStart.getTime()) / 86400000 + 1) / 7);
}

function getISOWeekThursday(year: number, month: number, day: number) {
  const date = new Date(Date.UTC(year, month - 1, day));
  const dayOfWeek = date.getUTCDay() || 7;
  date.setUTCDate(date.getUTCDate() + 4 - dayOfWeek);
  return date;
}

function formatDate(value?: string) {
  if (!value) {
    return "-";
  }
  const parsed = new Date(value);
  if (Number.isNaN(parsed.getTime())) {
    return value;
  }
  return parsed.toLocaleDateString();
}

function formatPeriodLabel(date: string, period: RPUsagePeriod) {
  const parts = parseDateParts(date);
  if (!parts) {
    return date;
  }
  if (period === "month") {
    return `${parts.monthText}월`;
  }
  if (period === "week") {
    const weekNumber = String(
      getISOWeekNumber(parts.year, parts.month, parts.day),
    ).padStart(2, "0");
    const weekThursday = getISOWeekThursday(parts.year, parts.month, parts.day);
    const weekMonth = weekThursday.getUTCMonth() + 1;
    const weekDay = weekThursday.getUTCDate();
    const weekMonthText = String(weekMonth).padStart(2, "0");
    const weekOfMonth = Math.min(5, Math.max(1, Math.ceil(weekDay / 7)));
    return `${weekNumber}(${weekMonthText}월${weekOfMonth}주)`;
  }
  return `${parts.monthText}.${parts.dayText}`;
}

function formatMetric(value: number | undefined) {
  return value === undefined ? "-" : value.toLocaleString();
}

function RPUsageMixedChart({
  period,
  rows,
  palette,
  multiLineSeries,
}: {
  period: RPUsagePeriod;
  rows: RPUsageDailyMetric[];
  palette?: UsageChartPalette;
  multiLineSeries?: MultiLineSeries[];
}) {
  const colors = palette ?? usageChartPalettes[0];
  const daily = summarizeDaily(rows);
  const series = summarizeSeries(rows);
  const topSeries = series.slice(0, 5);
  const seriesByKey = new Map(series.map((item) => [item.key, item]));
  const chartWidth = 720;
  const chartHeight = 230;
  const padX = 48;
  const padTop = 40;
  const padBottom = 34;
  const innerWidth = chartWidth - padX * 2;
  const innerHeight = chartHeight - padTop - padBottom;
  const maxValue = Math.max(1, ...daily.map((point) => point.loginRequests));
  const slot = daily.length > 0 ? innerWidth / daily.length : innerWidth;
  const y = (value: number) =>
    padTop + innerHeight - (value / maxValue) * innerHeight;
  const x = (index: number) => padX + slot * index + slot / 2;
  const linePoints = daily
    .map((point, index) => `${x(index)},${y(point.loginRequests)}`)
    .join(" ");
  const multiLinePoints = multiLineSeries?.map((seriesItem) => ({
    ...seriesItem,
    pointsAttr: seriesItem.points
      .map((point, index) => `${x(index)},${y(point.loginRequests)}`)
      .join(" "),
  }));

  if (daily.length === 0) {
    return (
      <div className="flex min-h-[210px] items-center justify-center text-sm text-muted-foreground">
        {t("msg.dev.dashboard.chart.empty", "표시할 RP 이용 집계가 없습니다.")}
      </div>
    );
  }

  return (
    <div className="space-y-3">
      <div className="overflow-x-auto">
        <svg
          role="img"
          aria-label={t("ui.dev.dashboard.chart.aria", "RP 요청 현황")}
          viewBox={`0 0 ${chartWidth} ${chartHeight}`}
          className="h-[235px] min-w-[720px] w-full"
        >
          <title>{t("ui.dev.dashboard.chart.aria", "RP 요청 현황")}</title>
          {[0, 0.25, 0.5, 0.75, 1].map((ratio) => {
            const gridY = padTop + innerHeight * ratio;
            const label = Math.round(maxValue * (1 - ratio));
            return (
              <g key={ratio}>
                <line
                  x1={padX}
                  x2={chartWidth - padX}
                  y1={gridY}
                  y2={gridY}
                  stroke="currentColor"
                  className="text-border"
                  strokeWidth="1"
                />
                <text
                  x={padX - 12}
                  y={gridY + 4}
                  textAnchor="end"
                  className="fill-muted-foreground text-[11px]"
                >
                  {label}
                </text>
              </g>
            );
          })}
          {daily.map((point, index) => {
            const center = x(index);
            return (
              <g key={point.date}>
                <text
                  x={center}
                  y={chartHeight - 12}
                  textAnchor="middle"
                  className="fill-muted-foreground text-[11px]"
                >
                  {formatPeriodLabel(point.date, period)}
                </text>
              </g>
            );
          })}
          {!multiLinePoints || multiLinePoints.length === 0 ? (
            <>
              <polyline
                points={linePoints}
                fill="none"
                stroke={colors.line}
                strokeWidth="3"
                strokeLinecap="round"
                strokeLinejoin="round"
              />
              {daily.map((point, index) => (
                <circle
                  key={`${point.date}-login`}
                  cx={x(index)}
                  cy={y(point.loginRequests)}
                  r="4"
                  fill={colors.point}
                  stroke="hsl(var(--background))"
                  strokeWidth="2"
                />
              ))}
            </>
          ) : (
            multiLinePoints.map((seriesItem) => (
              <g key={seriesItem.key}>
                <polyline
                  points={seriesItem.pointsAttr}
                  fill="none"
                  stroke={seriesItem.color.line}
                  strokeWidth="3"
                  strokeLinecap="round"
                  strokeLinejoin="round"
                />
                {seriesItem.points.map((point, index) => (
                  <circle
                    key={`${seriesItem.key}-${point.date}`}
                    cx={x(index)}
                    cy={y(point.loginRequests)}
                    r="3.5"
                    fill={seriesItem.color.point}
                    stroke="hsl(var(--background))"
                    strokeWidth="2"
                  />
                ))}
              </g>
            ))
          )}
        </svg>
      </div>

      <OverviewAxisNotes
        xAxisLabel={t("ui.common.chart.axis.x", "X축: 기간")}
        yAxisLabel={t("ui.common.chart.axis.y", "Y축: 로그인 요청 수")}
      />

      {multiLinePoints && multiLinePoints.length > 0 ? (
        <div className="grid gap-x-6 gap-y-2 border-t border-border/60 pt-2 text-xs md:grid-cols-2 xl:grid-cols-3">
          {multiLinePoints.map((item) => {
            const seriesItem = seriesByKey.get(item.key);
            return (
              <div
                key={item.key}
                className="flex min-w-0 flex-wrap items-center gap-x-3 gap-y-1"
              >
                <span
                  className="h-2.5 w-2.5 rounded-full"
                  style={{ backgroundColor: item.color.line }}
                />
                <span className="font-medium">{item.clientLabel}</span>
                {seriesItem ? (
                  <span className="whitespace-nowrap tabular-nums text-muted-foreground">
                    {t(
                      "ui.dev.dashboard.chart.series",
                      "로그인 {{login}} / 사용자 {{subjects}}",
                      {
                        login: seriesItem.loginRequests.toLocaleString(),
                        subjects: seriesItem.uniqueSubjects.toLocaleString(),
                      },
                    )}
                  </span>
                ) : null}
              </div>
            );
          })}
        </div>
      ) : topSeries.length > 0 ? (
        <div className="grid gap-x-6 gap-y-2 border-t border-border/60 pt-2 text-xs md:grid-cols-2 xl:grid-cols-3">
          {topSeries.map((item) => (
            <div
              key={item.key}
              className="flex min-w-0 flex-wrap items-center gap-x-3 gap-y-1"
            >
              <span className="font-medium">{item.clientLabel}</span>
              <span className="whitespace-nowrap tabular-nums text-muted-foreground">
                {t(
                  "ui.dev.dashboard.chart.series",
                  "로그인 {{login}} / 사용자 {{subjects}}",
                  {
                    login: item.loginRequests.toLocaleString(),
                    subjects: item.uniqueSubjects.toLocaleString(),
                  },
                )}
              </span>
            </div>
          ))}
        </div>
      ) : null}
    </div>
  );
}

function GlobalOverviewPage() {
  const navigate = useNavigate();
  const auth = useAuth();
  const hasAccessToken = Boolean(auth.user?.access_token);
  const userProfile = auth.user?.profile as Record<string, unknown> | undefined;
  const role = resolveProfileRole(userProfile);
  const tenantId = userProfile?.tenant_id as string | undefined;
  const [period, setPeriod] = useState<RPUsagePeriod>("day");
  const [selectedClientIds, setSelectedClientIds] = useState<string[]>([]);
  const usageDays = period === "day" ? 14 : period === "week" ? 84 : 90;
  const { data: requestStatus, isLoading: isLoadingRequestStatus } = useQuery({
    queryKey: ["developer-request", tenantId],
    queryFn: () => fetchDeveloperRequestStatus(tenantId),
    enabled: hasAccessToken && role === "user",
  });
  const statsQuery = useQuery({
    queryKey: ["dev-dashboard-stats"],
    queryFn: fetchDevStats,
    retry: false,
  });
  const clientsQuery = useQuery({
    queryKey: ["dev-dashboard-clients"],
    queryFn: fetchClients,
    retry: false,
  });
  const usageQuery = useQuery({
    queryKey: ["dev-dashboard-rp-usage", usageDays, period],
    queryFn: () =>
      fetchDevRPUsageDaily({
        days: usageDays,
        period,
      }),
    retry: false,
  });

  const clients = clientsQuery.data?.items ?? [];
  const hasDeveloperAccess =
    role === "super_admin" ||
    role === "tenant_admin" ||
    role === "rp_admin" ||
    requestStatus?.status === "approved";
  const isDeveloperRequestPending = requestStatus?.status === "pending";
  const canRequestDeveloperAccess =
    (role === "user" || role === "tenant_member") &&
    !isLoadingRequestStatus &&
    !hasDeveloperAccess &&
    !isDeveloperRequestPending;
  const distribution = useMemo(
    () => buildClientDistribution(clients),
    [clients],
  );
  const visibleClients = useMemo(
    () =>
      [...clients]
        .sort((left, right) => {
          const statusCompare = (left.status || "").localeCompare(
            right.status || "",
          );
          if (statusCompare !== 0) {
            return statusCompare;
          }
          return (left.name || left.id).localeCompare(right.name || right.id);
        })
        .slice(0, 6),
    [clients],
  );
  const clientFilterOptions = useMemo<ClientFilterOption[]>(
    () =>
      [...clients]
        .map((client) => ({
          id: client.id,
          label: client.name || client.id,
        }))
        .sort((left, right) => left.label.localeCompare(right.label)),
    [clients],
  );
  const stats = statsQuery.data;
  const usageRows = usageQuery.data?.items ?? [];
  const filteredUsageRows = useMemo(() => {
    if (selectedClientIds.length === 0) {
      return usageRows;
    }
    const selectedSet = new Set(selectedClientIds);
    return usageRows.filter((row) => selectedSet.has(row.clientId));
  }, [selectedClientIds, usageRows]);
  const selectedMultiLineSeries = useMemo(
    () => buildMultiLineSeries(filteredUsageRows),
    [filteredUsageRows],
  );
  const usageError = usageQuery.error as AxiosError<{ error?: string }> | null;
  const usageStatus = usageError?.response?.status;
  const usageErrorMessage =
    usageError?.response?.data?.error ?? usageError?.message ?? "";
  const usageErrorText =
    usageStatus === 403
      ? t(
          "msg.dev.dashboard.chart.forbidden",
          "현재 계정에는 RP 이용 통계를 볼 권한이 없습니다.",
        )
      : usageStatus === 503
        ? t(
            "msg.dev.dashboard.chart.service_unavailable",
            "RP 이용 통계 집계 서비스가 아직 준비되지 않았습니다.",
          )
        : usageStatus === 500
          ? t(
              "msg.dev.dashboard.chart.server_error",
              "RP 이용 통계 조회 중 서버 오류가 발생했습니다.",
            )
          : t(
              "msg.dev.dashboard.chart.unavailable_with_reason",
              "RP 이용 통계 API 응답을 확인할 수 없습니다. {{reason}}",
              {
                reason:
                  usageErrorMessage ||
                  t("err.common.unknown", "알 수 없는 오류"),
              },
            );
  const isAllClientsSelected = selectedClientIds.length === 0;

  const toggleClientSelection = (clientId: string) => {
    setSelectedClientIds((current) => {
      if (current.includes(clientId)) {
        const next = current.filter((item) => item !== clientId);
        return next;
      }
      return [...current, clientId];
    });
  };

  const selectAllClients = () => {
    setSelectedClientIds([]);
  };

  if ((role === "user" || role === "tenant_member") && isLoadingRequestStatus) {
    return (
      <div className="p-8 text-center">
        {t("ui.common.loading", "Loading...")}
      </div>
    );
  }

  if (!hasDeveloperAccess) {
    return (
      <div className="rounded-xl border border-border/60 bg-card p-8 text-center">
        <div className="space-y-3">
          <h2 className="text-2xl font-semibold tracking-tight">
            {t("ui.common.overview.title", "운영 현황")}
          </h2>
          <p className="font-medium text-foreground">
            {isDeveloperRequestPending
              ? t(
                  "msg.dev.dashboard.access_pending",
                  "개발자 권한 신청을 검토 중입니다.",
                )
              : t(
                  "msg.dev.dashboard.access_denied",
                  "대시보드는 개발자 권한이 있어야 볼 수 있습니다.",
                )}
          </p>
          <p className="text-sm text-muted-foreground">
            {isDeveloperRequestPending
              ? t(
                  "msg.dev.dashboard.access_pending_detail",
                  "super admin이 승인하면 개요와 개발자 기능을 사용할 수 있습니다.",
                )
              : t(
                  "msg.dev.dashboard.access_denied_detail",
                  "개발자 권한 신청 페이지에서 신청을 등록한 뒤 승인을 받아주세요.",
                )}
          </p>
          {(isDeveloperRequestPending || canRequestDeveloperAccess) && (
            <button
              type="button"
              className="font-bold text-primary hover:underline"
              onClick={() => navigate("/developer-requests")}
            >
              {isDeveloperRequestPending
                ? t("ui.dev.nav.developer_request", "개발자 권한 신청")
                : t("ui.dev.welcome.btn_request", "개발자 등록 신청하기")}
            </button>
          )}
        </div>
      </div>
    );
  }

  return (
    <div className="space-y-4 animate-in fade-in duration-500">
      <div className="flex flex-wrap items-end justify-between gap-4">
        <div className="space-y-1">
          <h2 className="text-2xl font-semibold tracking-tight">
            {t("ui.common.overview.title", "운영 현황")}
          </h2>
          <p className="text-sm text-muted-foreground">
            {t(
              "msg.dev.dashboard.description",
              "연동 앱 구성과 인증 운영 지표를 한 곳에서 확인합니다.",
            )}
          </p>
        </div>
      </div>

      <div className="flex flex-wrap items-center gap-x-6 gap-y-2 border-y border-border/60 py-2">
        <OverviewMetric
          icon={<ShieldCheck size={14} />}
          label={t("ui.dev.dashboard.summary.total_clients", "총 RP 수")}
          value={formatMetric(stats?.total_clients ?? clients.length)}
        />
        <OverviewMetric
          icon={<CheckCircle2 size={14} />}
          label={t("ui.dev.dashboard.summary.active_clients", "활성 RP 수")}
          value={formatMetric(distribution.activeClients)}
        />
        <OverviewMetric
          icon={<Activity size={14} />}
          label={t("ui.dev.dashboard.summary.active_sessions", "활성 세션 수")}
          value={formatMetric(stats?.active_sessions)}
        />
        <OverviewMetric
          icon={<AlertTriangle size={14} />}
          label={t(
            "ui.dev.dashboard.summary.auth_failures_24h",
            "24시간 인증 실패 수",
          )}
          value={formatMetric(stats?.auth_failures_24h)}
        />
      </div>

      <section className="space-y-3">
        <div className="flex flex-wrap items-center justify-between gap-3">
          <div className="flex items-center gap-2">
            <BarChart3 size={18} className="text-primary" />
            <div className="space-y-1">
              <h3 className="text-base font-semibold">
                {t(
                  "ui.dev.dashboard.chart.title",
                  "애플리케이션별 로그인요청/기타 요청 현황",
                )}
              </h3>
              <p className="text-sm text-muted-foreground">
                {t(
                  "msg.dev.dashboard.chart.filter_description",
                  "전체 또는 선택한 애플리케이션만 기준으로 그래프를 확인합니다.",
                )}
              </p>
            </div>
          </div>
          <div className="flex h-8 items-center gap-1" aria-label="집계 단위">
            {[
              ["day", t("ui.common.chart.period.day", "일")],
              ["week", t("ui.common.chart.period.week", "주")],
              ["month", t("ui.common.chart.period.month", "월")],
            ].map(([value, label]) => (
              <button
                key={value}
                type="button"
                aria-pressed={period === value}
                onClick={() => setPeriod(value as RPUsagePeriod)}
                className={`h-8 rounded px-3 text-xs font-medium transition-colors ${
                  period === value
                    ? "bg-primary text-primary-foreground"
                    : "bg-muted/60 hover:bg-muted"
                }`}
              >
                {label}
              </button>
            ))}
          </div>
        </div>

        <OverviewSelectionChips
          allLabel={t("ui.dev.dashboard.chart.filter_all", "전체")}
          options={clientFilterOptions}
          selectedIds={selectedClientIds}
          onSelectAll={selectAllClients}
          onToggle={toggleClientSelection}
        />

        {usageQuery.isError ? (
          <div className="text-sm text-muted-foreground">{usageErrorText}</div>
        ) : isAllClientsSelected ? (
          <RPUsageMixedChart rows={filteredUsageRows} period={period} />
        ) : (
          <RPUsageMixedChart
            rows={filteredUsageRows}
            period={period}
            multiLineSeries={selectedMultiLineSeries}
          />
        )}
      </section>

      <div className="grid gap-4 lg:grid-cols-[0.9fr,1.1fr]">
        <section className="rounded-xl border border-border/60 bg-card p-6">
          <div className="flex items-center gap-2">
            <Layers3 size={18} className="text-primary" />
            <h3 className="text-base font-semibold">
              {t(
                "ui.dev.dashboard.distribution.title",
                "애플리케이션 구성 요약",
              )}
            </h3>
          </div>
          <p className="mt-1 text-sm text-muted-foreground">
            {t(
              "msg.dev.dashboard.distribution.description",
              "애플리케이션 유형 분포와 server side app의 headless login 사용 현황을 빠르게 확인합니다.",
            )}
          </p>
          <div className="mt-4 grid gap-3 sm:grid-cols-2">
            <div className="rounded-xl border border-border/60 bg-secondary/30 p-4">
              <p className="text-sm text-muted-foreground">
                {t("ui.dev.dashboard.distribution.private", "Server side App")}
              </p>
              <p className="mt-2 text-2xl font-semibold tabular-nums">
                {distribution.privateClients.toLocaleString()}
              </p>
              <p className="mt-1 text-xs text-muted-foreground">
                {t(
                  "ui.dev.dashboard.distribution.headless_hint",
                  "이 중 Headless Login 사용 {{count}}",
                  {
                    count: distribution.headlessClients.toLocaleString(),
                  },
                )}
              </p>
            </div>
            <div className="rounded-xl border border-border/60 bg-secondary/30 p-4">
              <p className="text-sm text-muted-foreground">
                {t("ui.dev.dashboard.distribution.pkce", "PKCE")}
              </p>
              <p className="mt-2 text-2xl font-semibold tabular-nums">
                {distribution.pkceClients.toLocaleString()}
              </p>
            </div>
          </div>
        </section>

        <section className="rounded-xl border border-border/60 bg-card p-6">
          <div className="flex items-center gap-2">
            <Layers3 size={18} className="text-primary" />
            <h3 className="text-base font-semibold">
              {t("ui.dev.dashboard.recent.title", "내 애플리케이션")}
            </h3>
          </div>
          <p className="mt-1 text-sm text-muted-foreground">
            {t(
              "msg.dev.dashboard.recent.empty",
              "현재 계정이 접근할 수 있는 RP를 확인합니다.",
            )}
          </p>
          <div className="mt-4 space-y-2">
            {visibleClients.length === 0 ? (
              <p className="text-sm text-muted-foreground">
                {t(
                  "msg.dev.dashboard.recent.none",
                  "표시할 연동 앱이 없습니다.",
                )}
              </p>
            ) : (
              visibleClients.map((client) => (
                <div
                  key={client.id}
                  className="flex items-center justify-between gap-3 rounded-lg border border-border/40 px-3 py-2"
                >
                  <div className="min-w-0">
                    <p className="truncate font-semibold">
                      {client.name || t("ui.dev.clients.untitled", "Untitled")}
                    </p>
                    <p className="truncate text-xs text-muted-foreground">
                      {client.id}
                    </p>
                  </div>
                  <div className="text-right text-xs text-muted-foreground">
                    <p>
                      {client.metadata?.headless_login_enabled === true
                        ? t(
                            "ui.dev.clients.type.private_headless",
                            "Server side App (Headless Login)",
                          )
                        : client.type === "private"
                          ? t("ui.dev.clients.type.private", "Server side App")
                          : t("ui.dev.clients.type.pkce", "PKCE")}
                    </p>
                    <p>
                      {client.status === "active"
                        ? t("ui.dev.clients.status.active", "활성")
                        : client.status === "inactive"
                          ? t("ui.dev.clients.status.inactive", "비활성")
                          : client.status || "-"}
                    </p>
                    <p>
                      {t("ui.dev.clients.table.created_at", "생성일")}{" "}
                      {formatDate(client.createdAt)}
                    </p>
                  </div>
                </div>
              ))
            )}
          </div>
        </section>
      </div>
    </div>
  );
}

export default GlobalOverviewPage;
