"use client";

export const dynamic = "force-dynamic";

import { type KeyboardEvent, type MouseEvent, useMemo } from "react";
import { useRouter } from "next/navigation";
import { useQuery } from "@tanstack/react-query";

import { SignedIn, SignedOut, useAuth } from "@/auth/clerk";
import { Activity, Bot, LayoutGrid, Timer } from "lucide-react";

import { DashboardSidebar } from "@/components/organisms/DashboardSidebar";
import { DashboardShell } from "@/components/templates/DashboardShell";
import { SignedOutPanel } from "@/components/auth/SignedOutPanel";
import { ForgejoIssueMetricCards } from "@/components/git/ForgejoIssueMetricCards";
import { ForgejoHeatmap } from "@/components/git/ForgejoHeatmap";
import {
  DashboardMetricCard,
  DashboardInfoBlock,
  DashboardEmptyState,
  PendingApprovalsSection,
  SessionsSection,
  RecentActivitySection,
} from "@/components/dashboard";
import { ApiError } from "@/api/mutator";
import {
  type dashboardMetricsApiV1MetricsDashboardGetResponse,
  useDashboardMetricsApiV1MetricsDashboardGet,
} from "@/api/generated/metrics/metrics";
import {
  gatewaysStatusApiV1GatewaysStatusGet,
  getGatewayRuntimeUsageApiV1GatewaysGatewayIdRuntimeUsageGet,
} from "@/api/generated/gateways/gateways";
import type { GatewaysStatusResponse } from "@/api/generated/model/gatewaysStatusResponse";
import type { CronStatusResponse, RuntimeUsageResponse, SystemHealthResponse } from "@/api/generated/model";
import {
  getGatewayCronApiV1GatewaysGatewayIdCronGet,
  getGatewayHealthApiV1GatewaysGatewayIdHealthGet,
} from "@/api/generated/gateways/gateways";
import {
  RuntimeUsageSection,
  aggregateRuntimeUsage,
  type AggregatedRuntimeUsage,
} from "@/components/dashboard/RuntimeUsageSection";
import { GatewayHealthPanel } from "@/components/dashboard/GatewayHealthPanel";
import { GatewayCronPanel } from "@/components/dashboard/GatewayCronPanel";
import {
  type listAgentsApiV1AgentsGetResponse,
  useListAgentsApiV1AgentsGet,
} from "@/api/generated/agents/agents";
import {
  type listBoardsApiV1BoardsGetResponse,
  useListBoardsApiV1BoardsGet,
} from "@/api/generated/boards/boards";
import {
  type listActivityApiV1ActivityGetResponse,
  useListActivityApiV1ActivityGet,
} from "@/api/generated/activity/activity";
import type { ActivityEventRead } from "@/api/generated/model";
import {
  getForgejoHeatmap,
  getForgejoMetrics,
  getForgejoRepositories,
  type ForgejoHeatmapDay,
  type ForgejoIssueMetrics,
  type ForgejoRepository,
} from "@/lib/api-forgejo";
import {
  formatRelativeTimestamp,
  formatTimestamp,
  parseTimestamp,
} from "@/lib/formatters";

type SessionSummary = {
  key: string;
  title: string;
  subtitle: string;
  usage: string;
  lastSeenAt: string | null;
  isMain: boolean;
};

type SummaryRow = {
  label: string;
  value: string;
  tone?: "default" | "success" | "warning" | "danger";
};

type GatewayTarget = {
  gatewayId: string;
  boardId: string;
  boardName: string;
};

type GatewaySnapshot = GatewayTarget & {
  connected: boolean;
  gatewayUrl: string | null;
  sessionsCount: number;
  sessions: unknown[];
  mainSession: unknown | null;
  mainSessionError: string | null;
  error: string | null;
  requestError: string | null;
};

const DASH = "—";
const DASHBOARD_RANGE = "7d";
const DASHBOARD_RANGE_DAYS = 7;
const DASHBOARD_RANGE_LABEL = "7 days";

const numberFormatter = new Intl.NumberFormat("en-US");
const SESSION_ID_KEYS = ["key", "id", "session_key", "sessionKey", "sessionId"];

const toRecord = (value: unknown): Record<string, unknown> | null => {
  if (!value || Array.isArray(value) || typeof value !== "object") return null;
  return value as Record<string, unknown>;
};

const readString = (
  record: Record<string, unknown> | null,
  keys: string[],
): string | null => {
  if (!record) return null;
  for (const key of keys) {
    const value = record[key];
    if (typeof value === "string" && value.trim()) return value.trim();
  }
  return null;
};

const readNumber = (
  record: Record<string, unknown> | null,
  keys: string[],
): number | null => {
  if (!record) return null;
  for (const key of keys) {
    const value = record[key];
    if (typeof value === "number" && Number.isFinite(value)) return value;
    if (typeof value === "string") {
      const cleaned = value.replace(/[^0-9.-]/g, "");
      const parsed = Number.parseFloat(cleaned);
      if (Number.isFinite(parsed)) return parsed;
    }
  }
  return null;
};

