"use client";

import React, { FormEvent, useCallback, useEffect, useMemo, useState } from "react";
import {
  Alert,
  alpha,
  Box,
  Button,
  Chip,
  CircularProgress,
  Dialog,
  DialogActions,
  DialogContent,
  DialogTitle,
  FormControl,
  IconButton,
  InputLabel,
  LinearProgress,
  MenuItem,
  Paper,
  Select,
  Stack,
  Table,
  TableBody,
  TableCell,
  TableContainer,
  TableHead,
  TablePagination,
  TableRow,
  TextField,
  Tooltip,
  Typography,
} from "@mui/material";
import "dayjs/locale/zh-cn";
import dayjs from "dayjs";
import { AdapterDayjs } from "@mui/x-date-pickers/AdapterDayjs";
import { DateTimePicker, LocalizationProvider } from "@mui/x-date-pickers";
import { zhCN as pickerZhCN } from "@mui/x-date-pickers/locales";
import {
  AdminPanelSettings as AdminPanelSettingsIcon,
  Close as CloseIcon,
  Download as DownloadIcon,
  FactCheck as FactCheckIcon,
  FilterAltOff as FilterAltOffIcon,
  InfoOutlined as InfoOutlinedIcon,
  Refresh as RefreshIcon,
  Search as SearchIcon,
  Visibility as VisibilityIcon,
} from "@mui/icons-material";
import { config } from "@config/config";
import { apiFetch } from "@/lib/apiFetch";
import { permissionCodes } from "@/lib/permissions";
import { useAccessStore } from "@/store/accessStore";

type AuditLog = {
  id: string;
  user_id: string | null;
  project_id: string | null;
  action: string;
  resource_type: string | null;
  resource_id: string | null;
  ip_address: string | null;
  request_method: string | null;
  request_path: string | null;
  request_data: Record<string, unknown> | null;
  response_status: number | null;
  timestamp: string;
};

type MetadataUser = {
  id: string;
  username: string;
  email: string;
};

type AdminProject = {
  project_id: string;
  name: string;
  code: string;
};

type AuditFilters = {
  user_id: string;
  project_id: string;
  action: string;
  resource_type: string;
  status: AuditStatusFilter;
  start_time: string;
  end_time: string;
};

type AuditStatusFilter =
  | "all"
  | "success"
  | "redirect"
  | "client_error"
  | "server_error"
  | "no_status";

const defaultFilters: AuditFilters = {
  user_id: "",
  project_id: "",
  action: "",
  resource_type: "",
  status: "all",
  start_time: "",
  end_time: "",
};

const AUDIT_LOGS_PATH = "/api/v1/audit-logs";

const statusFilterOptions: Array<{ value: AuditStatusFilter; label: string }> = [
  { value: "all", label: "全部状态" },
  { value: "success", label: "成功 2xx" },
  { value: "redirect", label: "重定向 3xx" },
  { value: "client_error", label: "客户端错误 4xx" },
  { value: "server_error", label: "服务端错误 5xx" },
  { value: "no_status", label: "无响应状态" },
];

const cardSx = {
  borderRadius: 2,
  borderColor: "divider",
  boxShadow: "0 10px 30px rgba(15, 23, 42, 0.06)",
};

const tableSx = {
  minWidth: 1080,
  "& .MuiTableCell-head": {
    bgcolor: "action.hover",
    color: "text.secondary",
    fontSize: 12,
    fontWeight: 700,
    letterSpacing: 0,
  },
  "& .MuiTableRow-root:last-child .MuiTableCell-body": {
    borderBottom: 0,
  },
};

const selectMenuProps = {
  disableScrollLock: true,
};

const readErrorText = async (response: Response) => {
  const text = await response.text();
  return text || `HTTP ${response.status}`;
};

const normalizeDateTime = (value: string) => {
  if (!value) return "";
  const date = new Date(value);
  if (Number.isNaN(date.getTime())) return "";
  return date.toISOString();
};

const formatDateTime = (value: string) => {
  const date = new Date(value);
  if (Number.isNaN(date.getTime())) return value;
  return new Intl.DateTimeFormat("zh-CN", {
    year: "numeric",
    month: "2-digit",
    day: "2-digit",
    hour: "2-digit",
    minute: "2-digit",
    second: "2-digit",
    hour12: false,
  }).format(date);
};

