import "./ScreenSaverManagement.css";

import {
  App,
  Button,
  Card,
  Col,
  Drawer,
  Empty,
  Form,
  Input,
  InputNumber,
  Modal,
  Popconfirm,
  Row,
  Select,
  Slider,
  Space,
  Switch,
  Table,
  Tag,
  Typography,
  Upload,
} from "antd";
import type { ColumnsType } from "antd/es/table";
import {
  DeleteOutlined,
  EditOutlined,
  PictureOutlined,
  PlusOutlined,
  ReloadOutlined,
  SaveOutlined,
  ScissorOutlined,
  SearchOutlined,
  SettingOutlined,
  TeamOutlined,
  UploadOutlined,
  UserOutlined,
} from "@ant-design/icons";
import PageContainer from "@/components/shared/PageContainer";
import DataListPanel from "@/components/shared/DataListPanel";
import SectionCard from "@/components/shared/SectionCard";
import { useEffect, useMemo, useRef, useState } from "react";
import type { UploadProps } from "antd";
import AppPagination from "@/components/shared/AppPagination";
import {
  createScreenSaver,
  deleteScreenSaver,
  getMyScreenSaverSettings,
  listScreenSavers,
  type ScreenSaverDTO,
  type ScreenSaverScopeType,
  type ScreenSaverUserSettingsVO,
  type ScreenSaverUploadResult,
  type ScreenSaverVO,
  updateMyScreenSaverSettings,
  updateScreenSaver,
  updateScreenSaverStatus,
  uploadScreenSaverImage,
} from "@/api/business/screenSaver";
import { listUsers } from "@/api";
import type { SysUser, UserProfile } from "@/types";
import dayjs from "dayjs";

const { Text, Title } = Typography;
const { TextArea } = Input;

const CROP_WIDTH = 1280;
const CROP_HEIGHT = 800;
const VIEWPORT_WIDTH = 640;
const VIEWPORT_HEIGHT = 400;
const ALLOWED_TYPES = new Map<string, "image/jpeg" | "image/png">([
  ["image/jpeg", "image/jpeg"],
  ["image/jpg", "image/jpeg"],
  ["image/png", "image/png"],
]);

type ScreenSaverFormValues = {
  scopeType: ScreenSaverScopeType;
  ownerUserId?: number;
  name: string;
  imageUrl: string;
  description?: string;
  imageWidth: number;
  imageHeight: number;
  imageFormat: string;
  sortOrder?: number;
  statusEnabled: boolean;
  remark?: string;
};

type ScreenSaverSettingsFormValues = {
  displayDurationSec: number;
};

type CropModalState = {
  open: boolean;
  src: string;
  fileName: string;
  mimeType: "image/jpeg" | "image/png";
  targetWidth: number;
  targetHeight: number;
};

type DragState = {
  startX: number;
  startY: number;
  originX: number;
  originY: number;
};

function clamp(value: number, min: number, max: number) {
  return Math.min(Math.max(value, min), max);
}

function normalizeOwnerLabel(user?: SysUser) {
  if (!user) {
    return "未指定";
  }
  return user.displayName || user.username || `用户 ${user.userId}`;
}

function getImageFormatLabel(format?: string) {
  if (!format) {
    return "-";
  }
  return format.toUpperCase();
}

function validateImageFile(file: File) {
  const normalizedType = ALLOWED_TYPES.get(file.type.toLowerCase());
  if (!normalizedType) {
    throw new Error("仅支持 jpg、jpeg、png 图片");
  }
  return normalizedType;
}

async function readFileAsDataUrl(file: File) {
  return new Promise<string>((resolve, reject) => {
    const reader = new FileReader();
    reader.onload = () => resolve(String(reader.result || ""));
    reader.onerror = () => reject(new Error("读取图片失败"));
    reader.readAsDataURL(file);
  });
}

function createImage(src: string) {
  return new Promise<HTMLImageElement>((resolve, reject) => {
    const image = new Image();
    image.onload = () => resolve(image);
    image.onerror = () => reject(new Error("图片加载失败"));
    image.src = src;
  });
}

type CropDialogProps = {
  state: CropModalState;
  onCancel: () => void;
  onConfirm: (file: File) => Promise<void>;
};

