"use client";

import React, {
  FormEvent,
  useCallback,
  useEffect,
  useMemo,
  useRef,
  useState,
} from "react";
import {
  Alert,
  alpha,
  Box,
  Button,
  Chip,
  CircularProgress,
  Divider,
  Dialog,
  DialogActions,
  DialogContent,
  DialogTitle,
  FormControl,
  IconButton,
  InputLabel,
  MenuItem,
  Paper,
  Select,
  Stack,
  Tab,
  Table,
  TableBody,
  TableCell,
  TableContainer,
  TableHead,
  TableRow,
  Tabs,
  TextField,
  Tooltip,
  Typography,
} from "@mui/material";
import {
  Add as AddIcon,
  AdminPanelSettings as AdminPanelSettingsIcon,
  Block as BlockIcon,
  CheckCircle as CheckCircleIcon,
  Close as CloseIcon,
  Dns as DnsIcon,
  Groups as GroupsIcon,
  People as PeopleIcon,
  Refresh as RefreshIcon,
  RemoveCircleOutline as RemoveCircleOutlineIcon,
  Save as SaveIcon,
  Security as SecurityIcon,
  Storage as StorageIcon,
} from "@mui/icons-material";
import { useNotification } from "@refinedev/core";
import { config } from "@config/config";
import { apiFetch } from "@/lib/apiFetch";
import { useProjectStore } from "@/store/projectStore";

type MetadataUser = {
  id: string;
  keycloak_id: string;
  username: string;
  email: string;
  role: string;
  is_active: boolean;
  is_superuser: boolean;
};

type ProjectMember = {
  id: string;
  user_id: string;
  project_id: string;
  project_role: string;
  username: string;
  email: string;
  is_active: boolean;
};

type AdminProject = {
  project_id: string;
  name: string;
  code: string;
  description?: string | null;
  gs_workspace: string;
  map_extent?: Record<string, unknown> | null;
  status: string;
};

type ProjectDatabaseConfig = {
  id: string;
  project_id: string;
  db_role: string;
  db_type: string;
  pool_min_size: number;
  pool_max_size: number;
  has_dsn: boolean;
};

type DatabaseHealth = {
  ok: boolean;
  detail: string;
};

const businessRoleOptions = [
  { value: "admin", label: "系统管理员" },
  { value: "operator", label: "运行人员" },
  { value: "user", label: "普通用户" },
  { value: "viewer", label: "只读用户" },
];

const projectRoleLabels: Record<string, string> = {
  owner: "项目负责人",
  admin: "项目管理员",
  member: "项目成员",
  viewer: "只读成员",
};

const projectRoleOptions = [
  { value: "admin", label: projectRoleLabels.admin },
  { value: "member", label: projectRoleLabels.member },
  { value: "viewer", label: projectRoleLabels.viewer },
];

const projectStatusOptions = [
  { value: "active", label: "启用" },
  { value: "inactive", label: "停用" },
  { value: "archived", label: "归档" },
];

const databaseRoleOptions = [
  { value: "biz_data", label: "业务数据库", helper: "PostgreSQL / 管网业务数据" },
  { value: "iot_data", label: "时序数据库", helper: "TimescaleDB / SCADA 与实时数据" },
] as const;

const defaultProjectForm = {
  name: "",
  code: "",
  description: "",
  gs_workspace: "",
  map_extent: "",
  status: "active",
};

const defaultDatabaseForms = {
  biz_data: {
    dsn: "",
    pool_min_size: 2,
    pool_max_size: 10,
  },
  iot_data: {
    dsn: "",
    pool_min_size: 1,
    pool_max_size: 10,
  },
};

type ProjectFormState = typeof defaultProjectForm;
type DatabaseRole = keyof typeof defaultDatabaseForms;
type DatabaseFormState = (typeof defaultDatabaseForms)[DatabaseRole];

const createDefaultDatabaseForms = () => ({
  biz_data: { ...defaultDatabaseForms.biz_data },
  iot_data: { ...defaultDatabaseForms.iot_data },
});

const createEmptyDatabaseHealth = (): Record<
  DatabaseRole,
  DatabaseHealth | null
> => ({
  biz_data: null,
  iot_data: null,
});

const getBusinessRoleLabel = (role: string) =>
  businessRoleOptions.find((option) => option.value === role)?.label ?? role;

const getProjectRoleLabel = (role: string) =>
  projectRoleLabels[role] ?? role;

const getDatabaseRoleLabel = (role: DatabaseRole) =>
  databaseRoleOptions.find((option) => option.value === role)?.label ?? role;

const formatJsonField = (value?: Record<string, unknown> | null) =>
  value ? JSON.stringify(value, null, 2) : "";

const parseOptionalJsonObject = (value: string, label: string) => {
  const trimmed = value.trim();
  if (!trimmed) return null;
  const parsed = JSON.parse(trimmed);
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
    throw new Error(`${label} 必须是 JSON 对象`);
  }
  return parsed as Record<string, unknown>;
};

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

const isFastApiRouteNotFound = (response: Response, text: string) =>
  response.status === 404 && text.includes('"detail":"Not Found"');

const normalizeDatabaseHealthDetail = (detail: string, ok: boolean) => {
  if (ok) return detail || "连通性测试通过";

  const lowerDetail = detail.toLowerCase();
  if (lowerDetail.includes("password authentication failed")) {
    return "连通性测试失败：用户名或密码错误，请检查 DSN 中的账号密码。";
  }
  if (lowerDetail.includes("connection refused")) {
    return "连通性测试失败：目标主机或端口拒绝连接，请检查地址、端口和服务状态。";
  }
  if (lowerDetail.includes("timeout") || lowerDetail.includes("timed out")) {
    return "连通性测试失败：连接超时，请检查网络、防火墙和数据库服务状态。";
  }
  if (
    lowerDetail.includes("could not translate host name") ||
    lowerDetail.includes("name or service not known")
  ) {
    return "连通性测试失败：数据库主机名无法解析，请检查 DSN 中的主机地址。";
  }
  if (detail.startsWith("数据库连接失败：")) {
    return detail.replace("数据库连接失败：", "连通性测试失败：");
  }
  return detail || "连通性测试失败";
};

const parseDatabaseHealthText = (text: string): DatabaseHealth | null => {
  try {
    const payload = JSON.parse(text);
    if (payload && typeof payload === "object" && "ok" in payload) {
      return {
        ok: Boolean(payload.ok),
        detail: String(payload.detail ?? ""),
      };
    }
  } catch {
    return null;
  }
  return null;
};

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

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