const getStatusMeta = (status: number | null) => {
  if (status == null) {
    return { label: "无状态", color: "default" as const };
  }
  if (status >= 200 && status < 300) {
    return { label: String(status), color: "success" as const };
  }
  if (status >= 300 && status < 400) {
    return { label: String(status), color: "info" as const };
  }
  if (status >= 400 && status < 500) {
    return { label: String(status), color: "warning" as const };
  }
  if (status >= 500) {
    return { label: String(status), color: "error" as const };
  }
  return { label: String(status), color: "default" as const };
};

const matchesStatusFilter = (log: AuditLog, filter: AuditStatusFilter) => {
  const status = log.response_status;
  if (filter === "all") return true;
  if (filter === "no_status") return status == null;
  if (status == null) return false;
  if (filter === "success") return status >= 200 && status < 300;
  if (filter === "redirect") return status >= 300 && status < 400;
  if (filter === "client_error") return status >= 400 && status < 500;
  if (filter === "server_error") return status >= 500;
  return true;
};

const appendCsvValue = (value: unknown) => {
  const text =
    typeof value === "string"
      ? value
      : value == null
        ? ""
        : JSON.stringify(value);
  return `"${text.replaceAll('"', '""')}"`;
};

const buildCsv = (logs: AuditLog[], userMap: Map<string, MetadataUser>, projectMap: Map<string, AdminProject>) => {
  const header = [
    "时间",
    "操作者",
    "用户ID",
    "项目",
    "项目ID",
    "动作",
    "资源类型",
    "资源ID",
    "状态",
    "方法",
    "路径",
    "IP",
    "请求数据",
  ];
  const rows = logs.map((log) => [
    formatDateTime(log.timestamp),
    log.user_id ? userMap.get(log.user_id)?.username ?? "" : "",
    log.user_id ?? "",
    log.project_id ? projectMap.get(log.project_id)?.name ?? "" : "",
    log.project_id ?? "",
    log.action,
    log.resource_type ?? "",
    log.resource_id ?? "",
    log.response_status ?? "",
    log.request_method ?? "",
    log.request_path ?? "",
    log.ip_address ?? "",
    log.request_data ?? "",
  ]);

  return [header, ...rows]
    .map((row) => row.map(appendCsvValue).join(","))
    .join("\n");
};

const buildServerParams = (filters: AuditFilters, skip: number, limit: number) => {
  const params = new URLSearchParams();
  if (filters.user_id) params.set("user_id", filters.user_id);
  if (filters.project_id) params.set("project_id", filters.project_id);
  if (filters.action.trim()) params.set("action", filters.action.trim());
  if (filters.resource_type.trim()) {
    params.set("resource_type", filters.resource_type.trim());
  }
  const startTime = normalizeDateTime(filters.start_time);
  const endTime = normalizeDateTime(filters.end_time);
  if (startTime) params.set("start_time", startTime);
  if (endTime) params.set("end_time", endTime);
  params.set("skip", String(skip));
  params.set("limit", String(limit));
  return params;
};

const buildCountParams = (filters: AuditFilters) => {
  const params = buildServerParams(filters, 0, 1);
  params.delete("skip");
  params.delete("limit");
  return params;
};

const EmptyRow = ({ colSpan, label }: { colSpan: number; label: string }) => (
  <TableRow>
    <TableCell colSpan={colSpan} align="center" sx={{ py: 6 }}>
      <Typography color="text.secondary">{label}</Typography>
    </TableCell>
  </TableRow>
);

const StatusChip = ({ status }: { status: number | null }) => {
  const meta = getStatusMeta(status);
  return <Chip size="small" color={meta.color} label={meta.label} variant={status == null ? "outlined" : "filled"} />;
};