function ScreenSaverCropDialog({ state, onCancel, onConfirm }: CropDialogProps) {
  const { message } = App.useApp();
  const [loading, setLoading] = useState(false);
  const [dragging, setDragging] = useState(false);
  const [naturalSize, setNaturalSize] = useState({ width: 0, height: 0 });
  const [minZoom, setMinZoom] = useState(1);
  const [zoom, setZoom] = useState(1);
  const [offset, setOffset] = useState({ x: 0, y: 0 });
  const dragRef = useRef<DragState | null>(null);

  const { targetWidth, targetHeight } = state;

  useEffect(() => {
    if (!state.open) {
      return;
    }
    let active = true;
    void createImage(state.src)
      .then((image) => {
        if (!active) {
          return;
        }
        const nextMinZoom = Math.max(VIEWPORT_WIDTH / image.width, VIEWPORT_HEIGHT / image.height);
        setNaturalSize({ width: image.width, height: image.height });
        setMinZoom(nextMinZoom);
        setZoom(nextMinZoom);
        setOffset({ x: 0, y: 0 });
      })
      .catch((error: Error) => {
        message.error(error.message || "图片加载失败");
      });
    return () => {
      active = false;
    };
  }, [message, state.open, state.src]);

  const displaySize = useMemo(() => ({
    width: naturalSize.width * zoom,
    height: naturalSize.height * zoom,
  }), [naturalSize, zoom]);

  const clampOffset = (x: number, y: number, currentZoom = zoom) => {
    const width = naturalSize.width * currentZoom;
    const height = naturalSize.height * currentZoom;
    const maxX = Math.max(0, (width - VIEWPORT_WIDTH) / 2);
    const maxY = Math.max(0, (height - VIEWPORT_HEIGHT) / 2);
    return {
      x: clamp(x, -maxX, maxX),
      y: clamp(y, -maxY, maxY),
    };
  };

  const handleZoomChange = (nextZoom: number) => {
    const nextOffset = clampOffset(offset.x, offset.y, nextZoom);
    setZoom(nextZoom);
    setOffset(nextOffset);
  };

  const beginDrag = (clientX: number, clientY: number) => {
    dragRef.current = {
      startX: clientX,
      startY: clientY,
      originX: offset.x,
      originY: offset.y,
    };
    setDragging(true);
  };

  const updateDrag = (clientX: number, clientY: number) => {
    if (!dragRef.current) {
      return;
    }
    const deltaX = clientX - dragRef.current.startX;
    const deltaY = clientY - dragRef.current.startY;
    setOffset(clampOffset(dragRef.current.originX + deltaX, dragRef.current.originY + deltaY));
  };

  const endDrag = () => {
    dragRef.current = null;
    setDragging(false);
  };

  const exportCroppedFile = async () => {
    const image = await createImage(state.src);
    const canvas = document.createElement("canvas");
    canvas.width = targetWidth;
    canvas.height = targetHeight;
    const context = canvas.getContext("2d");
    if (!context) {
      throw new Error("浏览器不支持图片裁剪");
    }
    const previewScale = targetWidth / VIEWPORT_WIDTH;
    const exportedWidth = image.width * zoom * previewScale;
    const exportedHeight = image.height * zoom * previewScale;
    const drawX = targetWidth / 2 - exportedWidth / 2 + offset.x * previewScale;
    const drawY = targetHeight / 2 - exportedHeight / 2 + offset.y * previewScale;
    context.drawImage(image, drawX, drawY, exportedWidth, exportedHeight);
    const extension = state.mimeType === "image/png" ? "png" : "jpg";
    const fileName = state.fileName.replace(/\.[^.]+$/, "") + `_${targetWidth}x${targetHeight}.${extension}`;
    const blob = await new Promise<Blob | null>((resolve) => {
      if (state.mimeType === "image/png") {
        canvas.toBlob(resolve, "image/png");
      } else {
        canvas.toBlob(resolve, "image/jpeg", 0.92);
      }
    });
    if (!blob) {
      throw new Error("导出裁剪图片失败");
    }
    return new File([blob], fileName, { type: state.mimeType });
  };

  const handleConfirm = async () => {
    setLoading(true);
    try {
      const file = await exportCroppedFile();
      await onConfirm(file);
    } catch (error) {
      message.error(error instanceof Error ? error.message : "瑁佸壀涓婁紶澶辫触");
    } finally {
      setLoading(false);
    }
  };

  return (
    <Modal
      open={state.open}
      onCancel={loading ? undefined : onCancel}
      footer={null}
      width={1100}
      centered
      destroyOnHidden
      className="screen-saver-crop-modal"
      maskClosable={!loading}
      closable={!loading}
    >
      <div className="screen-saver-crop-modal__layout">
        <div className="screen-saver-crop-modal__stage">
          <div className="screen-saver-crop-modal__stage-head">
            <h3>裁剪成屏保成品图</h3>
            <p>请在固定 8:5 取景框内调整画面位置。导出尺寸固定为 {targetWidth} × {targetHeight}，安卓端将直接使用该成品图展示。</p>
          </div>
          <div
            className={`screen-saver-crop-modal__viewport${dragging ? " is-dragging" : ""}`}
            onMouseDown={(event) => beginDrag(event.clientX, event.clientY)}
            onMouseMove={(event) => updateDrag(event.clientX, event.clientY)}
            onMouseUp={endDrag}
            onMouseLeave={endDrag}
            onTouchStart={(event) => {
              const touch = event.touches[0];
              if (touch) {
                beginDrag(touch.clientX, touch.clientY);
              }
            }}
            onTouchMove={(event) => {
              const touch = event.touches[0];
              if (touch) {
                updateDrag(touch.clientX, touch.clientY);
              }
            }}
            onTouchEnd={endDrag}
          >
            {state.src ? (
              <img
                src={state.src}
                alt="待裁剪屏保"
                className="screen-saver-crop-modal__image"
                draggable={false}
                style={{
                  width: displaySize.width,
                  height: displaySize.height,
                  transform: `translate(calc(-50% + ${offset.x}px), calc(-50% + ${offset.y}px))`,
                }}
              />
            ) : null}
          </div>
          <div className="screen-saver-crop-modal__meta">
            <span>原图：{naturalSize.width || "-"} × {naturalSize.height || "-"}</span>
            <span>输出：{targetWidth} × {targetHeight}</span>
          </div>
        </div>
        <div className="screen-saver-crop-modal__sidebar">
          <div className="screen-saver-crop-modal__sidebar-card">
            <h4>缩放与构图</h4>
            <p>拖动画面调整主体位置，保留足够安全边距，避免标题、人物或徽标在不同设备上被裁切。</p>
            <div style={{ marginTop: 18 }}>
              <Text type="secondary">缩放</Text>
              <Slider
                min={minZoom}
                max={Math.max(minZoom * 3, minZoom + 0.2)}
                step={0.01}
                value={zoom}
                tooltip={{ formatter: (value) => `${Math.round((value || 1) / minZoom * 100)}%` }}
                onChange={handleZoomChange}
              />
            </div>
          </div>
          <div className="screen-saver-crop-modal__sidebar-card">
            <h4>交付标准</h4>
            <p>仅支持 JPG / JPEG / PNG。导出的屏保图片会以 {targetWidth} × {targetHeight} 固定尺寸上传，后端仅做格式与尺寸校验，不再重新裁剪。</p>
          </div>
          <div className="screen-saver-crop-modal__footer">
            <Button onClick={onCancel} disabled={loading}>取消</Button>
            <Button type="primary" icon={<ScissorOutlined />} loading={loading} onClick={() => void handleConfirm()}>
              生成并上传
            </Button>
          </div>
        </div>
      </div>
    </Modal>
  );
}