type StatCardProps = {
  icon: React.ReactNode;
  label: string;
  value: string | number;
  tone?: "primary" | "success" | "warning" | "info";
};

const StatCard = ({ icon, label, value, tone = "primary" }: StatCardProps) => (
  <Paper
    variant="outlined"
    sx={(theme) => ({
      ...cardSx,
      p: 2,
      minWidth: 0,
      boxShadow: "none",
      bgcolor: alpha(theme.palette[tone].main, 0.04),
    })}
  >
    <Stack direction="row" spacing={1.5} alignItems="center">
      <Box
        sx={(theme) => ({
          width: 40,
          height: 40,
          borderRadius: 1.5,
          display: "grid",
          placeItems: "center",
          color: `${tone}.main`,
          bgcolor: alpha(theme.palette[tone].main, 0.12),
        })}
      >
        {icon}
      </Box>
      <Box sx={{ minWidth: 0 }}>
        <Typography variant="body2" color="text.secondary" lineHeight={1.2}>
          {label}
        </Typography>
        <Typography variant="h6" fontWeight={800} lineHeight={1.2}>
          {value}
        </Typography>
      </Box>
    </Stack>
  </Paper>
);

const SectionHeader = ({
  title,
  description,
  action,
}: {
  title: string;
  description?: string;
  action?: React.ReactNode;
}) => (
  <Stack
    direction={{ xs: "column", sm: "row" }}
    spacing={1.5}
    alignItems={{ xs: "stretch", sm: "center" }}
    justifyContent="space-between"
  >
    <Box>
      <Typography variant="subtitle1" fontWeight={800}>
        {title}
      </Typography>
      {description && (
        <Typography variant="body2" color="text.secondary">
          {description}
        </Typography>
      )}
    </Box>
    {action}
  </Stack>
);

const StatusChip = ({ active }: { active: boolean }) => (
  <Chip
    size="small"
    color={active ? "success" : "default"}
    icon={active ? <CheckCircleIcon /> : <BlockIcon />}
    label={active ? "启用" : "禁用"}
    variant={active ? "filled" : "outlined"}
    sx={{ minWidth: 76, justifyContent: "flex-start" }}
  />
);

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

type ProjectFormFieldsProps = {
  value: ProjectFormState;
  onChange: (value: ProjectFormState) => void;
  disabled?: boolean;
};

const ProjectFormFields = ({
  value,
  onChange,
  disabled = false,
}: ProjectFormFieldsProps) => {
  const updateField = (field: keyof ProjectFormState, nextValue: string) => {
    onChange({ ...value, [field]: nextValue });
  };

  return (
    <Stack spacing={2}>
      <Stack direction={{ xs: "column", md: "row" }} spacing={1.5}>
        <TextField
          size="small"
          label="项目名称"
          value={value.name}
          onChange={(event) => updateField("name", event.target.value)}
          disabled={disabled}
          required
          fullWidth
        />
        <TextField
          size="small"
          label="项目代码"
          value={value.code}
          onChange={(event) => updateField("code", event.target.value)}
          disabled={disabled}
          required
          fullWidth
        />
      </Stack>
      <Stack direction={{ xs: "column", md: "row" }} spacing={1.5}>
        <TextField
          size="small"
          label="GeoServer 工作区"
          value={value.gs_workspace}
          onChange={(event) => updateField("gs_workspace", event.target.value)}
          disabled={disabled}
          required
          fullWidth
        />
        <FormControl
          size="small"
          sx={{ minWidth: { xs: "100%", md: 160 } }}
          disabled={disabled}
        >
          <InputLabel>状态</InputLabel>
          <Select
            label="状态"
            value={value.status}
            onChange={(event) => updateField("status", event.target.value)}
          >
            {projectStatusOptions.map((option) => (
              <MenuItem key={option.value} value={option.value}>
                {option.label}
              </MenuItem>
            ))}
          </Select>
        </FormControl>
      </Stack>
      <TextField
        size="small"
        label="描述"
        value={value.description}
        onChange={(event) => updateField("description", event.target.value)}
        disabled={disabled}
        fullWidth
        multiline
        minRows={2}
      />
      <TextField
        size="small"
        label="地图范围 JSON"
        value={value.map_extent}
        onChange={(event) => updateField("map_extent", event.target.value)}
        disabled={disabled}
        fullWidth
        multiline
        minRows={4}
        placeholder='{"bbox":[120.1,30.1,120.2,30.2]}'
      />
    </Stack>
  );
};