const DetailLine = ({
  label,
  value,
}: {
  label: string;
  value: React.ReactNode;
}) => (
  <Box
    sx={{
      minWidth: 0,
      p: 1.5,
      borderRadius: 1.5,
      border: 1,
      borderColor: "divider",
      bgcolor: "background.default",
    }}
  >
    <Typography variant="caption" color="text.secondary">
      {label}
    </Typography>
    <Box
      sx={{
        mt: 0.5,
        color: "text.primary",
        fontSize: 14,
        fontWeight: 600,
        lineHeight: 1.6,
        overflowWrap: "anywhere",
      }}
    >
      {value || "-"}
    </Box>
  </Box>
);

const DetailSection = ({
  title,
  children,
}: {
  title: string;
  children: React.ReactNode;
}) => (
  <Paper variant="outlined" sx={{ p: 2, borderRadius: 2 }}>
    <Typography variant="subtitle2" fontWeight={800} sx={{ mb: 1.5 }}>
      {title}
    </Typography>
    <Box
      sx={{
        display: "grid",
        gridTemplateColumns: { xs: "1fr", md: "repeat(3, minmax(0, 1fr))" },
        gap: 1.5,
      }}
    >
      {children}
    </Box>
  </Paper>
);

export const AuditLogPanel = () => {
  const accessLoading = useAccessStore((state) => state.loading);
  const permissions = useAccessStore((state) => state.permissions);
  const isSystemAdmin = useAccessStore(
    (state) => state.context?.is_system_admin === true,
  );
  const canViewAudit = permissions.includes(permissionCodes.auditView);
  const adminChecked = !accessLoading;
  const isAuthorized = adminChecked && canViewAudit && isSystemAdmin;
  const [logs, setLogs] = useState<AuditLog[]>([]);
  const [users, setUsers] = useState<MetadataUser[]>([]);
  const [projects, setProjects] = useState<AdminProject[]>([]);
  const [filters, setFilters] = useState<AuditFilters>(defaultFilters);
  const [appliedFilters, setAppliedFilters] = useState<AuditFilters>(defaultFilters);
  const [page, setPage] = useState(0);
  const [rowsPerPage, setRowsPerPage] = useState(25);
  const [totalCount, setTotalCount] = useState(0);
  const [loading, setLoading] = useState(false);
  const [exporting, setExporting] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const [selectedLog, setSelectedLog] = useState<AuditLog | null>(null);
  const [lastLoadedAt, setLastLoadedAt] = useState<string | null>(null);

  const userMap = useMemo(
    () => new Map(users.map((user) => [user.id, user])),
    [users],
  );
  const projectMap = useMemo(
    () => new Map(projects.map((project) => [project.project_id, project])),
    [projects],
  );
  const usesClientStatusFilter = appliedFilters.status !== "all";

  const visibleLogs = useMemo(() => {
    if (!usesClientStatusFilter) return logs;
    const filtered = logs.filter((log) => matchesStatusFilter(log, appliedFilters.status));
    return filtered.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage);
  }, [appliedFilters.status, logs, page, rowsPerPage, usesClientStatusFilter]);

  const loadOptions = useCallback(async () => {
    const [usersResult, projectsResult] = await Promise.allSettled([
      apiFetch(`${config.BACKEND_URL}/api/v1/admin/users`),
      apiFetch(`${config.BACKEND_URL}/api/v1/admin/projects`),
    ]);

    if (usersResult.status === "fulfilled" && usersResult.value.ok) {
      setUsers((await usersResult.value.json()) as MetadataUser[]);
    }
    if (projectsResult.status === "fulfilled" && projectsResult.value.ok) {
      setProjects((await projectsResult.value.json()) as AdminProject[]);
    }
  }, []);

  const loadLogs = useCallback(async () => {
    setLoading(true);
    setError(null);
    try {
      if (appliedFilters.status === "all") {
        const params = buildServerParams(appliedFilters, page * rowsPerPage, rowsPerPage);
        const countParams = buildCountParams(appliedFilters);
        const [logsResponse, countResponse] = await Promise.all([
          apiFetch(`${config.BACKEND_URL}${AUDIT_LOGS_PATH}?${params.toString()}`),
          apiFetch(`${config.BACKEND_URL}${AUDIT_LOGS_PATH}/count?${countParams.toString()}`),
        ]);
        if (!logsResponse.ok) throw new Error(await readErrorText(logsResponse));
        if (!countResponse.ok) throw new Error(await readErrorText(countResponse));
        const countPayload = (await countResponse.json()) as { count?: number };
        setLogs((await logsResponse.json()) as AuditLog[]);
        setTotalCount(Number(countPayload.count ?? 0));
      } else {
        const params = buildServerParams(appliedFilters, 0, 1000);
        const response = await apiFetch(`${config.BACKEND_URL}${AUDIT_LOGS_PATH}?${params.toString()}`);
        if (!response.ok) throw new Error(await readErrorText(response));
        const payload = (await response.json()) as AuditLog[];
        setLogs(payload);
        setTotalCount(payload.filter((log) => matchesStatusFilter(log, appliedFilters.status)).length);
      }
      setLastLoadedAt(new Date().toISOString());
    } catch (err) {
      setError(String(err));
    } finally {
      setLoading(false);
    }
  }, [appliedFilters, page, rowsPerPage]);

  useEffect(() => {
    if (!isAuthorized) return;
    void loadOptions();
  }, [isAuthorized, loadOptions]);

  useEffect(() => {
    if (!adminChecked || !isAuthorized) return;
    void loadLogs();
  }, [adminChecked, isAuthorized, loadLogs]);

  const applyFilters = (event: FormEvent) => {
    event.preventDefault();
    setPage(0);
    setAppliedFilters(filters);
  };

  const resetFilters = () => {
    setFilters(defaultFilters);
    setAppliedFilters(defaultFilters);
    setPage(0);
  };

  const exportLogs = async () => {
    setExporting(true);
    setError(null);
    try {
      const params = buildServerParams(appliedFilters, 0, 1000);
      const response = await apiFetch(`${config.BACKEND_URL}${AUDIT_LOGS_PATH}?${params.toString()}`);
      if (!response.ok) throw new Error(await readErrorText(response));
      const payload = ((await response.json()) as AuditLog[]).filter((log) =>
        matchesStatusFilter(log, appliedFilters.status),
      );
      const csv = buildCsv(payload, userMap, projectMap);
      const blob = new Blob([`\uFEFF${csv}`], { type: "text/csv;charset=utf-8" });
      const href = URL.createObjectURL(blob);
      const link = document.createElement("a");
      link.href = href;
      link.download = `tjwater-audit-logs-${new Date().toISOString().slice(0, 10)}.csv`;
      document.body.appendChild(link);
      link.click();
      link.remove();
      URL.revokeObjectURL(href);
    } catch (err) {
      setError(String(err));
    } finally {
      setExporting(false);
    }
  };

  return (
    <Box
      sx={{
        minHeight: "100%",
        overflow: "auto",
        bgcolor: "background.default",
        p: { xs: 2, md: 3 },
      }}
    >
      <Stack spacing={2.5} sx={{ maxWidth: 1440, mx: "auto" }}>
        <Paper
          variant="outlined"
          sx={(theme) => ({
            ...cardSx,
            p: { xs: 2, md: 3 },
            bgcolor:
              theme.palette.mode === "dark"
                ? alpha(theme.palette.info.main, 0.1)
                : alpha(theme.palette.info.main, 0.04),
          })}
        >
          <Stack
            direction={{ xs: "column", md: "row" }}
            spacing={2}
            alignItems={{ xs: "stretch", md: "center" }}
            justifyContent="space-between"
          >
            <Stack direction="row" spacing={1.5} alignItems="center">
              <Box
                sx={(theme) => ({
                  width: 48,
                  height: 48,
                  borderRadius: 2,
                  display: "grid",
                  placeItems: "center",
                  color: "info.main",
                  bgcolor: alpha(theme.palette.info.main, 0.12),
                })}
              >
                <FactCheckIcon />
              </Box>
              <Box sx={{ minWidth: 0 }}>
                <Typography variant="h5" fontWeight={800}>
                  审计日志
                </Typography>
                <Typography variant="body2" color="text.secondary">
                  全局审计查询
                </Typography>
              </Box>
            </Stack>
            {adminChecked && isAuthorized && (
              <Chip
                color="success"
                icon={<AdminPanelSettingsIcon />}
                label="系统管理员权限已验证"
                sx={{ alignSelf: { xs: "flex-start", md: "center" } }}
              />
            )}
          </Stack>
        </Paper>

        {!adminChecked && (
          <Paper variant="outlined" sx={{ ...cardSx, p: 5 }}>
            <Stack alignItems="center" spacing={2}>
              <CircularProgress size={28} />
              <Typography color="text.secondary">正在校验审计权限</Typography>
            </Stack>
          </Paper>
        )}

        {adminChecked && !isAuthorized && (
          <Alert severity="error" sx={{ borderRadius: 2 }}>
            无审计日志访问权限
          </Alert>
        )}

        {error && (
          <Alert severity="error" onClose={() => setError(null)} sx={{ borderRadius: 2 }}>
            {error}
          </Alert>
        )}

        {adminChecked && isAuthorized && (
          <>
            <Stack direction={{ xs: "column", md: "row" }} spacing={2}>
              <Paper variant="outlined" sx={{ ...cardSx, p: 2, flex: 1 }}>
                <Stack spacing={0.5}>
                  <Typography variant="caption" color="text.secondary">
                    匹配记录
                  </Typography>
                  <Typography variant="h5" fontWeight={800}>
                    {totalCount}
                  </Typography>
                </Stack>
              </Paper>
              <Paper variant="outlined" sx={{ ...cardSx, p: 2, flex: 1 }}>
                <Stack spacing={0.5}>
                  <Typography variant="caption" color="text.secondary">
                    最近刷新
                  </Typography>
                  <Typography variant="h6" fontWeight={800}>
                    {lastLoadedAt ? formatDateTime(lastLoadedAt) : "-"}
                  </Typography>
                </Stack>
              </Paper>
            </Stack>

            <Paper
              component="form"
              variant="outlined"
              sx={{ ...cardSx, p: 2 }}
              onSubmit={applyFilters}
            >
              <Stack spacing={2}>
                <Stack
                  direction={{ xs: "column", md: "row" }}
                  spacing={1.5}
                  alignItems={{ xs: "stretch", md: "center" }}
                >
                  <FormControl size="small" sx={{ minWidth: { xs: "100%", md: 220 } }}>
                    <InputLabel shrink>操作者</InputLabel>
                    <Select
                      label="操作者"
                      value={filters.user_id}
                      MenuProps={selectMenuProps}
                      displayEmpty
                      notched
                      renderValue={(value) => {
                        if (!value) return "全部操作者";
                        const user = userMap.get(String(value));
                        return user ? `${user.username} / ${user.email}` : String(value);
                      }}
                      onChange={(event) =>
                        setFilters((current) => ({ ...current, user_id: event.target.value }))
                      }
                    >
                      <MenuItem value="">全部操作者</MenuItem>
                      {users.map((user) => (
                        <MenuItem key={user.id} value={user.id}>
                          {user.username} / {user.email}
                        </MenuItem>
                      ))}
                    </Select>
                  </FormControl>
                  <FormControl size="small" sx={{ minWidth: { xs: "100%", md: 220 } }}>
                    <InputLabel shrink>项目</InputLabel>
                    <Select
                      label="项目"
                      value={filters.project_id}
                      MenuProps={selectMenuProps}
                      displayEmpty
                      notched
                      renderValue={(value) => {
                        if (!value) return "全部项目";
                        const project = projectMap.get(String(value));
                        return project ? `${project.name} / ${project.code}` : String(value);
                      }}
                      onChange={(event) =>
                        setFilters((current) => ({ ...current, project_id: event.target.value }))
                      }
                    >
                      <MenuItem value="">全部项目</MenuItem>
                      {projects.map((project) => (
                        <MenuItem key={project.project_id} value={project.project_id}>
                          {project.name} / {project.code}
                        </MenuItem>
                      ))}
                    </Select>
                  </FormControl>
                  <TextField
                    size="small"
                    label="动作"
                    value={filters.action}
                    onChange={(event) =>
                      setFilters((current) => ({ ...current, action: event.target.value }))
                    }
                    sx={{ minWidth: { xs: "100%", md: 180 } }}
                  />
                  <TextField
                    size="small"
                    label="资源"
                    value={filters.resource_type}
                    onChange={(event) =>
                      setFilters((current) => ({ ...current, resource_type: event.target.value }))
                    }
                    sx={{ minWidth: { xs: "100%", md: 180 } }}
                  />
                </Stack>
                <Stack
                  direction={{ xs: "column", md: "row" }}
                  spacing={1.5}
                  alignItems={{ xs: "stretch", md: "center" }}
                >
                  <LocalizationProvider
                    dateAdapter={AdapterDayjs}
                    adapterLocale="zh-cn"
                    localeText={
                      pickerZhCN.components.MuiLocalizationProvider.defaultProps.localeText
                    }
                  >
                    <FormControl size="small" sx={{ minWidth: { xs: "100%", md: 180 } }}>
                      <InputLabel>状态</InputLabel>
                      <Select
                        label="状态"
                        value={filters.status}
                        MenuProps={selectMenuProps}
                        onChange={(event) =>
                          setFilters((current) => ({
                            ...current,
                            status: event.target.value as AuditStatusFilter,
                          }))
                        }
                      >
                        {statusFilterOptions.map((option) => (
                          <MenuItem key={option.value} value={option.value}>
                            {option.label}
                          </MenuItem>
                        ))}
                      </Select>
                    </FormControl>
                    <DateTimePicker
                      label="开始时间"
                      value={filters.start_time ? dayjs(filters.start_time) : null}
                      onChange={(value) =>
                        setFilters((current) => ({
                          ...current,
                          start_time: value?.isValid() ? value.toISOString() : "",
                        }))
                      }
                      maxDateTime={filters.end_time ? dayjs(filters.end_time) : undefined}
                      slotProps={{
                        textField: {
                          size: "small",
                          sx: { minWidth: { xs: "100%", md: 220 } },
                        },
                      }}
                    />
                    <DateTimePicker
                      label="结束时间"
                      value={filters.end_time ? dayjs(filters.end_time) : null}
                      onChange={(value) =>
                        setFilters((current) => ({
                          ...current,
                          end_time: value?.isValid() ? value.toISOString() : "",
                        }))
                      }
                      minDateTime={filters.start_time ? dayjs(filters.start_time) : undefined}
                      slotProps={{
                        textField: {
                          size: "small",
                          sx: { minWidth: { xs: "100%", md: 220 } },
                        },
                      }}
                    />
                  </LocalizationProvider>
                  <Box sx={{ flex: 1 }} />
                  <Stack direction="row" spacing={1} justifyContent="flex-end">
                    <Button
                      type="button"
                      variant="outlined"
                      startIcon={<FilterAltOffIcon />}
                      onClick={resetFilters}
                    >
                      重置
                    </Button>
                    <Button
                      type="button"
                      variant="outlined"
                      startIcon={<RefreshIcon />}
                      onClick={loadLogs}
                      disabled={loading}
                    >
                      刷新
                    </Button>
                    <Button type="submit" variant="contained" startIcon={<SearchIcon />}>
                      查询
                    </Button>
                  </Stack>
                </Stack>
              </Stack>
            </Paper>

            {usesClientStatusFilter && (
              <Alert severity="info" icon={<InfoOutlinedIcon />} sx={{ borderRadius: 2 }}>
                状态筛选基于当前查询最多 1000 条记录处理。
              </Alert>
            )}

            <Paper variant="outlined" sx={{ ...cardSx, overflow: "hidden" }}>
              <Stack
                direction={{ xs: "column", md: "row" }}
                spacing={1}
                alignItems={{ xs: "stretch", md: "center" }}
                justifyContent="space-between"
                sx={{ p: 2, borderBottom: 1, borderColor: "divider" }}
              >
                <Box>
                  <Typography variant="subtitle1" fontWeight={800}>
                    查询结果
                  </Typography>
                  <Typography variant="body2" color="text.secondary">
                    {totalCount} 条匹配记录
                  </Typography>
                </Box>
                <Button
                  variant="outlined"
                  startIcon={exporting ? <CircularProgress size={16} /> : <DownloadIcon />}
                  onClick={exportLogs}
                  disabled={exporting || loading}
                  sx={{ minWidth: 116 }}
                >
                  导出 CSV
                </Button>
              </Stack>
              <Box sx={{ height: 3 }}>
                {loading && <LinearProgress sx={{ height: 3 }} />}
              </Box>
              <TableContainer>
                <Table size="small" sx={tableSx}>
                  <TableHead>
                    <TableRow>
                      <TableCell>时间</TableCell>
                      <TableCell>操作者</TableCell>
                      <TableCell>动作</TableCell>
                      <TableCell>资源</TableCell>
                      <TableCell>状态</TableCell>
                      <TableCell>请求</TableCell>
                      <TableCell>IP</TableCell>
                      <TableCell align="right">详情</TableCell>
                    </TableRow>
                  </TableHead>
                  <TableBody>
                    {visibleLogs.length === 0 && (
                      <EmptyRow
                        colSpan={8}
                        label={loading ? "正在加载审计日志" : "暂无审计日志"}
                      />
                    )}
                    {visibleLogs.map((log) => {
                        const user = log.user_id ? userMap.get(log.user_id) : null;
                        return (
                          <TableRow key={log.id} hover>
                            <TableCell sx={{ whiteSpace: "nowrap" }}>
                              {formatDateTime(log.timestamp)}
                            </TableCell>
                            <TableCell>
                              <Stack spacing={0.25}>
                                <Typography variant="body2" fontWeight={700}>
                                  {user?.username ?? "未知用户"}
                                </Typography>
                                <Typography variant="caption" color="text.secondary">
                                  {log.user_id ?? "-"}
                                </Typography>
                              </Stack>
                            </TableCell>
                            <TableCell>
                              <Typography variant="body2" fontWeight={700}>
                                {log.action}
                              </Typography>
                            </TableCell>
                            <TableCell>
                              <Stack spacing={0.25}>
                                <Typography variant="body2">
                                  {log.resource_type ?? "-"}
                                </Typography>
                                <Typography variant="caption" color="text.secondary">
                                  {log.resource_id ?? "-"}
                                </Typography>
                              </Stack>
                            </TableCell>
                            <TableCell>
                              <StatusChip status={log.response_status} />
                            </TableCell>
                            <TableCell>
                              <Stack spacing={0.25} sx={{ maxWidth: 280 }}>
                                <Typography variant="body2" fontWeight={700}>
                                  {log.request_method ?? "-"}
                                </Typography>
                                <Typography variant="caption" color="text.secondary" noWrap>
                                  {log.request_path ?? "-"}
                                </Typography>
                              </Stack>
                            </TableCell>
                            <TableCell>{log.ip_address ?? "-"}</TableCell>
                            <TableCell align="right">
                              <Tooltip title="查看详情">
                                <IconButton size="small" onClick={() => setSelectedLog(log)}>
                                  <VisibilityIcon fontSize="small" />
                                </IconButton>
                              </Tooltip>
                            </TableCell>
                          </TableRow>
                        );
                      })}
                  </TableBody>
                </Table>
              </TableContainer>
              <TablePagination
                component="div"
                count={totalCount}
                page={page}
                onPageChange={(_, nextPage) => setPage(nextPage)}
                rowsPerPage={rowsPerPage}
                onRowsPerPageChange={(event) => {
                  setRowsPerPage(Number(event.target.value));
                  setPage(0);
                }}
                SelectProps={{ MenuProps: selectMenuProps }}
                rowsPerPageOptions={[10, 25, 50, 100]}
                labelRowsPerPage="每页行数"
              />
            </Paper>
          </>
        )}
      </Stack>

      <Dialog
        open={Boolean(selectedLog)}
        onClose={() => setSelectedLog(null)}
        maxWidth="md"
        fullWidth
        disableScrollLock
        transitionDuration={{ enter: 120, exit: 0 }}
      >
        <DialogTitle sx={{ px: 3, py: 2.25, pr: 7 }}>
          <Stack spacing={0.25}>
            <Typography variant="h6" fontWeight={800}>
              审计详情
            </Typography>
            <Typography variant="body2" color="text.secondary">
              {selectedLog ? formatDateTime(selectedLog.timestamp) : ""}
            </Typography>
          </Stack>
          <IconButton
            aria-label="关闭"
            onClick={() => setSelectedLog(null)}
            sx={{ position: "absolute", right: 12, top: 12 }}
          >
            <CloseIcon />
          </IconButton>
        </DialogTitle>
        <DialogContent dividers sx={{ bgcolor: "background.default", p: 2.5 }}>
          {selectedLog && (
            <Stack spacing={2.5}>
              <Paper
                variant="outlined"
                sx={(theme) => ({
                  p: 2,
                  borderRadius: 2,
                  bgcolor: alpha(theme.palette.info.main, 0.05),
                  borderColor: alpha(theme.palette.info.main, 0.2),
                })}
              >
                <Stack
                  direction={{ xs: "column", sm: "row" }}
                  spacing={1.5}
                  alignItems={{ xs: "flex-start", sm: "center" }}
                  justifyContent="space-between"
                >
                  <Stack spacing={0.5} sx={{ minWidth: 0 }}>
                    <Typography variant="caption" color="text.secondary">
                      审计动作
                    </Typography>
                    <Typography variant="h6" fontWeight={800} sx={{ overflowWrap: "anywhere" }}>
                      {selectedLog.action}
                    </Typography>
                    <Typography variant="body2" color="text.secondary" sx={{ overflowWrap: "anywhere" }}>
                      {selectedLog.request_method ?? "-"} {selectedLog.request_path ?? "-"}
                    </Typography>
                  </Stack>
                  <StatusChip status={selectedLog.response_status} />
                </Stack>
              </Paper>

              <DetailSection title="审计主体">
                <DetailLine
                  label="操作者"
                  value={
                    selectedLog.user_id
                      ? userMap.get(selectedLog.user_id)?.username ?? selectedLog.user_id
                      : "-"
                  }
                />
                <DetailLine label="用户 ID" value={selectedLog.user_id ?? "-"} />
                <DetailLine
                  label="项目"
                  value={
                    selectedLog.project_id
                      ? projectMap.get(selectedLog.project_id)?.name ?? selectedLog.project_id
                      : "-"
                  }
                />
                <DetailLine label="项目 ID" value={selectedLog.project_id ?? "-"} />
                <DetailLine label="来源 IP" value={selectedLog.ip_address ?? "-"} />
                <DetailLine label="审计 ID" value={selectedLog.id} />
              </DetailSection>

              <DetailSection title="资源与请求">
                <DetailLine label="资源类型" value={selectedLog.resource_type ?? "-"} />
                <DetailLine label="资源 ID" value={selectedLog.resource_id ?? "-"} />
                <DetailLine label="请求方法" value={selectedLog.request_method ?? "-"} />
                <DetailLine label="请求路径" value={selectedLog.request_path ?? "-"} />
                <DetailLine
                  label="响应状态"
                  value={<StatusChip status={selectedLog.response_status} />}
                />
                <DetailLine label="记录时间" value={formatDateTime(selectedLog.timestamp)} />
              </DetailSection>

              <Paper variant="outlined" sx={{ p: 2, borderRadius: 2 }}>
                <Stack
                  direction="row"
                  alignItems="center"
                  justifyContent="space-between"
                  sx={{ mb: 1.5 }}
                >
                  <Typography variant="subtitle2" fontWeight={800}>
                    请求数据
                  </Typography>
                  <Chip
                    size="small"
                    variant="outlined"
                    label={selectedLog.request_data ? "JSON" : "空对象"}
                  />
                </Stack>
                <Box
                  component="pre"
                  sx={{
                    p: 2,
                    borderRadius: 2,
                    bgcolor: "action.hover",
                    overflow: "auto",
                    fontSize: 13,
                    lineHeight: 1.6,
                    maxHeight: 320,
                    m: 0,
                  }}
                >
                  {selectedLog.request_data
                    ? JSON.stringify(selectedLog.request_data, null, 2)
                    : "{}"}
                </Box>
              </Paper>
            </Stack>
          )}
        </DialogContent>
        <DialogActions sx={{ px: 3, py: 2 }}>
          <Button variant="contained" onClick={() => setSelectedLog(null)}>
            关闭
          </Button>
        </DialogActions>
      </Dialog>
    </Box>
  );
};