const readStringFromRecords = (
  records: Array<Record<string, unknown> | null>,
  keys: string[],
): string | null => {
  for (const record of records) {
    const value = readString(record, keys);
    if (value) return value;
  }
  return null;
};

const readNumberFromRecords = (
  records: Array<Record<string, unknown> | null>,
  keys: string[],
): number | null => {
  for (const record of records) {
    const value = readNumber(record, keys);
    if (value !== null) return value;
  }
  return null;
};

const normalizeEpochMs = (value: number): number => {
  if (value >= 1_000_000_000_000) return value;
  if (value >= 1_000_000_000) return value * 1000;
  return value;
};

const readTimestamp = (
  record: Record<string, unknown> | null,
  keys: string[],
): string | null => {
  if (!record) return null;
  for (const key of keys) {
    const value = record[key];
    if (typeof value === "number" && Number.isFinite(value)) {
      const date = new Date(normalizeEpochMs(value));
      if (!Number.isNaN(date.getTime())) return date.toISOString();
    }
    if (typeof value === "string") {
      const trimmed = value.trim();
      if (!trimmed) continue;
      const numeric = Number.parseFloat(trimmed);
      if (Number.isFinite(numeric)) {
        const date = new Date(normalizeEpochMs(numeric));
        if (!Number.isNaN(date.getTime())) return date.toISOString();
      }
      const parsed = parseTimestamp(trimmed);
      if (parsed) return parsed.toISOString();
    }
  }
  return null;
};

const readTimestampFromRecords = (
  records: Array<Record<string, unknown> | null>,
  keys: string[],
): string | null => {
  for (const record of records) {
    const value = readTimestamp(record, keys);
    if (value) return value;
  }
  return null;
};

const sessionIdentifiers = (
  record: Record<string, unknown> | null,
): string[] => {
  if (!record) return [];
  const ids = SESSION_ID_KEYS.map((key) => readString(record, [key])).filter(
    Boolean,
  ) as string[];
  return [...new Set(ids)];
};

const sharesSessionIdentity = (left: string[], right: string[]): boolean =>
  left.some((value) => right.includes(value));

const compactNumber = (value: number): string => {
  if (!Number.isFinite(value)) return DASH;
  if (Math.abs(value) >= 1_000_000) {
    return `${(value / 1_000_000).toFixed(1)}m`;
  }
  if (Math.abs(value) >= 1_000) {
    return `${(value / 1_000).toFixed(1)}k`;
  }
  return numberFormatter.format(value);
};

const formatCount = (value: number): string =>
  Number.isFinite(value)
    ? numberFormatter.format(Math.max(0, Math.round(value)))
    : "0";

const formatPercent = (value: number): string =>
  Number.isFinite(value) ? `${value.toFixed(1)}%` : DASH;

const formatPerDay = (total: number, days: number): string => {
  if (!Number.isFinite(total) || !Number.isFinite(days) || days <= 0)
    return DASH;
  return `${(total / days).toFixed(1)}/day`;
};

const formatForgejoDashboardError = (error: Error | null): string | null => {
  if (!error) return null;
  if (error.message === "Failed to fetch") {
    return "Pipeline could not load Git Project data. Check that the frontend can reach the backend API.";
  }
  return error.message;
};