export default function ScreenSaverManagement() {
  const { message } = App.useApp();
  const [form] = Form.useForm<ScreenSaverFormValues>();
  const [settingsForm] = Form.useForm<ScreenSaverSettingsFormValues>();
  const [loading, setLoading] = useState(false);
  const [saving, setSaving] = useState(false);
  const [settingsSaving, setSettingsSaving] = useState(false);
  const [drawerOpen, setDrawerOpen] = useState(false);
  const [settingsOpen, setSettingsOpen] = useState(false);
  const [editing, setEditing] = useState<ScreenSaverVO | null>(null);
  const [records, setRecords] = useState<ScreenSaverVO[]>([]);
  const [users, setUsers] = useState<SysUser[]>([]);
  const [mySettings, setMySettings] = useState<ScreenSaverUserSettingsVO>({ userId: 0, displayDurationSec: 15 });
  const [searchValue, setSearchValue] = useState("");
  const [statusFilter, setStatusFilter] = useState<"all" | "enabled" | "disabled">("all");
  const [scopeFilter, setScopeFilter] = useState<"all" | ScreenSaverScopeType>("all");
  const [page, setPage] = useState(1);
  const [pageSize, setPageSize] = useState(10);
  const [uploading, setUploading] = useState(false);
  const [cropState, setCropState] = useState<CropModalState>({
    open: false,
    src: "",
    fileName: "",
    mimeType: "image/jpeg",
    targetWidth: CROP_WIDTH,
    targetHeight: CROP_HEIGHT,
  });
  const userProfile = useMemo<UserProfile>(() => {
    const profileStr = sessionStorage.getItem("userProfile");
    return profileStr ? JSON.parse(profileStr) : {};
  }, []);
  const currentUserId = Number(userProfile.userId || 0);
  const isAdmin = userProfile.isAdmin === true || userProfile.isPlatformAdmin === true || userProfile.isTenantAdmin === true;

  const userMap = useMemo(() => {
    return new Map<number, SysUser>(users.map((user) => [user.userId, user]));
  }, [users]);

  const loadData = async () => {
    setLoading(true);
    try {
      const [screenSavers, userList, settings] = await Promise.all([
        listScreenSavers(),
        listUsers().catch(() => [] as SysUser[]),
        getMyScreenSaverSettings().catch(() => ({ userId: currentUserId || 0, displayDurationSec: 15 })),
      ]);
      setRecords(screenSavers || []);
      setUsers(userList || []);
      setMySettings(settings || { userId: currentUserId || 0, displayDurationSec: 15 });
    } finally {
      setLoading(false);
    }
  };

  useEffect(() => {
    void loadData();
  }, []);

  const filteredRecords = useMemo(() => {
    const keyword = searchValue.trim().toLowerCase();
    return records.filter((item) => {
      if (scopeFilter !== "all" && item.scopeType !== scopeFilter) {
        return false;
      }
      if (statusFilter === "enabled" && item.status !== 1) {
        return false;
      }
      if (statusFilter === "disabled" && item.status === 1) {
        return false;
      }
      if (!keyword) {
        return true;
      }
      const ownerName = normalizeOwnerLabel(item.ownerUserId ? userMap.get(item.ownerUserId) : undefined);
      return [item.name, item.description, item.creatorUsername, ownerName, item.imageFormat]
        .some((field) => String(field || "").toLowerCase().includes(keyword));
    });
  }, [records, scopeFilter, statusFilter, searchValue, userMap]);

  const pagedRecords = useMemo(() => {
    const start = (page - 1) * pageSize;
    return filteredRecords.slice(start, start + pageSize);
  }, [filteredRecords, page, pageSize]);

  useEffect(() => {
    setPage(1);
  }, [searchValue, statusFilter, scopeFilter]);

  const openCreate = () => {
    setEditing(null);
    form.resetFields();
    form.setFieldsValue({
      scopeType: "USER",
      ownerUserId: currentUserId || undefined,
      sortOrder: 0,
      statusEnabled: true,
      imageWidth: CROP_WIDTH,
      imageHeight: CROP_HEIGHT,
      imageFormat: "jpg",
    });
    setDrawerOpen(true);
  };

  const openEdit = (record: ScreenSaverVO) => {
    if (!isAdmin && (record.scopeType !== "USER" || record.ownerUserId !== currentUserId)) {
      message.warning("普通用户只能编辑自己的用户级屏保");
      return;
    }
    setEditing(record);
    form.setFieldsValue({
      scopeType: record.scopeType,
      ownerUserId: record.ownerUserId || undefined,
      name: record.name,
      imageUrl: record.imageUrl,
      description: record.description,
      imageWidth: record.imageWidth || CROP_WIDTH,
      imageHeight: record.imageHeight || CROP_HEIGHT,
      imageFormat: record.imageFormat || "jpg",
      sortOrder: record.sortOrder,
      statusEnabled: record.status === 1,
      remark: record.remark,
    });
    setDrawerOpen(true);
  };

  const handleDelete = async (record: ScreenSaverVO) => {
    await deleteScreenSaver(record.id);
    message.success("屏保已删除");
    await loadData();
  };

  const handleSubmit = async () => {
    const values = await form.validateFields();
    const resolvedScopeType: ScreenSaverScopeType = isAdmin ? values.scopeType : "USER";
    const resolvedOwnerUserId = resolvedScopeType === "USER" ? currentUserId || null : null;
    const resolvedStatusEnabled = values.statusEnabled ?? true;
    const payload: ScreenSaverDTO = {
      scopeType: resolvedScopeType,
      ownerUserId: resolvedOwnerUserId,
      name: values.name.trim(),
      imageUrl: values.imageUrl.trim(),
      description: values.description?.trim(),
      imageWidth: values.imageWidth,
      imageHeight: values.imageHeight,
      imageFormat: values.imageFormat.trim().toLowerCase(),
      sortOrder: values.sortOrder,
      status: resolvedStatusEnabled ? 1 : 0,
      remark: values.remark?.trim(),
    };

    setSaving(true);
    try {
      if (editing) {
        await updateScreenSaver(editing.id, payload);
        message.success("屏保已更新");
      } else {
        await createScreenSaver(payload);
        message.success("屏保已创建");
      }
      setDrawerOpen(false);
      await loadData();
    } finally {
      setSaving(false);
    }
  };

  const openCropper = async (file: File) => {
    const mimeType = validateImageFile(file);
    const src = await readFileAsDataUrl(file);
    const targetWidth = form.getFieldValue("imageWidth") || CROP_WIDTH;
    const targetHeight = form.getFieldValue("imageHeight") || CROP_HEIGHT;

    setCropState({
      open: true,
      src,
      fileName: file.name,
      mimeType,
      targetWidth,
      targetHeight,
    });
  };

  const handleUploadCroppedImage = async (file: File) => {
    setUploading(true);
    try {
      const result: ScreenSaverUploadResult = await uploadScreenSaverImage(file);
      form.setFieldsValue({
        imageUrl: result.imageUrl,
        imageWidth: result.imageWidth,
        imageHeight: result.imageHeight,
        imageFormat: result.imageFormat,
      });
      setCropState((prev) => ({ ...prev, open: false, src: "" }));
      message.success("屏保图片已上传");
    } finally {
      setUploading(false);
    }
  };

  const uploadProps: UploadProps = {
    showUploadList: false,
    beforeUpload: (file) => {
      void openCropper(file as File).catch((error: Error) => {
        message.error(error.message || "图片处理失败");
      });
      return Upload.LIST_IGNORE;
    },
  };

  const handleToggleStatus = async (record: ScreenSaverVO, checked: boolean) => {
    await updateScreenSaverStatus(record.id, checked ? 1 : 0);
    message.success(checked ? "屏保已启用" : "屏保已停用");
    await loadData();
  };

  const openSettingsModal = () => {
    settingsForm.setFieldsValue({
      displayDurationSec: mySettings.displayDurationSec,
    });
    setSettingsOpen(true);
  };

  const handleSaveSettings = async () => {
    const values = await settingsForm.validateFields();
    setSettingsSaving(true);
    try {
      const result = await updateMyScreenSaverSettings({
        displayDurationSec: values.displayDurationSec,
      });
      setMySettings(result);
      setSettingsOpen(false);
      message.success("播放设置已更新");
      await loadData();
    } finally {
      setSettingsSaving(false);
    }
  };

  const columns: ColumnsType<ScreenSaverVO> = [
    {
      title: "预览",
      key: "thumb",
      width: 90,
      render: (_, record) => (
        <div className="screen-saver-table-thumb">
          {record.imageUrl ? (
            <img src={record.imageUrl} alt={record.name} style={{ maxWidth: 70, maxHeight: 52, objectFit: 'cover', borderRadius: 4 }} />
          ) : (
            <div style={{ width: 70, height: 52, background: '#f5f5f5', borderRadius: 4, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
              <PictureOutlined style={{ color: '#ccc', fontSize: 20 }} />
            </div>
          )}
        </div>
      ),
    },
    {
      title: "名称与描述",
      key: "info",
      width: 160,
      render: (_, record) => (
        <Space direction="vertical" size={3}>
          <Text strong style={{ fontSize: 14 }}>{record.name}</Text>
          <Text type="secondary" ellipsis style={{ fontSize: 12, maxWidth: 150 }}>{record.description || "暂无描述"}</Text>
        </Space>
      ),
    },
    {
      title: "图片规格",
      key: "spec",
      width: 150,
      render: (_, record) => (
        <Space direction="vertical" size={4}>
          <Tag color="processing">{getImageFormatLabel(record.imageFormat)}</Tag>
          <Text type="secondary" style={{ fontSize: 12 }}>{record.imageWidth || CROP_WIDTH} × {record.imageHeight || CROP_HEIGHT}</Text>
        </Space>
      ),
    },
    {
      title: "作用域",
      key: "scope",
      width: 160,
      render: (_, record) => (
        <Space direction="vertical" size={4}>
          {record.scopeType === "USER" ? (
            <Tag color="gold" icon={<UserOutlined />}>用户级</Tag>
          ) : (
            <Tag color="blue" icon={<TeamOutlined />}>平台级</Tag>
          )}
          <Text type="secondary" style={{ fontSize: 12 }}>
            {record.scopeType === "USER"
              ? `归属：${normalizeOwnerLabel(record.ownerUserId ? userMap.get(record.ownerUserId) : undefined)}`
              : "全平台共用"}
          </Text>
        </Space>
      ),
    },
    {
      title: "状态",
      key: "status",
      width: 120,
      render: (_, record) => (
        <Space direction="vertical" size={6}>
          <Text type="secondary" style={{ fontSize: 12 }}>排序：{record.sortOrder ?? 0}</Text>
          <Switch size="small" checked={record.status === 1} onChange={(checked) => void handleToggleStatus(record, checked)} />
        </Space>
      ),
    },
    {
      title: "创建信息",
      key: "creator",
      width: 160,
      render: (_, record) => {
        const timeValue = record.updatedAt || record.createdAt;
        return (
          <Space direction="vertical" size={4}>
            <Text style={{ fontSize: 13 }}>{record.creatorUsername || "-"}</Text>
            <Text type="secondary" style={{ fontSize: 11 }}>
              {timeValue ? dayjs(timeValue).format("MM-DD HH:mm") : "-"}
            </Text>
          </Space>
        );
      },
    },
    {
      title: "操作",
      key: "action",
      width: 140,
      fixed: "right",
      render: (_, record) => {
        const canManageRecord = isAdmin || (record.scopeType === "USER" && record.ownerUserId === currentUserId);
        if (!canManageRecord) {
          return null;
        }
        return (
          <Space size={4}>
            <Button type="text" icon={<EditOutlined />} onClick={() => openEdit(record)} />
            <Popconfirm title="确认删除该屏保吗？" onConfirm={() => void handleDelete(record)}>
              <Button type="text" danger icon={<DeleteOutlined />} />
            </Popconfirm>
          </Space>
        );
      },
    },
  ];
  const currentImageUrl = Form.useWatch("imageUrl", form);
  const watchedScopeType = Form.useWatch("scopeType", form);
  const currentScopeType: ScreenSaverScopeType = isAdmin ? (watchedScopeType || "PLATFORM") : "USER";
  const currentWidth = Form.useWatch("imageWidth", form) || CROP_WIDTH;
  const currentHeight = Form.useWatch("imageHeight", form) || CROP_HEIGHT;

  return (
    <PageContainer
      title={null}
      className="screen-saver-page"
    >
      <SectionCard
        title="屏保管理"
        description="管理平台级和用户级屏保素材，统一维护播放时长、启停状态和图片规格。"
      >
        <DataListPanel
          className="screen-saver-list-panel"
          leftActions={
            <Space wrap>
              <Button type="primary" icon={<PlusOutlined />} onClick={openCreate}>
                新增屏保
              </Button>
              <Button icon={<SettingOutlined />} onClick={openSettingsModal}>
                播放设置
              </Button>
            </Space>
          }
          rightActions={
            <Space wrap>
              <Input
                placeholder="搜索名称、描述、创建人或归属用户"
                prefix={<SearchOutlined />}
                allowClear
                style={{ width: 280 }}
                value={searchValue}
                onChange={(event) => setSearchValue(event.target.value)}
              />
              <Select
                value={scopeFilter}
                style={{ width: 140 }}
                onChange={(value) => setScopeFilter(value)}
                options={[
                  { label: "全部作用域", value: "all" },
                  { label: "平台级", value: "PLATFORM" },
                  { label: "用户级", value: "USER" },
                ]}
              />
              <Select
                value={statusFilter}
                style={{ width: 140 }}
                onChange={(value) => setStatusFilter(value)}
                options={[
                  { label: "全部状态", value: "all" },
                  { label: "已启用", value: "enabled" },
                  { label: "已停用", value: "disabled" },
                ]}
              />
              <Button icon={<ReloadOutlined />} onClick={() => void loadData()} loading={loading} title="刷新" aria-label="刷新" />
            </Space>
          }
          footer={
            <AppPagination
              current={page}
              pageSize={pageSize}
              total={filteredRecords.length}
              onChange={(nextPage, nextSize) => {
                setPage(nextPage);
                setPageSize(nextSize);
              }}
            />
          }
        >
          <Table
            className="screen-saver-table"
            rowKey="id"
            columns={columns}
            dataSource={pagedRecords}
            loading={loading}
            pagination={false}
            locale={{
              emptyText: <Empty description="暂无屏保素材" />,
            }}
            scroll={{ x: 1100, y: "100%" }}
          />
        </DataListPanel>
      </SectionCard>
      <Drawer
        title={editing ? "编辑屏保" : "新增屏保"}
        open={drawerOpen}
        onClose={() => setDrawerOpen(false)}
        width={760}
        destroyOnHidden
        forceRender
        className="screen-saver-drawer"
        styles={{ body: { padding: 24 } }}
        footer={(
          <div className="screen-saver-drawer__footer">
            <Button onClick={() => setDrawerOpen(false)}>取消</Button>
            <Button type="primary" icon={<SaveOutlined />} loading={saving} onClick={() => void handleSubmit()}>
              保存
            </Button>
          </div>
        )}
      >
        <Form form={form} layout="vertical" className="screen-saver-drawer__form">
          <Row gutter={16}>
            <Col xs={24}>
              <Form.Item name="name" label="屏保名称" rules={[{ required: true, message: "请输入屏保名称" }]}>
                <Input placeholder="例如：大厅欢迎屏、品牌发布屏" />
              </Form.Item>
            </Col>
          </Row>

          {isAdmin ? (
            <Row gutter={16}>
              <Col xs={24} md={12}>
                <Form.Item name="scopeType" label="作用域" rules={[{ required: true, message: "请选择作用域" }]}>
                  <Select
                    options={[
                      { label: "平台级（全平台共用）", value: "PLATFORM" },
                      { label: "用户级（当前用户自己使用）", value: "USER" },
                    ]}
                  />
                </Form.Item>
              </Col>
              <Col xs={24} md={12}>
                <Form.Item label="归属用户">
                  <Input
                    value={currentScopeType === "USER" ? normalizeOwnerLabel(userMap.get(currentUserId)) : "平台级无需选择"}
                    readOnly
                  />
                </Form.Item>
              </Col>
            </Row>
          ) : (
            <Row gutter={16}>
              <Col xs={24} md={12}>
                <Form.Item label="作用域">
                  <Input value="个人级" readOnly />
                </Form.Item>
              </Col>
              <Col xs={24} md={12}>
                <Form.Item label="归属用户">
                  <Input value={normalizeOwnerLabel(userMap.get(currentUserId))} readOnly />
                </Form.Item>
              </Col>
            </Row>
          )}

          <Card
            className="screen-saver-preview-card"
            style={{ marginBottom: 18 }}
            styles={{ body: { padding: 18 } }}
          >
            <div style={{ display: "flex", flexDirection: "column", gap: 16 }}>
              <Space wrap style={{ width: "100%", justifyContent: "space-between" }}>
                <div>
                  <Title level={5} style={{ margin: 0 }}>屏保成片预览</Title>
                  <Text type="secondary">固定 8:5 构图，根据设定尺寸导出。上传后后端只做校验与存储。</Text>
                </div>
                <Upload {...uploadProps}>
                  <Button type="primary" icon={<UploadOutlined />} loading={uploading}>
                    选择图片并裁剪
                  </Button>
                </Upload>
              </Space>
              <div className="screen-saver-preview-stage">
                {currentImageUrl ? (
                  <img src={currentImageUrl} alt="屏保预览" style={{ maxWidth: '100%', maxHeight: 300, objectFit: 'contain', borderRadius: 8 }} />
                ) : (
                  <div style={{ height: "100%", display: "grid", placeItems: "center", color: "rgba(235,244,255,.72)" }}>
                    <Space direction="vertical" align="center" size={10}>
                      <ScissorOutlined style={{ fontSize: 26 }} />
                      <span>请选择图片并完成裁剪后上传</span>
                    </Space>
                  </div>
                )}
              </div>
              <Space wrap>
                <span className="screen-saver-preview-pill">输出规格 {currentWidth} × {currentHeight}</span>
                <span className="screen-saver-preview-pill">当前作用域 {currentScopeType === "USER" ? "用户级" : "平台级"}</span>
                {currentScopeType === "USER" ? (
                  <span className="screen-saver-preview-pill">
                    归属 {normalizeOwnerLabel(userMap.get(currentUserId))}
                  </span>
                ) : null}
              </Space>
            </div>
          </Card>

          <Row gutter={16}>
            <Col xs={24} md={8}>
              <Form.Item name="imageFormat" label="图片格式" rules={[{ required: true, message: "请先上传图片" }]}>
                <Input disabled />
              </Form.Item>
            </Col>
            <Col xs={12} md={8}>
              <Form.Item name="imageWidth" label="宽度" rules={[{ required: true, message: "请输入宽度" }]}>
                <InputNumber min={100} max={4096} style={{ width: "100%" }} />
              </Form.Item>
            </Col>
            <Col xs={12} md={8}>
              <Form.Item name="imageHeight" label="高度" rules={[{ required: true, message: "请输入高度" }]}>
                <InputNumber min={100} max={4096} style={{ width: "100%" }} />
              </Form.Item>
            </Col>
          </Row>

          <Form.Item name="imageUrl" label="图片地址" rules={[{ required: true, message: "请先上传裁剪后的屏保图片" }]}>
            <Input placeholder="上传完成后自动回填" readOnly />
          </Form.Item>

          <Form.Item name="description" label="描述">
            <TextArea rows={3} placeholder="描述这张屏保用于什么场景、展示什么信息。" />
          </Form.Item>

          <Row gutter={16}>
            <Col xs={24} md={12}>
              <Form.Item name="sortOrder" label="排序值">
                <InputNumber min={0} style={{ width: "100%" }} />
              </Form.Item>
            </Col>
            <Col xs={24} md={12}>
              <Form.Item name="remark" label="备注">
                <Input placeholder="例如：大厅屏、品牌发布期、个人欢迎页" />
              </Form.Item>
            </Col>
          </Row>

          {(isAdmin || currentScopeType === "USER") ? (
            <Form.Item name="statusEnabled" label="启用状态" valuePropName="checked" preserve>
              <Switch />
            </Form.Item>
          ) : null}
        </Form>
      </Drawer>

      <Modal
        title="我的屏保播放设置"
        open={settingsOpen}
        onCancel={() => setSettingsOpen(false)}
        onOk={() => void handleSaveSettings()}
        okText="保存"
        confirmLoading={settingsSaving}
        destroyOnHidden
      >
        <Form form={settingsForm} layout="vertical">
          <Form.Item
            name="displayDurationSec"
            label="统一展示时长（秒）"
            rules={[{ required: true, message: "请输入统一展示时长" }]}
            extra="该时长会应用到你看到的所有屏保图片，包括平台级和个人级素材。"
          >
            <InputNumber min={3} max={3600} style={{ width: "100%" }} />
          </Form.Item>
        </Form>
      </Modal>

      <ScreenSaverCropDialog
        state={cropState}
        onCancel={() => setCropState((prev) => ({ ...prev, open: false, src: "" }))}
        onConfirm={handleUploadCroppedImage}
      />
    </PageContainer>
  );
}