export const SystemAdminPanel = () => {
  const { open: openNotification } = useNotification();
  const openNotificationRef = useRef(openNotification);
  const currentProjectId = useProjectStore((state) => state.currentProjectId);
  const [tab, setTab] = useState(0);
  const [users, setUsers] = useState<MetadataUser[]>([]);
  const [members, setMembers] = useState<ProjectMember[]>([]);
  const [projects, setProjects] = useState<AdminProject[]>([]);
  const [databases, setDatabases] = useState<ProjectDatabaseConfig[]>([]);
  const [currentAdmin, setCurrentAdmin] = useState<MetadataUser | null>(null);
  const [adminChecked, setAdminChecked] = useState(false);
  const [isAuthorized, setIsAuthorized] = useState(false);
  const [metadataConfigAvailable, setMetadataConfigAvailable] = useState(true);
  const [projectId, setProjectId] = useState(currentProjectId ?? "");
  const [memberForm, setMemberForm] = useState({
    user_id: "",
    project_role: "viewer",
  });
  const [projectForm, setProjectForm] = useState(defaultProjectForm);
  const [createProjectOpen, setCreateProjectOpen] = useState(false);
  const [createProjectForm, setCreateProjectForm] = useState(defaultProjectForm);
  const [databaseForms, setDatabaseForms] = useState(createDefaultDatabaseForms);
  const [databaseHealth, setDatabaseHealth] = useState(createEmptyDatabaseHealth);

  useEffect(() => {
    openNotificationRef.current = openNotification;
  }, [openNotification]);

  const notifySuccess = useCallback(
    (message: string) => {
      openNotificationRef.current?.({ type: "success", message });
    },
    [],
  );

  const notifyError = useCallback(
    (message: string) => {
      openNotificationRef.current?.({ type: "error", message });
    },
    [],
  );

  const userStats = useMemo(
    () =>
      users.reduce(
        (stats, user) => ({
          active: stats.active + Number(user.is_active),
          systemAdmins: stats.systemAdmins + Number(user.role === "admin"),
          superusers: stats.superusers + Number(user.is_superuser),
        }),
        { active: 0, systemAdmins: 0, superusers: 0 },
      ),
    [users],
  );
  const memberUserIds = useMemo(
    () => new Set(members.map((member) => member.user_id)),
    [members],
  );
  const availableMemberUsers = useMemo(
    () =>
      users.filter(
        (user) =>
          user.is_active &&
          !user.is_superuser &&
          user.id !== currentAdmin?.id &&
          !memberUserIds.has(user.id),
      ),
    [currentAdmin?.id, memberUserIds, users],
  );
  const selectedMemberUser = useMemo(
    () => users.find((user) => user.id === memberForm.user_id),
    [memberForm.user_id, users],
  );
  const hasProjectId = Boolean(projectId.trim());
  const selectedProject = useMemo(
    () => projects.find((project) => project.project_id === projectId.trim()),
    [projectId, projects],
  );
  const databasesByRole = useMemo(
    () =>
      new Map(
        databases.map((database) => [database.db_role, database] as const),
      ),
    [databases],
  );

  const loadUsers = useCallback(async () => {
    const response = await apiFetch(`${config.BACKEND_URL}/api/v1/admin/users`);
    if (!response.ok) {
      throw new Error(await readErrorText(response));
    }
    setUsers(await response.json());
  }, []);

  const applyProjectForm = useCallback((project: AdminProject | null) => {
    if (!project) {
      setProjectForm(defaultProjectForm);
      return;
    }
    setProjectForm({
      name: project.name ?? "",
      code: project.code ?? "",
      description: project.description ?? "",
      gs_workspace: project.gs_workspace ?? "",
      map_extent: formatJsonField(project.map_extent),
      status: project.status || "active",
    });
  }, []);

  const loadProjects = useCallback(async (preferredProjectId?: string) => {
    const response = await apiFetch(`${config.BACKEND_URL}/api/v1/admin/projects`);
    if (!response.ok) {
      const errorText = await readErrorText(response);
      if (isFastApiRouteNotFound(response, errorText)) {
        setMetadataConfigAvailable(false);
        setProjects([]);
        return;
      }
      throw new Error(errorText);
    }
    setMetadataConfigAvailable(true);
    const payload = (await response.json()) as AdminProject[];
    setProjects(payload);
    const activeProjectId =
      preferredProjectId ||
      projectId.trim() ||
      currentProjectId ||
      payload[0]?.project_id ||
      "";
    if (activeProjectId && !projectId.trim()) {
      setProjectId(activeProjectId);
    }
  }, [currentProjectId, projectId]);

  const loadMembers = useCallback(async () => {
    if (!projectId.trim()) return;
    const response = await apiFetch(
      `${config.BACKEND_URL}/api/v1/admin/projects/${projectId.trim()}/members`,
    );
    if (!response.ok) {
      throw new Error(await readErrorText(response));
    }
    setMembers(await response.json());
  }, [projectId]);

  const loadDatabases = useCallback(async () => {
    if (!projectId.trim()) return;
    setDatabaseHealth(createEmptyDatabaseHealth());
    const response = await apiFetch(
      `${config.BACKEND_URL}/api/v1/admin/projects/${projectId.trim()}/databases`,
    );
    if (!response.ok) {
      const errorText = await readErrorText(response);
      if (isFastApiRouteNotFound(response, errorText)) {
        setMetadataConfigAvailable(false);
        setDatabases([]);
        return;
      }
      throw new Error(errorText);
    }
    setMetadataConfigAvailable(true);
    const payload = (await response.json()) as ProjectDatabaseConfig[];
    setDatabases(payload);
    setDatabaseForms((current) => {
      const next = createDefaultDatabaseForms();
      for (const database of payload) {
        const role = database.db_role as keyof typeof defaultDatabaseForms;
        if (role in next) {
          next[role] = {
            ...current[role],
            dsn: "",
            pool_min_size: database.pool_min_size,
            pool_max_size: database.pool_max_size,
          };
        }
      }
      return next;
    });
  }, [projectId]);

  useEffect(() => {
    let cancelled = false;

    const loadInitialState = async () => {
      try {
        const adminResponse = await apiFetch(`${config.BACKEND_URL}/api/v1/admin/me`, {
          projectHeaderMode: "omit",
          skipAuthRedirect: true,
        });
        if (!adminResponse.ok) {
          if (!cancelled) {
            setIsAuthorized(false);
            setCurrentAdmin(null);
            setAdminChecked(true);
          }
          return;
        }
        const adminPayload = await adminResponse.json();
        if (!cancelled) {
          setCurrentAdmin(adminPayload);
          setIsAuthorized(true);
          setAdminChecked(true);
        }

        const usersResponse = await apiFetch(`${config.BACKEND_URL}/api/v1/admin/users`);
        if (!usersResponse.ok) {
          throw new Error(await readErrorText(usersResponse));
        }
        const payload = await usersResponse.json();
        if (!cancelled) setUsers(payload);

        const projectsResponse = await apiFetch(`${config.BACKEND_URL}/api/v1/admin/projects`);
        if (!projectsResponse.ok) {
          const errorText = await readErrorText(projectsResponse);
          if (isFastApiRouteNotFound(projectsResponse, errorText)) {
            if (!cancelled) {
              setMetadataConfigAvailable(false);
              setProjects([]);
            }
            return;
          }
          throw new Error(errorText);
        }
        if (!cancelled) setMetadataConfigAvailable(true);
        const projectsPayload = (await projectsResponse.json()) as AdminProject[];
        if (!cancelled) {
          setProjects(projectsPayload);
          const initialProjectId =
            currentProjectId || projectsPayload[0]?.project_id || "";
          setProjectId((current) =>
            current.trim() || !initialProjectId ? current : initialProjectId,
          );
        }
      } catch (err) {
        if (!cancelled) {
          setAdminChecked(true);
          notifyError(String(err));
        }
      }
    };

    void loadInitialState();

    return () => {
      cancelled = true;
    };
  }, [currentProjectId, notifyError]);

  useEffect(() => {
    if (!currentProjectId || projectId.trim()) return;
    setProjectId(currentProjectId);
  }, [currentProjectId, projectId]);

  useEffect(() => {
    if (!isAuthorized || !hasProjectId) return;
    loadMembers().catch((err) => notifyError(String(err)));
  }, [hasProjectId, isAuthorized, loadMembers, notifyError]);

  useEffect(() => {
    applyProjectForm(selectedProject ?? null);
  }, [applyProjectForm, selectedProject]);

  useEffect(() => {
    if (!isAuthorized || !hasProjectId || !metadataConfigAvailable) return;
    loadDatabases().catch((err) => notifyError(String(err)));
  }, [
    hasProjectId,
    isAuthorized,
    loadDatabases,
    metadataConfigAvailable,
    notifyError,
  ]);

  useEffect(() => {
    if (!metadataConfigAvailable && tab !== 3) {
      setTab(3);
    }
  }, [metadataConfigAvailable, tab]);

  const updateUserActive = async (user: MetadataUser, isActive: boolean) => {
    const response = await apiFetch(
      `${config.BACKEND_URL}/api/v1/admin/users/${user.id}`,
      {
        method: "PATCH",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ is_active: isActive }),
      },
    );
    if (!response.ok) {
      notifyError(await readErrorText(response));
      return;
    }
    await loadUsers();
  };

  const updateUserRole = async (user: MetadataUser, role: string) => {
    const response = await apiFetch(
      `${config.BACKEND_URL}/api/v1/admin/users/${user.id}`,
      {
        method: "PATCH",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ role }),
      },
    );
    if (!response.ok) {
      notifyError(await readErrorText(response));
      return;
    }
    await loadUsers();
  };

  const addMember = async (event: FormEvent) => {
    event.preventDefault();
    const response = await apiFetch(
      `${config.BACKEND_URL}/api/v1/admin/projects/${projectId.trim()}/members`,
      {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify(memberForm),
      },
    );
    if (!response.ok) {
      notifyError(await readErrorText(response));
      return;
    }
    notifySuccess("项目成员已添加");
    setMemberForm((prev) => ({ ...prev, user_id: "" }));
    await loadMembers();
  };

  const updateMemberRole = async (member: ProjectMember, projectRole: string) => {
    const response = await apiFetch(
      `${config.BACKEND_URL}/api/v1/admin/projects/${member.project_id}/members/${member.user_id}`,
      {
        method: "PATCH",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ project_role: projectRole }),
      },
    );
    if (!response.ok) {
      notifyError(await readErrorText(response));
      return;
    }
    await loadMembers();
  };

  const removeMember = async (member: ProjectMember) => {
    const response = await apiFetch(
      `${config.BACKEND_URL}/api/v1/admin/projects/${member.project_id}/members/${member.user_id}`,
      { method: "DELETE" },
    );
    if (!response.ok) {
      notifyError(await readErrorText(response));
      return;
    }
    notifySuccess("项目成员已移除");
    await loadMembers();
  };

  const startNewProject = () => {
    setCreateProjectForm(defaultProjectForm);
    setCreateProjectOpen(true);
  };

  const selectProject = (value: string) => {
    setProjectId(value);
    setMembers([]);
    setDatabases([]);
    setDatabaseForms(createDefaultDatabaseForms());
    setDatabaseHealth(createEmptyDatabaseHealth());
  };

  const updateDatabaseForm = <Field extends keyof DatabaseFormState>(
    role: DatabaseRole,
    field: Field,
    value: DatabaseFormState[Field],
  ) => {
    setDatabaseHealth((current) => ({ ...current, [role]: null }));
    setDatabaseForms((current) => ({
      ...current,
      [role]: { ...current[role], [field]: value },
    }));
  };

  const buildProjectPayload = (form: ProjectFormState) => ({
    name: form.name.trim(),
    code: form.code.trim(),
    description: form.description.trim() || null,
    gs_workspace: form.gs_workspace.trim(),
    map_extent: parseOptionalJsonObject(form.map_extent, "地图范围"),
    status: form.status,
  });

  const saveProject = async (event: FormEvent) => {
    event.preventDefault();
    if (!selectedProject?.project_id) {
      notifyError("请先选择要编辑的项目。");
      return;
    }
    try {
      const response = await apiFetch(
        `${config.BACKEND_URL}/api/v1/admin/projects/${selectedProject.project_id}`,
        {
          method: "PATCH",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify(buildProjectPayload(projectForm)),
        },
      );
      if (!response.ok) {
        throw new Error(await readErrorText(response));
      }
      const saved = (await response.json()) as AdminProject;
      setProjectId(saved.project_id);
      await loadProjects(saved.project_id);
      notifySuccess("项目配置已更新");
    } catch (err) {
      notifyError(String(err));
    }
  };

  const createProject = async (event: FormEvent) => {
    event.preventDefault();
    try {
      const response = await apiFetch(`${config.BACKEND_URL}/api/v1/admin/projects`, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify(buildProjectPayload(createProjectForm)),
      });
      if (!response.ok) {
        throw new Error(await readErrorText(response));
      }
      const saved = (await response.json()) as AdminProject;
      setCreateProjectOpen(false);
      setCreateProjectForm(defaultProjectForm);
      setProjectId(saved.project_id);
      await loadProjects(saved.project_id);
      notifySuccess("项目已创建");
    } catch (err) {
      notifyError(String(err));
    }
  };

  const saveDatabase = async (role: DatabaseRole) => {
    if (!projectId.trim()) return;
    const form = databaseForms[role];
    if (!form.dsn.trim()) {
      notifyError("请填写新的 DSN 并通过连通性测试后再保存。");
      return;
    }
    if (!databaseHealth[role]?.ok) {
      notifyError("请先通过连通性测试再保存数据库配置。");
      return;
    }
    const payload: Record<string, unknown> = {
      db_role: role,
      pool_min_size: Number(form.pool_min_size),
      pool_max_size: Number(form.pool_max_size),
    };
    if (form.dsn.trim()) {
      payload.dsn = form.dsn.trim();
    }
    const response = await apiFetch(
      `${config.BACKEND_URL}/api/v1/admin/projects/${projectId.trim()}/databases`,
      {
        method: "PUT",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify(payload),
      },
    );
    if (!response.ok) {
      const errorText = await readErrorText(response);
      if (isFastApiRouteNotFound(response, errorText)) {
        setMetadataConfigAvailable(false);
        return;
      }
      notifyError(errorText);
      return;
    }
    setDatabaseForms((current) => ({
      ...current,
      [role]: { ...current[role], dsn: "" },
    }));
    notifySuccess(`${getDatabaseRoleLabel(role)}已保存`);
    await loadDatabases();
  };

  const checkDatabaseHealth = async (role: DatabaseRole) => {
    if (!projectId.trim()) return;
    setDatabaseHealth((current) => ({ ...current, [role]: null }));
    const form = databaseForms[role];
    const body = form.dsn.trim() ? { dsn: form.dsn.trim() } : {};
    const response = await apiFetch(
      `${config.BACKEND_URL}/api/v1/admin/projects/${projectId.trim()}/databases/${role}/health`,
      {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify(body),
      },
    );
    if (!response.ok) {
      const errorText = await readErrorText(response);
      if (isFastApiRouteNotFound(response, errorText)) {
        setMetadataConfigAvailable(false);
        return;
      }
      const healthPayload = parseDatabaseHealthText(errorText);
      if (healthPayload) {
        setDatabaseHealth((current) => ({
          ...current,
          [role]: {
            ...healthPayload,
            detail: normalizeDatabaseHealthDetail(
              healthPayload.detail,
              healthPayload.ok,
            ),
          },
        }));
        return;
      }
      notifyError(normalizeDatabaseHealthDetail(errorText, false));
      return;
    }
    const payload = (await response.json()) as DatabaseHealth;
    setDatabaseHealth((current) => ({
      ...current,
      [role]: {
        ...payload,
        detail: normalizeDatabaseHealthDetail(payload.detail, payload.ok),
      },
    }));
  };

  const deleteDatabase = async (role: DatabaseRole) => {
    if (!projectId.trim()) return;
    const response = await apiFetch(
      `${config.BACKEND_URL}/api/v1/admin/projects/${projectId.trim()}/databases/${role}`,
      { method: "DELETE" },
    );
    if (!response.ok) {
      const errorText = await readErrorText(response);
      if (isFastApiRouteNotFound(response, errorText)) {
        setMetadataConfigAvailable(false);
        return;
      }
      notifyError(errorText);
      return;
    }
    notifySuccess(`${getDatabaseRoleLabel(role)}配置已删除`);
    await loadDatabases();
  };

  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.primary.main, 0.1)
                : alpha(theme.palette.primary.main, 0.04),
          })}
        >
          <Stack direction="row" spacing={1.5} alignItems="center">
            <Box
              sx={(theme) => ({
                width: 48,
                height: 48,
                borderRadius: 2,
                display: "grid",
                placeItems: "center",
                color: "primary.main",
                bgcolor: alpha(theme.palette.primary.main, 0.12),
                flexShrink: 0,
              })}
            >
              <SecurityIcon />
            </Box>
            <Box>
              <Typography variant="h5" fontWeight={800}>
                系统管理
              </Typography>
              <Typography variant="body2" color="text.secondary">
                管理系统用户、项目权限和数据库连接
              </Typography>
            </Box>
          </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>
        )}
        {isAuthorized && !metadataConfigAvailable && (
          <Alert severity="warning" sx={{ borderRadius: 2 }}>
            后端尚未启用项目配置接口，请重启或部署包含 /api/v1/admin/projects 的后端后再使用项目配置和数据库配置。
          </Alert>
        )}

        {isAuthorized && (
          <>
            <Box
              sx={{
                display: "grid",
                gridTemplateColumns: {
                  xs: "repeat(2, minmax(0, 1fr))",
                  md: "repeat(3, minmax(0, 1fr))",
                  xl: "repeat(6, minmax(0, 1fr))",
                },
                gap: 2,
              }}
            >
              <StatCard
                icon={<PeopleIcon />}
                label="系统用户"
                value={users.length}
              />
              <StatCard
                icon={<CheckCircleIcon />}
                label="启用用户"
                value={userStats.active}
                tone="success"
              />
              <StatCard
                icon={<AdminPanelSettingsIcon />}
                label="系统管理员"
                value={userStats.systemAdmins}
                tone="warning"
              />
              <StatCard
                icon={<SecurityIcon />}
                label="超级管理员"
                value={userStats.superusers}
                tone="info"
              />
              <StatCard
                icon={<GroupsIcon />}
                label="当前项目成员"
                value={hasProjectId ? members.length : "-"}
                tone="info"
              />
              <StatCard
                icon={<DnsIcon />}
                label="系统项目"
                value={projects.length}
                tone="primary"
              />
            </Box>

            {metadataConfigAvailable && (
              <Paper variant="outlined" sx={{ ...cardSx, p: 2 }}>
                <Stack
                  direction={{ xs: "column", md: "row" }}
                  spacing={2}
                  alignItems={{ xs: "stretch", md: "center" }}
                  justifyContent="space-between"
                >
                  <Box sx={{ minWidth: 0 }}>
                    <Typography variant="subtitle2" fontWeight={800}>
                      当前管理项目
                    </Typography>
                    <Typography variant="body2" color="text.secondary" noWrap>
                      {selectedProject
                        ? `${selectedProject.name} / ${selectedProject.code}`
                        : "未选择项目"}
                    </Typography>
                  </Box>
                  <Stack direction={{ xs: "column", sm: "row" }} spacing={1}>
                    <FormControl size="small" sx={{ minWidth: { xs: "100%", sm: 280 } }}>
                      <InputLabel>选择项目</InputLabel>
                      <Select
                        label="选择项目"
                        value={selectedProject?.project_id ?? ""}
                        onChange={(event) => selectProject(event.target.value)}
                      >
                        {projects.length === 0 && (
                          <MenuItem value="" disabled>
                            暂无项目
                          </MenuItem>
                        )}
                        {projects.map((project) => (
                          <MenuItem key={project.project_id} value={project.project_id}>
                            {project.name} / {project.code}
                          </MenuItem>
                        ))}
                      </Select>
                    </FormControl>
                    <Button
                      startIcon={<RefreshIcon />}
                      variant="outlined"
                      onClick={() => loadProjects()}
                    >
                      刷新项目
                    </Button>
                    <Button
                      startIcon={<AddIcon />}
                      variant="contained"
                      onClick={startNewProject}
                    >
                      新建项目
                    </Button>
                  </Stack>
                </Stack>
              </Paper>
            )}

            <Paper variant="outlined" sx={{ ...cardSx, overflow: "hidden" }}>
              <Tabs
                value={tab}
                onChange={(_, value) => setTab(value)}
                variant="scrollable"
                scrollButtons="auto"
                sx={{
                  px: 2,
                  minHeight: 56,
                  borderBottom: 1,
                  borderColor: "divider",
                  "& .MuiTab-root": {
                    minHeight: 56,
                    textTransform: "none",
                    fontWeight: 700,
                  },
                }}
              >
                <Tab
                  icon={<GroupsIcon />}
                  iconPosition="start"
                  label="项目成员"
                  disabled={!metadataConfigAvailable}
                />
                <Tab
                  icon={<DnsIcon />}
                  iconPosition="start"
                  label="项目配置"
                  disabled={!metadataConfigAvailable}
                />
                <Tab
                  icon={<StorageIcon />}
                  iconPosition="start"
                  label="数据库配置"
                  disabled={!metadataConfigAvailable}
                />
                <Tab icon={<PeopleIcon />} iconPosition="start" label="系统用户" />
              </Tabs>

              <Box sx={{ p: { xs: 2, md: 2.5 } }}>
                {tab === 3 && (
                  <Stack spacing={2}>
                    <SectionHeader
                      title="系统用户"
                      description="Keycloak 信息只读展示；这里维护系统角色和启用状态。超级管理员由后台初始化或受控脚本设置，不在页面修改。"
                      action={
                        <Button startIcon={<RefreshIcon />} variant="outlined" onClick={loadUsers}>
                          刷新
                        </Button>
                      }
                    />
                    <TableContainer component={Paper} variant="outlined" sx={{ borderRadius: 2 }}>
                      <Table size="small" sx={tableSx}>
                        <TableHead>
                          <TableRow>
                            <TableCell>用户身份</TableCell>
                            <TableCell>系统角色</TableCell>
                            <TableCell>超级权限</TableCell>
                            <TableCell>状态</TableCell>
                            <TableCell align="right">操作</TableCell>
                          </TableRow>
                        </TableHead>
                        <TableBody>
                          {users.length === 0 && <EmptyRow colSpan={5} label="暂无用户数据" />}
                          {users.map((user) => {
                            const isSelf = user.id === currentAdmin?.id;
                            const protectedUserReason = isSelf
                              ? "不能操作当前登录用户"
                              : user.is_superuser
                                ? "超级管理员权限独立于系统角色，需后台设置"
                                : "";

                            return (
                              <TableRow key={user.id} hover>
                                <TableCell>
                                  <Stack spacing={0.25}>
                                    <Stack direction="row" spacing={1} alignItems="center">
                                      <Typography fontWeight={700}>{user.username}</Typography>
                                      {isSelf && (
                                        <Chip size="small" color="info" label="当前用户" />
                                      )}
                                    </Stack>
                                    <Typography variant="body2" color="text.secondary">
                                      {user.email}
                                    </Typography>
                                    <Typography variant="caption" color="text.secondary">
                                      {user.keycloak_id}
                                    </Typography>
                                  </Stack>
                                </TableCell>
                                <TableCell>
                                  <Tooltip title={protectedUserReason}>
                                    <span>
                                      <FormControl
                                        size="small"
                                        sx={{ minWidth: 150 }}
                                        disabled={user.is_superuser || isSelf}
                                      >
                                        <Select
                                          value={user.role}
                                          onChange={(e) => updateUserRole(user, e.target.value)}
                                          renderValue={(value) =>
                                            getBusinessRoleLabel(String(value))
                                          }
                                        >
                                          {businessRoleOptions.map((role) => (
                                            <MenuItem key={role.value} value={role.value}>
                                              {role.label}
                                            </MenuItem>
                                          ))}
                                        </Select>
                                      </FormControl>
                                    </span>
                                  </Tooltip>
                                </TableCell>
                                <TableCell>
                                  {user.is_superuser ? (
                                    <Chip
                                      size="small"
                                      color="warning"
                                      icon={<SecurityIcon />}
                                      label="超级管理员"
                                    />
                                  ) : (
                                    <Chip size="small" label="无" variant="outlined" />
                                  )}
                                </TableCell>
                                <TableCell>
                                  <StatusChip active={user.is_active} />
                                </TableCell>
                                <TableCell align="right">
                                  <Tooltip
                                    title={
                                      isSelf
                                        ? "不能操作当前登录用户"
                                        : user.is_superuser
                                          ? "超级管理员不可禁用"
                                          : ""
                                    }
                                  >
                                    <span>
                                      <Button
                                        size="small"
                                        variant="outlined"
                                        color={user.is_active ? "warning" : "success"}
                                        onClick={() => updateUserActive(user, !user.is_active)}
                                        disabled={user.is_superuser || isSelf}
                                      >
                                        {user.is_active ? "禁用" : "启用"}
                                      </Button>
                                    </span>
                                  </Tooltip>
                                </TableCell>
                              </TableRow>
                            );
                          })}
                        </TableBody>
                      </Table>
                    </TableContainer>
                  </Stack>
                )}

                {tab === 0 && (
                  <Stack spacing={2}>
                    <SectionHeader
                      title="项目成员"
                      description="维护当前项目内权限；此处只管理项目管理员、项目成员和只读成员，项目负责人另行维护。"
                      action={
                        <Button
                          variant="outlined"
                          startIcon={<RefreshIcon />}
                          onClick={loadMembers}
                          disabled={!hasProjectId}
                        >
                          刷新成员
                        </Button>
                      }
                    />
                    {!hasProjectId && (
                      <Alert severity="warning" sx={{ borderRadius: 2 }}>
                        当前未选择管理项目。
                      </Alert>
                    )}
                    <Paper
                      component="form"
                      variant="outlined"
                      sx={{ p: 2, borderRadius: 2, bgcolor: "action.hover" }}
                      onSubmit={addMember}
                    >
                      <Stack spacing={1.5}>
                        <Typography variant="subtitle2" fontWeight={800}>
                          添加成员
                        </Typography>
                        <Stack
                          direction="row"
                          spacing={1.5}
                          useFlexGap
                          flexWrap="wrap"
                          alignItems="center"
                        >
                          <FormControl
                            size="small"
                            disabled={!hasProjectId}
                            sx={{
                              width: { xs: "100%", sm: 320, md: 360 },
                              flexShrink: 0,
                            }}
                          >
                            <InputLabel>选择用户</InputLabel>
                            <Select
                              label="选择用户"
                              value={memberForm.user_id}
                              onChange={(e) =>
                                setMemberForm({ ...memberForm, user_id: e.target.value })
                              }
                              renderValue={() => selectedMemberUser?.username ?? ""}
                              required
                            >
                              {availableMemberUsers.length === 0 && (
                                <MenuItem value="" disabled>
                                  暂无可添加用户
                                </MenuItem>
                              )}
                              {availableMemberUsers.map((user) => (
                                <MenuItem key={user.id} value={user.id}>
                                  <Stack spacing={0.25} sx={{ minWidth: 0 }}>
                                    <Typography variant="body2" fontWeight={700} noWrap>
                                      {user.username}
                                    </Typography>
                                    <Typography
                                      variant="caption"
                                      color="text.secondary"
                                      noWrap
                                    >
                                      {user.email}
                                    </Typography>
                                  </Stack>
                                </MenuItem>
                              ))}
                            </Select>
                          </FormControl>
                          <FormControl
                            size="small"
                            sx={{ width: { xs: "calc(50% - 6px)", sm: 160 } }}
                            disabled={!hasProjectId}
                          >
                            <InputLabel>项目角色</InputLabel>
                            <Select
                              label="项目角色"
                              value={memberForm.project_role}
                              onChange={(e) =>
                                setMemberForm({ ...memberForm, project_role: e.target.value })
                              }
                            >
                              {projectRoleOptions.map((role) => (
                                <MenuItem key={role.value} value={role.value}>
                                  {role.label}
                                </MenuItem>
                              ))}
                            </Select>
                          </FormControl>
                          <Button
                            type="submit"
                            variant="contained"
                            startIcon={<AddIcon />}
                            disabled={!hasProjectId || !memberForm.user_id}
                            sx={{
                              width: { xs: "calc(50% - 6px)", sm: "auto" },
                              minWidth: 120,
                            }}
                          >
                            添加成员
                          </Button>
                        </Stack>
                      </Stack>
                    </Paper>
                    <TableContainer component={Paper} variant="outlined" sx={{ borderRadius: 2 }}>
                      <Table size="small" sx={tableSx}>
                        <TableHead>
                          <TableRow>
                            <TableCell>用户</TableCell>
                            <TableCell>邮箱</TableCell>
                            <TableCell>项目角色</TableCell>
                            <TableCell>状态</TableCell>
                            <TableCell align="right">操作</TableCell>
                          </TableRow>
                        </TableHead>
                        <TableBody>
                          {members.length === 0 && (
                            <EmptyRow colSpan={5} label="暂无项目成员数据" />
                          )}
                          {members.map((member) => {
                            const isSelf = member.user_id === currentAdmin?.id;
                            const isOwner = member.project_role === "owner";

                            return (
                              <TableRow key={member.id} hover>
                                <TableCell>
                                  <Stack spacing={0.25}>
                                    <Stack direction="row" spacing={1} alignItems="center">
                                      <Typography fontWeight={700}>{member.username}</Typography>
                                      {isSelf && (
                                        <Chip size="small" color="info" label="当前用户" />
                                      )}
                                    </Stack>
                                    <Typography variant="caption" color="text.secondary">
                                      {member.user_id}
                                    </Typography>
                                  </Stack>
                                </TableCell>
                                <TableCell>{member.email}</TableCell>
                                <TableCell>
                                  {isOwner ? (
                                    <Tooltip title="项目负责人不在系统管理页维护">
                                      <Chip
                                        size="small"
                                        color="warning"
                                        label={getProjectRoleLabel(member.project_role)}
                                      />
                                    </Tooltip>
                                  ) : (
                                    <Tooltip title={isSelf ? "不能操作当前登录用户" : ""}>
                                      <span>
                                        <FormControl
                                          size="small"
                                          sx={{ minWidth: 140 }}
                                          disabled={isSelf}
                                        >
                                          <Select
                                            value={member.project_role}
                                            onChange={(e) =>
                                              updateMemberRole(member, e.target.value)
                                            }
                                            renderValue={(value) =>
                                              getProjectRoleLabel(String(value))
                                            }
                                          >
                                            {projectRoleOptions.map((role) => (
                                              <MenuItem key={role.value} value={role.value}>
                                                {role.label}
                                              </MenuItem>
                                            ))}
                                          </Select>
                                        </FormControl>
                                      </span>
                                    </Tooltip>
                                  )}
                                </TableCell>
                                <TableCell>
                                  <StatusChip active={member.is_active} />
                                </TableCell>
                                <TableCell align="right">
                                  <Tooltip
                                    title={
                                      isSelf
                                        ? "不能操作当前登录用户"
                                        : isOwner
                                          ? "项目负责人不在系统管理页维护"
                                          : ""
                                    }
                                  >
                                    <span>
                                      <Button
                                        size="small"
                                        color="error"
                                        variant="outlined"
                                        startIcon={<RemoveCircleOutlineIcon />}
                                        onClick={() => removeMember(member)}
                                        disabled={isSelf || isOwner}
                                      >
                                        移除
                                      </Button>
                                    </span>
                                  </Tooltip>
                                </TableCell>
                              </TableRow>
                            );
                          })}
                        </TableBody>
                      </Table>
                    </TableContainer>
                  </Stack>
                )}

                {tab === 1 && (
                  <Stack spacing={2}>
                    <SectionHeader
                      title="项目配置"
                      description="维护项目基础信息、GeoServer 工作区、地图范围和项目状态。"
                      action={
                        <Button
                          startIcon={<RefreshIcon />}
                          variant="outlined"
                          onClick={() => loadProjects()}
                        >
                          刷新
                        </Button>
                      }
                    />
                    {!selectedProject && (
                      <Alert severity="warning" sx={{ borderRadius: 2 }}>
                        当前未选择管理项目。请在页面顶部选择项目，或使用“新建项目”创建项目。
                      </Alert>
                    )}
                    <Paper
                      component="form"
                      variant="outlined"
                      sx={{ p: 2, borderRadius: 2 }}
                      onSubmit={saveProject}
                    >
                      <Stack spacing={2}>
                        <ProjectFormFields
                          value={projectForm}
                          onChange={setProjectForm}
                          disabled={!selectedProject}
                        />
                        <Stack direction="row" justifyContent="flex-end">
                          <Button
                            type="submit"
                            variant="contained"
                            startIcon={<SaveIcon />}
                            disabled={!selectedProject}
                          >
                            保存项目
                          </Button>
                        </Stack>
                      </Stack>
                    </Paper>
                  </Stack>
                )}

                {tab === 2 && (
                  <Stack spacing={2}>
                    <SectionHeader
                      title="项目数据库配置"
                      description="配置当前管理项目的 biz_data 和 iot_data 路由；填写或修改后先测试连通性，通过后才能保存。"
                      action={
                        <Button
                          startIcon={<RefreshIcon />}
                          variant="outlined"
                          onClick={loadDatabases}
                          disabled={!hasProjectId}
                        >
                          刷新配置
                        </Button>
                      }
                    />
                    {!hasProjectId && (
                      <Alert severity="warning" sx={{ borderRadius: 2 }}>
                        当前未选择管理项目。
                      </Alert>
                    )}
                    {hasProjectId &&
                      databaseRoleOptions.map((roleOption) => {
                        const role = roleOption.value;
                        const form = databaseForms[role];
                        const configRecord = databasesByRole.get(role);
                        const health = databaseHealth[role];

                        return (
                          <Paper key={role} variant="outlined" sx={{ p: 2, borderRadius: 2 }}>
                            <Stack spacing={2}>
                              <Stack
                                direction={{ xs: "column", md: "row" }}
                                spacing={1}
                                alignItems={{ xs: "stretch", md: "center" }}
                                justifyContent="space-between"
                              >
                                <Box>
                                  <Typography variant="subtitle2" fontWeight={800}>
                                    {roleOption.label}
                                  </Typography>
                                  <Typography variant="body2" color="text.secondary">
                                    {roleOption.helper}
                                  </Typography>
                                </Box>
                                <Chip
                                  color={configRecord?.has_dsn ? "success" : "default"}
                                  label={configRecord?.has_dsn ? "DSN 已配置" : "未配置 DSN"}
                                  sx={{ alignSelf: { xs: "flex-start", md: "center" } }}
                                />
                              </Stack>
                              <Stack direction={{ xs: "column", md: "row" }} spacing={1.5}>
                                <TextField
                                  size="small"
                                  type="password"
                                  label={configRecord?.has_dsn ? "替换 DSN" : "DSN"}
                                  value={form.dsn}
                                  onChange={(event) =>
                                    updateDatabaseForm(role, "dsn", event.target.value)
                                  }
                                  placeholder="postgresql://user:password@host:5432/db"
                                  helperText={
                                    configRecord?.has_dsn
                                      ? "填写新 DSN 后测试新连接，通过后才能保存；留空只测试已保存 DSN。"
                                      : "首次保存前必须填写 DSN 并通过连通性测试。"
                                  }
                                  fullWidth
                                />
                                <TextField
                                  size="small"
                                  type="number"
                                  label="最小连接"
                                  value={form.pool_min_size}
                                  onChange={(event) =>
                                    updateDatabaseForm(
                                      role,
                                      "pool_min_size",
                                      Number(event.target.value),
                                    )
                                  }
                                  sx={{ width: { xs: "100%", md: 120 } }}
                                />
                                <TextField
                                  size="small"
                                  type="number"
                                  label="最大连接"
                                  value={form.pool_max_size}
                                  onChange={(event) =>
                                    updateDatabaseForm(
                                      role,
                                      "pool_max_size",
                                      Number(event.target.value),
                                    )
                                  }
                                  sx={{ width: { xs: "100%", md: 120 } }}
                                />
                              </Stack>
                              {health && (
                                <Alert
                                  severity={health.ok ? "success" : "error"}
                                  sx={{ borderRadius: 2 }}
                                >
                                  {health.detail}
                                </Alert>
                              )}
                              <Stack direction="row" spacing={1} justifyContent="flex-end">
                                <Button
                                  variant="outlined"
                                  onClick={() => checkDatabaseHealth(role)}
                                  disabled={!configRecord?.has_dsn && !form.dsn.trim()}
                                >
                                  测试连通性
                                </Button>
                                <Button
                                  variant="outlined"
                                  color="error"
                                  onClick={() => deleteDatabase(role)}
                                  disabled={!configRecord?.has_dsn}
                                >
                                  删除
                                </Button>
                                <Button
                                  variant="contained"
                                  startIcon={<SaveIcon />}
                                  onClick={() => saveDatabase(role)}
                                  disabled={!form.dsn.trim() || !health?.ok}
                                >
                                  保存
                                </Button>
                              </Stack>
                            </Stack>
                          </Paper>
                        );
                      })}
                  </Stack>
                )}

              </Box>
            </Paper>
            <Dialog
              open={createProjectOpen}
              onClose={() => setCreateProjectOpen(false)}
              fullWidth
              maxWidth="md"
              PaperProps={{
                sx: {
                  borderRadius: 2,
                  overflow: "hidden",
                },
              }}
            >
              <Box component="form" onSubmit={createProject}>
                <DialogTitle sx={{ px: 3, py: 2 }}>
                  <Stack direction="row" alignItems="center" justifyContent="space-between">
                    <Stack direction="row" spacing={1.5} alignItems="center" sx={{ minWidth: 0 }}>
                      <Box
                        sx={(theme) => ({
                          width: 40,
                          height: 40,
                          borderRadius: 1.5,
                          display: "grid",
                          placeItems: "center",
                          color: "primary.main",
                          bgcolor: alpha(theme.palette.primary.main, 0.12),
                          flexShrink: 0,
                        })}
                      >
                        <DnsIcon />
                      </Box>
                      <Box sx={{ minWidth: 0 }}>
                        <Typography variant="h6" fontWeight={800} lineHeight={1.2}>
                          新建项目
                        </Typography>
                        <Typography variant="body2" color="text.secondary" noWrap>
                          系统项目基础配置
                        </Typography>
                      </Box>
                    </Stack>
                    <IconButton
                      aria-label="关闭"
                      onClick={() => setCreateProjectOpen(false)}
                      edge="end"
                    >
                      <CloseIcon />
                    </IconButton>
                  </Stack>
                </DialogTitle>
                <DialogContent dividers sx={{ px: 3, py: 2.5 }}>
                  <ProjectFormFields
                    value={createProjectForm}
                    onChange={setCreateProjectForm}
                  />
                </DialogContent>
                <DialogActions sx={{ px: 3, py: 2, bgcolor: "action.hover" }}>
                  <Button onClick={() => setCreateProjectOpen(false)}>取消</Button>
                  <Button type="submit" variant="contained" startIcon={<SaveIcon />}>
                    创建项目
                  </Button>
                </DialogActions>
              </Box>
            </Dialog>
          </>
        )}
      </Stack>
    </Box>
  );
};