const toSessionSummaries = (
  sessions: unknown[] | null | undefined,
  mainSession: unknown,
): SessionSummary[] => {
  const sessionRecords = (sessions ?? [])
    .map(toRecord)
    .filter(Boolean) as Array<Record<string, unknown>>;
  const mainRecord = toRecord(mainSession);
  const mainIdentifiers = sessionIdentifiers(mainRecord);

  if (mainRecord && mainIdentifiers.length > 0) {
    const exists = sessionRecords.some((entry) =>
      sharesSessionIdentity(sessionIdentifiers(entry), mainIdentifiers),
    );
    if (!exists) sessionRecords.unshift(mainRecord);
  }

  const uniqueRecords: Record<string, unknown>[] = [];
  const seenIdentifiers = new Set<string>();

  for (const entry of sessionRecords) {
    const identifiers = sessionIdentifiers(entry);
    if (
      identifiers.length > 0 &&
      identifiers.some((value) => seenIdentifiers.has(value))
    ) {
      continue;
    }
    uniqueRecords.push(entry);
    identifiers.forEach((value) => seenIdentifiers.add(value));
  }

  return uniqueRecords.map((entry, index) => {
    const usageRecord = toRecord(entry.usage);
    const statsRecord = toRecord(entry.stats);
    const metricsRecord = toRecord(entry.metrics);
    const originRecord = toRecord(entry.origin);
    const candidateRecords = [entry, usageRecord, statsRecord, metricsRecord];

    const identifiers = sessionIdentifiers(entry);
    const key =
      readString(entry, [
        "key",
        "session_key",
        "sessionKey",
        "id",
        "sessionId",
      ]) ?? `session-${index}`;
    const label = readString(entry, ["label", "name", "title"]) ?? key;
    const channel = readStringFromRecords(
      [entry, originRecord],
      ["channel", "source", "kind", "chatType"],
    );
    const model = readString(entry, [
      "model",
      "model_name",
      "provider",
      "engine",
    ]);
    const modelProvider = readString(entry, [
      "modelProvider",
      "model_provider",
      "provider",
    ]);
    const lastSeenAt = readTimestampFromRecords(candidateRecords, [
      "updated_at",
      "updatedAt",
      "last_updated_at",
      "lastUpdatedAt",
      "last_seen_at",
      "lastSeen",
      "last_seen",
      "last_active_at",
      "lastActiveAt",
      "lastActivityAt",
      "activityAt",
      "created_at",
      "createdAt",
    ]);

    const usedTokens = readNumberFromRecords(candidateRecords, [
      "used",
      "used_tokens",
      "tokens",
      "current",
      "token_count",
      "tokenCount",
      "totalTokens",
      "total_tokens",
      "inputTokens",
      "input_tokens",
    ]);
    const maxTokens = readNumberFromRecords(candidateRecords, [
      "max",
      "limit",
      "token_limit",
      "capacity",
      "max_tokens",
      "maxTokens",
      "context_window",
      "contextWindow",
      "contextTokens",
      "context_tokens",
      "maxContextTokens",
      "max_context_tokens",
    ]);

    const pctFromPayload = readNumberFromRecords(candidateRecords, [
      "pct",
      "percent",
      "ratio_pct",
      "ratioPct",
      "token_pct",
      "usage_pct",
      "percentUsed",
      "contextPercent",
    ]);
    const usagePct = Number.isFinite(pctFromPayload ?? NaN)
      ? Math.max(0, Math.min(100, Math.round(pctFromPayload ?? 0)))
      : usedTokens !== null && maxTokens !== null && maxTokens > 0
        ? Math.max(0, Math.min(100, Math.round((usedTokens / maxTokens) * 100)))
        : 0;

    const usage =
      usedTokens !== null && maxTokens !== null
        ? `${compactNumber(usedTokens)}/${compactNumber(maxTokens)} (${usagePct}%)`
        : usedTokens !== null
          ? `${compactNumber(usedTokens)} tokens`
          : DASH;

    const subtitleBits = [channel, model].filter(Boolean) as string[];
    const subtitle =
      subtitleBits.length > 0 ? subtitleBits.join(" · ") : "Session";
    const modelWithProvider =
      modelProvider && model && modelProvider !== model
        ? `${model} · ${modelProvider}`
        : model;
    const subtitleWithProvider = [channel, modelWithProvider]
      .filter(Boolean)
      .join(" · ");

    return {
      key,
      title: label,
      subtitle: subtitleWithProvider || subtitle,
      usage,
      lastSeenAt,
      isMain:
        mainIdentifiers.length > 0 &&
        sharesSessionIdentity(identifiers, mainIdentifiers),
    };
  });
};


export default function DashboardPage() {
  const router = useRouter();
  const { isSignedIn } = useAuth();

  const boardsQuery = useListBoardsApiV1BoardsGet<
    listBoardsApiV1BoardsGetResponse,
    ApiError
  >(
    { limit: 200 },
    {
      query: {
        enabled: Boolean(isSignedIn),
        refetchInterval: 30_000,
        refetchOnMount: "always",
      },
    },
  );

  const agentsQuery = useListAgentsApiV1AgentsGet<
    listAgentsApiV1AgentsGetResponse,
    ApiError
  >(
    { limit: 200 },
    {
      query: {
        enabled: Boolean(isSignedIn),
        refetchInterval: 15_000,
        refetchOnMount: "always",
      },
    },
  );

  const metricsQuery = useDashboardMetricsApiV1MetricsDashboardGet<
    dashboardMetricsApiV1MetricsDashboardGetResponse,
    ApiError
  >(
    {
      range_key: DASHBOARD_RANGE,
    },
    {
      query: {
        enabled: Boolean(isSignedIn),
        refetchInterval: 15_000,
        refetchOnMount: "always",
        retry: 3,
        retryDelay: (attempt) => Math.min(1000 * 2 ** attempt, 5000),
      },
    },
  );

  const activityQuery = useListActivityApiV1ActivityGet<
    listActivityApiV1ActivityGetResponse,
    ApiError
  >(
    { limit: 200 },
    {
      query: {
        enabled: Boolean(isSignedIn),
        refetchInterval: 15_000,
        refetchOnMount: "always",
      },
    },
  );

  const forgejoRepositoriesQuery = useQuery<ForgejoRepository[], Error>({
    queryKey: ["dashboard", "forgejo", "repositories"],
    enabled: Boolean(isSignedIn),
    refetchInterval: 60_000,
    refetchOnMount: "always",
    queryFn: () => getForgejoRepositories(),
  });

  const forgejoRepositories = useMemo(
    () => forgejoRepositoriesQuery.data ?? [],
    [forgejoRepositoriesQuery.data],
  );
  const forgejoOrganizationId = useMemo(
    () =>
      forgejoRepositories.find((repository) => repository.organization_id)
        ?.organization_id ?? null,
    [forgejoRepositories],
  );

  const forgejoMetricsQuery = useQuery<ForgejoIssueMetrics | null, Error>({
    queryKey: ["dashboard", "forgejo", "metrics", forgejoOrganizationId],
    enabled: Boolean(
      isSignedIn &&
      !forgejoRepositoriesQuery.isLoading &&
      !forgejoRepositoriesQuery.error,
    ),
    refetchInterval: 60_000,
    refetchOnMount: "always",
    queryFn: () => {
      if (!forgejoOrganizationId) return Promise.resolve(null);
      return getForgejoMetrics({ organization_id: forgejoOrganizationId });
    },
  });

  const forgejoHeatmapQuery = useQuery<{ days: ForgejoHeatmapDay[]; max_count: number } | null, Error>({
    queryKey: ["dashboard", "forgejo", "heatmap", forgejoOrganizationId],
    enabled: Boolean(
      isSignedIn &&
      forgejoOrganizationId &&
      !forgejoRepositoriesQuery.isLoading &&
      !forgejoRepositoriesQuery.error,
    ),
    refetchInterval: 60_000,
    refetchOnMount: "always",
    queryFn: () => {
      if (!forgejoOrganizationId) return Promise.resolve(null);
      return getForgejoHeatmap({ organization_id: forgejoOrganizationId });
    },
  });

  const boards = useMemo(
    () =>
      boardsQuery.data?.status === 200
        ? [...(boardsQuery.data.data.items ?? [])].sort((a, b) =>
            a.name.localeCompare(b.name),
          )
        : [],
    [boardsQuery.data],
  );

  const agents = useMemo(
    () =>
      agentsQuery.data?.status === 200
        ? [...(agentsQuery.data.data.items ?? [])].sort((a, b) =>
            a.name.localeCompare(b.name),
          )
        : [],
    [agentsQuery.data],
  );

  const metrics =
    metricsQuery.data?.status === 200 ? metricsQuery.data.data : null;

  const onlineAgents = useMemo(
    () =>
      agents.filter((agent) => (agent.status ?? "").toLowerCase() === "online")
        .length,
    [agents],
  );
  const gatewayTargets = useMemo<GatewayTarget[]>(() => {
    const byGateway = new Map<string, GatewayTarget>();
    for (const board of boards) {
      const gatewayId = board.gateway_id;
      if (!gatewayId) continue;
      if (byGateway.has(gatewayId)) continue;
      byGateway.set(gatewayId, {
        gatewayId,
        boardId: board.id,
        boardName: board.name,
      });
    }
    return [...byGateway.values()].sort((a, b) =>
      a.boardName.localeCompare(b.boardName),
    );
  }, [boards]);
  const hasConfiguredGateways = gatewayTargets.length > 0;

  const gatewayStatusesQuery = useQuery<GatewaySnapshot[], ApiError>({
    queryKey: [
      "dashboard",
      "gateway-statuses",
      gatewayTargets.map((target) => `${target.gatewayId}:${target.boardId}`),
    ],
    enabled: Boolean(isSignedIn && hasConfiguredGateways),
    refetchInterval: 15_000,
    refetchOnMount: "always",
    queryFn: async ({ signal }) => {
      return Promise.all(
        gatewayTargets.map(async (target): Promise<GatewaySnapshot> => {
          try {
            const response = await gatewaysStatusApiV1GatewaysStatusGet(
              { board_id: target.boardId },
              { signal },
            );
            if (response.status !== 200) {
              return {
                ...target,
                connected: false,
                gatewayUrl: null,
                sessionsCount: 0,
                sessions: [],
                mainSession: null,
                mainSessionError: null,
                error: null,
                requestError: `Gateway status request failed (${response.status})`,
              };
            }
            const payload: GatewaysStatusResponse = response.data;
            return {
              ...target,
              connected: Boolean(payload.connected),
              gatewayUrl: payload.gateway_url ?? null,
              sessionsCount: Number(payload.sessions_count ?? 0),
              sessions: Array.isArray(payload.sessions) ? payload.sessions : [],
              mainSession: payload.main_session ?? null,
              mainSessionError: payload.main_session_error ?? null,
              error: payload.error ?? null,
              requestError: null,
            };
          } catch (error) {
            if (signal.aborted) throw error;
            return {
              ...target,
              connected: false,
              gatewayUrl: null,
              sessionsCount: 0,
              sessions: [],
              mainSession: null,
              mainSessionError: null,
              error: null,
              requestError:
                error instanceof Error
                  ? error.message
                  : "Gateway status request failed.",
            };
          }
        }),
      );
    },
  });

  const gatewaySnapshots = useMemo(
    () => gatewayStatusesQuery.data ?? [],
    [gatewayStatusesQuery.data],
  );
  // Runtime usage — query all gateways in parallel, aggregate
  const runtimeUsageQuery = useQuery<AggregatedRuntimeUsage, ApiError>({
    queryKey: [
      "dashboard",
      "runtime-usage",
      gatewayTargets.map((t) => t.gatewayId),
    ],
    enabled: Boolean(isSignedIn && hasConfiguredGateways),
    refetchInterval: 30_000,
    refetchOnMount: "always",
    queryFn: async () => {
      const results = await Promise.allSettled(
        gatewayTargets.map((target) =>
          getGatewayRuntimeUsageApiV1GatewaysGatewayIdRuntimeUsageGet(
            target.gatewayId,
          ).then((res) => {
            if (res.status === 200) return res.data as RuntimeUsageResponse;
            return null;
          }),
        ),
      );
      const valid = results
        .filter(
          (r): r is PromiseFulfilledResult<RuntimeUsageResponse> =>
            r.status === "fulfilled" && r.value !== null,
        )
        .map((r) => r.value);
      return aggregateRuntimeUsage(valid);
    },
  });

  const runtimeUsage = runtimeUsageQuery.data ?? null;

  // Gateway health — query the first gateway only for the compact dashboard panel
  const primaryGatewayId = gatewayTargets[0]?.gatewayId ?? null;
  const gatewayHealthQuery = useQuery<SystemHealthResponse | null, ApiError>({
    queryKey: ["dashboard", "gateway-health", primaryGatewayId],
    enabled: Boolean(isSignedIn && primaryGatewayId),
    refetchInterval: 60_000,
    refetchOnMount: "always",
    queryFn: () => {
      if (!primaryGatewayId) return Promise.resolve(null);
      return getGatewayHealthApiV1GatewaysGatewayIdHealthGet(primaryGatewayId).then(
        (r) => (r.status === 200 ? (r.data as SystemHealthResponse) : null),
      );
    },
  });

  const gatewayCronQuery = useQuery<CronStatusResponse | null, ApiError>({
    queryKey: ["dashboard", "gateway-cron", primaryGatewayId],
    enabled: Boolean(isSignedIn && primaryGatewayId),
    refetchInterval: 60_000,
    refetchOnMount: "always",
    queryFn: () => {
      if (!primaryGatewayId) return Promise.resolve(null);
      return getGatewayCronApiV1GatewaysGatewayIdCronGet(primaryGatewayId).then(
        (r) => (r.status === 200 ? (r.data as CronStatusResponse) : null),
      );
    },
  });

  // Build a session-id → TopSession lookup for enriching session summaries
  const topSessionById = useMemo(() => {
    const map = new Map<string, { costUsd: number; totalTokens: number; model: string | null }>();
    for (const s of runtimeUsage?.topSessions ?? []) {
      if (s.session_id) {
        map.set(s.session_id, {
          costUsd: s.cost_usd,
          totalTokens: s.total_tokens,
          model: s.model ?? null,
        });
      }
    }
    return map;
  }, [runtimeUsage]);

  const sessionSummaries = useMemo(
    () =>
      gatewaySnapshots.flatMap((snapshot) => {
        if (snapshot.requestError) return [];
        const sourceLabel = snapshot.gatewayUrl || snapshot.boardName;
        return toSessionSummaries(snapshot.sessions, snapshot.mainSession).map(
          (session) => {
            const enrichment = topSessionById.get(session.key) ?? topSessionById.get(`${snapshot.gatewayId}:${session.key}`);
            return {
              ...session,
              key: `${snapshot.gatewayId}:${session.key}`,
              subtitle: `${sourceLabel} · ${session.subtitle}`,
              costUsd: enrichment?.costUsd ?? null,
              totalTokens: enrichment?.totalTokens ?? null,
              model: enrichment?.model ?? null,
            };
          },
        );
      }),
    [gatewaySnapshots, topSessionById],
  );

  const activityEvents = useMemo(
    () =>
      activityQuery.data?.status === 200
        ? [...(activityQuery.data.data.items ?? [])]
        : [],
    [activityQuery.data],
  );

  const orderedActivityEvents = useMemo(
    () =>
      [...activityEvents].sort((a, b) => {
        const left = parseTimestamp(a.created_at)?.getTime() ?? 0;
        const right = parseTimestamp(b.created_at)?.getTime() ?? 0;
        return right - left;
      }),
    [activityEvents],
  );

  const recentLogs = orderedActivityEvents.slice(0, 8);

  const latestThroughputPoint =
    metrics?.throughput.primary.points?.[
      metrics.throughput.primary.points.length - 1
    ] ?? null;
  const throughputTotal = (metrics?.throughput.primary.points ?? []).reduce(
    (sum, point) => sum + Number(point.value ?? 0),
    0,
  );
  const completionDaysCount = (metrics?.throughput.primary.points ?? []).reduce(
    (sum, point) => sum + (Number(point.value ?? 0) > 0 ? 1 : 0),
    0,
  );

  const inboxTasksMetric = metrics?.kpis.inbox_tasks ?? 0;
  const inProgressTasksMetric = metrics?.kpis.in_progress_tasks ?? 0;
  const reviewTasksMetric = metrics?.kpis.review_tasks ?? 0;
  const doneTasksMetric = metrics?.kpis.done_tasks ?? 0;

  const activeAgentsMetric = onlineAgents;
  const tasksTotal =
    inboxTasksMetric +
    inProgressTasksMetric +
    reviewTasksMetric +
    doneTasksMetric;
  const tasksInProgressMetric =
    metrics?.kpis.tasks_in_progress ?? inProgressTasksMetric;
  const errorRateMetric = Number(metrics?.kpis.error_rate_pct ?? 0);
  const reviewBacklogRatio =
    inProgressTasksMetric > 0
      ? reviewTasksMetric / inProgressTasksMetric
      : null;

  const gatewayConnectedCount = gatewaySnapshots.filter(
    (snapshot) => !snapshot.requestError && snapshot.connected,
  ).length;
  const gatewayDisconnectedCount = gatewaySnapshots.filter(
    (snapshot) => !snapshot.requestError && !snapshot.connected,
  ).length;
  const gatewayUnavailableCount = gatewaySnapshots.filter((snapshot) =>
    Boolean(snapshot.requestError),
  ).length;
  const gatewayHealthErrorCount = gatewaySnapshots.filter((snapshot) =>
    Boolean(snapshot.error || snapshot.mainSessionError),
  ).length;

  const countedSessions = gatewaySnapshots.reduce(
    (sum, snapshot) => sum + Math.max(0, snapshot.sessionsCount),
    0,
  );
  const activeSessions = Math.max(countedSessions, sessionSummaries.length);

  const gatewayStatusLabel = !hasConfiguredGateways
    ? "Not configured"
    : gatewayStatusesQuery.isLoading
      ? "Checking"
      : gatewayConnectedCount === gatewayTargets.length
        ? "All connected"
        : gatewayConnectedCount > 0
          ? "Partially connected"
          : gatewayUnavailableCount === gatewayTargets.length
            ? "Unavailable"
            : "Disconnected";
  const gatewayBadgeTone: "online" | "offline" | "neutral" =
    gatewayStatusLabel === "All connected"
      ? "online"
      : gatewayStatusLabel === "Partially connected" ||
          gatewayStatusLabel === "Disconnected" ||
          gatewayStatusLabel === "Unavailable"
        ? "offline"
        : "neutral";
  const gatewayStatusTone: SummaryRow["tone"] =
    gatewayStatusLabel === "All connected"
      ? "success"
      : gatewayStatusLabel === "Checking" ||
          gatewayStatusLabel === "Not configured"
        ? "default"
        : gatewayStatusLabel === "Partially connected" ||
            gatewayStatusLabel === "Disconnected"
          ? "warning"
          : "danger";

  const workloadRows: SummaryRow[] = [
    {
      label: "Total work items",
      value: formatCount(tasksTotal),
    },
    {
      label: "Inbox",
      value: formatCount(inboxTasksMetric),
    },
    {
      label: "In progress",
      value: formatCount(inProgressTasksMetric),
      tone: inProgressTasksMetric > 0 ? "warning" : "default",
    },
    {
      label: "In review",
      value: formatCount(reviewTasksMetric),
    },
    {
      label: "Completed",
      value: formatCount(doneTasksMetric),
      tone: doneTasksMetric > 0 ? "success" : "default",
    },
  ];

  const throughputRows: SummaryRow[] = [
    {
      label: "Completed tasks",
      value: formatCount(throughputTotal),
    },
    {
      label: "Average throughput",
      value: formatPerDay(throughputTotal, DASHBOARD_RANGE_DAYS),
    },
    {
      label: "Error rate",
      value: formatPercent(errorRateMetric),
      tone: errorRateMetric > 0 ? "warning" : "success",
    },
    {
      label: "Completion consistency",
      value: `${formatCount(completionDaysCount)} active days`,
      tone:
        completionDaysCount >= Math.ceil(DASHBOARD_RANGE_DAYS * 0.75)
          ? "success"
          : "default",
    },
    {
      label: "Review backlog ratio",
      value:
        reviewBacklogRatio !== null
          ? `${reviewBacklogRatio.toFixed(2)}x`
          : reviewTasksMetric > 0
            ? "∞"
            : "0.00x",
      tone:
        reviewBacklogRatio !== null
          ? reviewBacklogRatio > 1
            ? "warning"
            : "success"
          : reviewTasksMetric > 0
            ? "warning"
            : "success",
    },
  ];

  const gatewayRows: SummaryRow[] = [
    {
      label: "Gateway status",
      value: gatewayStatusLabel,
      tone: gatewayStatusTone,
    },
    { label: "Configured gateways", value: formatCount(gatewayTargets.length) },
    {
      label: "Connected gateways",
      value: formatCount(gatewayConnectedCount),
      tone: gatewayConnectedCount > 0 ? "success" : "default",
    },
    {
      label: "Unavailable gateways",
      value: formatCount(gatewayUnavailableCount),
      tone: gatewayUnavailableCount > 0 ? "danger" : "default",
    },
    {
      label: "Gateways with issues",
      value: formatCount(gatewayHealthErrorCount + gatewayDisconnectedCount),
      tone:
        gatewayHealthErrorCount + gatewayDisconnectedCount > 0
          ? "warning"
          : "success",
    },
  ];
  const pendingApprovalItems = metrics?.pending_approvals.items ?? [];
  const pendingApprovalsTotal = metrics?.pending_approvals.total ?? 0;
  const hasPendingApprovals = pendingApprovalItems.length > 0;
  const activityFeedHref = "/activity";
  const forgejoIssueMetrics = forgejoMetricsQuery.data ?? null;
  const forgejoIssueMetricsError =
    formatForgejoDashboardError(forgejoRepositoriesQuery.error) ??
    formatForgejoDashboardError(forgejoMetricsQuery.error) ??
    null;
  const forgejoIssueMetricsLoading =
    forgejoRepositoriesQuery.isLoading || forgejoMetricsQuery.isLoading;

  const shouldIgnoreRowNavigation = (target: EventTarget | null): boolean => {
    if (!(target instanceof HTMLElement)) return false;
    return Boolean(target.closest("a"));
  };

  const buildActivityEventHref = (event: ActivityEventRead): string => {
    const routeName = event.route_name ?? null;
    const routeParams = event.route_params ?? {};

    if (routeName === "board.approvals") {
      const boardId = routeParams.boardId;
      if (boardId) {
        return `/boards/${encodeURIComponent(boardId)}/approvals`;
      }
    }

    if (routeName === "board") {
      const boardId = routeParams.boardId;
      if (boardId) {
        const params = new URLSearchParams();
        Object.entries(routeParams).forEach(([key, value]) => {
          if (key !== "boardId") params.set(key, value);
        });
        const query = params.toString();
        return query
          ? `/boards/${encodeURIComponent(boardId)}?${query}`
          : `/boards/${encodeURIComponent(boardId)}`;
      }
    }

    const params = new URLSearchParams(
      Object.keys(routeParams).length > 0
        ? routeParams
        : {
            eventId: event.id,
            eventType: event.event_type,
            createdAt: event.created_at,
          },
    );
    if (event.task_id && !params.has("taskId")) {
      params.set("taskId", event.task_id);
    }
    return `${activityFeedHref}?${params.toString()}`;
  };

  const navigateToActivityFeed = (href: string) => {
    router.push(href);
  };

  const handleLogRowClick = (
    event: MouseEvent<HTMLDivElement>,
    href: string,
  ) => {
    if (shouldIgnoreRowNavigation(event.target)) return;
    navigateToActivityFeed(href);
  };

  const handleLogRowKeyDown = (
    event: KeyboardEvent<HTMLDivElement>,
    href: string,
  ) => {
    if (event.key !== "Enter" && event.key !== " ") return;
    if (shouldIgnoreRowNavigation(event.target)) return;
    event.preventDefault();
    navigateToActivityFeed(href);
  };

  return (
    <DashboardShell>
      <SignedOut>
        <SignedOutPanel
          message="Sign in to access the dashboard."
          forceRedirectUrl="/onboarding"
          signUpForceRedirectUrl="/onboarding"
        />
      </SignedOut>
      <SignedIn>
        <DashboardSidebar />
        <main className="flex-1 overflow-y-auto bg-app">
          <div className="p-4 md:p-8">
            {metricsQuery.error ? (
              <div className="mb-4 rounded-lg border border-[color:rgba(248,113,113,0.35)] bg-[color:rgba(248,113,113,0.08)] p-3 text-sm text-[color:var(--danger)]">
                Load failed: {metricsQuery.error.message}
              </div>
            ) : null}

            <div className="grid grid-cols-1 gap-4 md:grid-cols-2 xl:grid-cols-4">
              <DashboardMetricCard
                title="Online Agents"
                value={formatCount(activeAgentsMetric)}
                secondary={`${formatCount(agents.length)} total`}
                icon={<Bot className="h-4 w-4" />}
                tone="accent"
              />
              <DashboardMetricCard
                title="Tasks In Progress"
                value={formatCount(tasksInProgressMetric)}
                secondary={`${formatCount(tasksTotal)} total`}
                icon={<LayoutGrid className="h-4 w-4" />}
                tone="success"
              />
              <DashboardMetricCard
                title="Error Rate"
                value={formatPercent(errorRateMetric)}
                secondary={`${formatCount(Number(latestThroughputPoint?.value ?? 0))} completed (latest)`}
                icon={<Activity className="h-4 w-4" />}
                tone="warning"
              />
              <DashboardMetricCard
                title="Completion Speed"
                value={formatPerDay(throughputTotal, DASHBOARD_RANGE_DAYS)}
                secondary={`${formatCount(throughputTotal)} completed`}
                infoText={`Based on ${DASHBOARD_RANGE_LABEL}`}
                icon={<Timer className="h-4 w-4" />}
                tone="success"
              />
            </div>

            <div className="mt-4">
              <ForgejoIssueMetricCards
                metrics={forgejoIssueMetrics}
                repositories={forgejoRepositories}
                isLoading={forgejoIssueMetricsLoading}
                error={forgejoIssueMetricsError}
              />
            </div>

            <div className="mt-4">
              <section className="rounded-xl border border-[color:var(--border)] bg-[color:var(--surface)] p-4 shadow-lush md:p-6">
                <div className="mb-4">
                  <h3 className="text-lg font-semibold text-strong">
                    Git Activity
                  </h3>
                  <p className="mt-1 text-sm text-muted">
                    Issue contributions across all tracked repositories in the
                    last 12 months.
                  </p>
                </div>
                <ForgejoHeatmap
                  days={forgejoHeatmapQuery.data?.days ?? []}
                  maxCount={forgejoHeatmapQuery.data?.max_count ?? 0}
                  isLoading={forgejoHeatmapQuery.isLoading}
                />
              </section>
            </div>

            <div className="mt-4 grid grid-cols-1 gap-4 xl:grid-cols-3">
              <DashboardInfoBlock title="Workload" rows={workloadRows} />
              <DashboardInfoBlock
                title="Throughput"
                infoText={`All throughput values are calculated for ${DASHBOARD_RANGE_LABEL}`}
                rows={throughputRows}
              />
              <DashboardInfoBlock
                title="Gateway Health"
                badge={{ text: gatewayStatusLabel, tone: gatewayBadgeTone }}
                rows={gatewayRows}
              />
            </div>

            <PendingApprovalsSection
              items={pendingApprovalItems}
              total={pendingApprovalsTotal}
              isLoading={!metrics && metricsQuery.isLoading}
              hasError={!metrics && Boolean(metricsQuery.error)}
              formatCount={formatCount}
              formatRelative={formatRelativeTimestamp}
            />

            {hasConfiguredGateways && (
              <div className="mt-4">
                <RuntimeUsageSection
                  usage={runtimeUsage}
                  isLoading={runtimeUsageQuery.isLoading}
                  hasGateways={hasConfiguredGateways}
                />
              </div>
            )}

            <div className="mt-4 grid grid-cols-1 gap-4 md:grid-cols-2">
              <SessionsSection
                sessions={sessionSummaries}
                activeSessions={activeSessions}
                hasConfiguredGateways={hasConfiguredGateways}
                isLoading={gatewayStatusesQuery.isLoading}
                gatewayUnavailableCount={gatewayUnavailableCount}
                gatewayTargetsCount={gatewayTargets.length}
                formatCount={formatCount}
                formatRelative={formatRelativeTimestamp}
                dash={DASH}
              />
              <RecentActivitySection
                events={recentLogs}
                feedHref={activityFeedHref}
                onRowClick={handleLogRowClick}
                onRowKeyDown={handleLogRowKeyDown}
                buildHref={buildActivityEventHref}
                formatRelative={formatRelativeTimestamp}
                formatTimestamp={formatTimestamp}
              />
            </div>

            {hasConfiguredGateways && (
              <div className="mt-4 grid grid-cols-1 gap-4 md:grid-cols-2">
                <GatewayHealthPanel
                  health={gatewayHealthQuery.data ?? null}
                  isLoading={gatewayHealthQuery.isLoading}
                  hasGateways={hasConfiguredGateways}
                />
                <GatewayCronPanel
                  cron={gatewayCronQuery.data ?? null}
                  isLoading={gatewayCronQuery.isLoading}
                  hasGateways={hasConfiguredGateways}
                />
              </div>
            )}
          </div>
        </main>
      </SignedIn>
    </DashboardShell>
  );
}
