<script lang="ts" setup>
import { computed, ref, watch } from 'vue';

import { useVbenModal } from '@vben/common-ui';

import {
  Checkbox,
  Empty,
  Input,
  InputNumber,
  Alert,
  Button,
  Tag,
  message,
  Radio,
  RadioGroup,
  Select,
  Spin,
  Tabs,
  Textarea,
} from 'ant-design-vue';

import GalleryPickLink from '#/components/form/components/gallery-pick-link.vue';
import { useVbenForm } from '#/adapter/form';
import { getAdminList } from '#/views/system/admin/api';
import { getOaPlatformList } from '#/views/system/oa-platform/api';
import {
  getOaRobotChatMembers,
  getOaRobotList,
} from '#/views/system/oa-robot/api';
import { isWorkWechatApp } from '#/views/system/oa-robot/config/form';
import {
  createOaScene,
  getOaMessageTypes,
  testSendOaScene,
  updateOaScene,
} from '#/views/system/oa-scene/api';
import { modalFormProps } from '#/views/system/oa-scene/config/form';
import TemplateCardForm from '#/views/system/oa-scene/components/template-card-form.vue';
import SceneTargetsPanel, {
  type SceneTargetItem,
} from '#/views/system/oa-scene/components/scene-targets-panel.vue';

/**
 * OA 场景新增/编辑弹窗（全量消息类型版）
 *
 * 提交 at_users 统一为双结构（后端兼容旧纯数组）：
 *   { work_wechat: { admin_ids: number[], userids: string[] }, work_wechat_app: { ... } }
 * work_wechat_app 额外提交 targets：人/多群/每群 @
 */

interface MessageTypeOption {
  message_type: string;
  name: string;
  icon: string;
  need_media: number;
  payload_schema: string | null;
}

interface PayloadFieldSchema {
  name: string;
  label: string;
  component: string;
  required?: boolean;
  props?: Record<string, any>;
}

const isUpdate = ref(false);
const gridApi = ref();
const loading = ref(false);

/** 平台列表（仅展示启用的平台） */
const platforms = ref<any[]>([]);
/** 启用平台下的所有机器人 */
const allRobots = ref<any[]>([]);
/** 员工列表（用于 @ 人多选） */
const adminList = ref<any[]>([]);
/** 当前选中的 Tab 平台编码 */
const activePlatformTab = ref('');

/** 各平台支持的消息类型列表（来自 message-types 接口） */
const messageTypesMap = ref<Record<string, MessageTypeOption[]>>({});

/**
 * 多维状态：
 * - selectedMessageType: 每个平台选中的消息类型
 * - payloadValues: 每个平台 payload 字段值（按 message_type 不同字段不同）
 */
const selectedMessageType = ref<Record<string, string>>({});
const payloadValues = ref<Record<string, Record<string, any>>>({});

/** 机器人勾选（按平台分组） */
const selectedRobots = ref<Record<string, number[]>>({});
/** @ 配置（按平台）：admin_ids=系统员工，userids=应用群成员 */
const selectedAtUsers = ref<
  Record<string, { admin_ids: number[]; userids: string[] }>
>({});
/** 应用 API 群成员选项（按平台合并已选机器人的成员） */
const membersByPlatform = ref<
  Record<string, { userid: string; name: string }[]>
>({});
/** 应用 API 投递目标（人 / 群 / 每群 @） */
const sceneTargets = ref<SceneTargetItem[]>([]);
/** 投递目标面板实例（保存前校验客户群确认人） */
const targetsPanelRef = ref<{ validateBeforeSubmit: () => string } | null>(
  null,
);
/** 暂存待回显的 robot_ids（数据加载完后处理） */
let pendingRobotIds: number[] = [];
/** 暂存待回显的 targets */
let pendingTargets: SceneTargetItem[] = [];

/** 业务传参示例值（仅测试用，不落库） */
const testParams = ref({
  content: '',
  title: '',
  url: '',
  media_url: '',
});
const testing = ref(false);
/** 传参示例里展示的 scene_code 提示 */
const formSceneCode = ref('');
interface SceneTestResultItem {
  robot_id: number;
  robot_name: string;
  platform_code: string;
  success: boolean;
  message: string;
  cost_ms: number;
  target_label?: string;
}
const testResults = ref<SceneTestResultItem[]>([]);
const testSummary = ref('');

/** 业务可传字段说明（与 SendOaNotifyJob 覆盖规则对齐） */
const DISPATCH_PARAM_FIELDS = [
  {
    key: 'content' as const,
    label: 'content',
    hint: '正文：覆盖各平台 payload.content',
  },
  {
    key: 'title' as const,
    label: 'title',
    hint: '标题：覆盖 payload.title',
  },
  {
    key: 'url' as const,
    label: 'url',
    hint: '链接：覆盖 payload.url',
  },
  {
    key: 'media_url' as const,
    label: 'media_url',
    hint: '媒体：覆盖 payload.media_url',
  },
];

/**
 * 规范化详情回显的 at_users（兼容旧纯数组）
 */
function normalizeAtUsers(
  raw: Record<string, any> | undefined,
): Record<string, { admin_ids: number[]; userids: string[] }> {
  const result: Record<string, { admin_ids: number[]; userids: string[] }> = {};
  for (const [code, val] of Object.entries(raw || {})) {
    if (Array.isArray(val)) {
      result[code] = {
        admin_ids: val.map((id) => Number(id)).filter((id) => id > 0),
        userids: [],
      };
    } else {
      result[code] = {
        admin_ids: ((val as any)?.admin_ids || [])
          .map((id: any) => Number(id))
          .filter((id: number) => id > 0),
        userids: ((val as any)?.userids || [])
          .map((u: any) => String(u))
          .filter((u: string) => u !== ''),
      };
    }
  }
  return result;
}

function ensureAtSlot(platformCode: string) {
  if (!selectedAtUsers.value[platformCode]) {
    selectedAtUsers.value = {
      ...selectedAtUsers.value,
      [platformCode]: { admin_ids: [], userids: [] },
    };
  }
}

function adminIdsOf(platformCode: string): number[] {
  return selectedAtUsers.value[platformCode]?.admin_ids || [];
}

function useridsOf(platformCode: string): string[] {
  return selectedAtUsers.value[platformCode]?.userids || [];
}

const [Form, formApi] = useVbenForm(modalFormProps);

const [Modal, modalApi] = useVbenModal({
  fullscreenButton: false,
  draggable: true,
  onCancel() {
    modalApi.close();
  },
  onConfirm: async () => {
    formApi.validate().then(async (e: any) => {
      if (e.valid) {
        // 客户群必须配置确认发送员工（前端先拦，后端 syncSceneTargets 再校验）
        const targetErr = targetsPanelRef.value?.validateBeforeSubmit?.() || '';
        if (targetErr) {
          message.warning(targetErr);
          return;
        }
        const payload = await assembleSceneDraft();
        modalApi.setState({ loading: true, confirmLoading: true });
        const submitApi = isUpdate.value ? updateOaScene : createOaScene;
        submitApi(payload)
          .then(() => {
            message.success('保存成功');
            gridApi.value?.reload();
            modalApi.close();
          })
          .finally(() => {
            modalApi.setState({ loading: false, confirmLoading: false });
          });
      }
    });
    await formApi.validateAndSubmitForm();
  },
  onOpenChange(isOpen: boolean) {
    gridApi.value = isOpen ? modalApi.getData()?.gridApi : null;
    if (isOpen) {
      const { values, update } = modalApi.getData<Record<string, any>>();
      isUpdate.value = !!update;
      // 重置内部状态
      selectedMessageType.value = {};
      payloadValues.value = {};
      selectedRobots.value = {};
      selectedAtUsers.value = {};
      sceneTargets.value = [];
      testParams.value = { content: '', title: '', url: '', media_url: '' };
      testResults.value = [];
      testSummary.value = '';
      formSceneCode.value = String(values?.scene_code || '');
      if (values) {
        formApi.setValues({
          ...values,
          // 编辑回显时不带 message_config 进 form（避免被 form schema 当字段处理）
          message_config: undefined,
        });
        // 回显 message_config
        const config = values.message_config || {};
        for (const code of Object.keys(config)) {
          selectedMessageType.value[code] = config[code].message_type || 'text';
          payloadValues.value[code] = config[code].payload || {};
        }
        // 回显已勾选的机器人（需等数据加载后由 groupRobotsByPlatform 重算）
        pendingRobotIds = values.robot_ids || [];
        selectedAtUsers.value = normalizeAtUsers(values.at_users);
        pendingTargets = Array.isArray(values.targets) ? values.targets : [];
        sceneTargets.value = pendingTargets.map((t: any) => ({
          target_type: Number(t.target_type) === 1 ? 1 : 2,
          platform_code: t.platform_code || 'work_wechat_app',
          admin_id: Number(t.admin_id || 0) || undefined,
          chat_id: Number(t.chat_id || 0) || undefined,
          at_admin_ids: (t.at_admin_ids || [])
            .map(Number)
            .filter((n: number) => n > 0),
          at_userids: (t.at_userids || [])
            .map(String)
            .filter((s: string) => s !== ''),
          sender_userid: String(t.sender_userid || ''),
        }));
      } else {
        pendingRobotIds = [];
        pendingTargets = [];
      }
      loadData();
    }
  },
});

/**
 * 加载平台、消息类型、机器人、员工列表（并行）
 */
async function loadData() {
  loading.value = true;
  try {
    const [platformList, typesRes, adminRes] = await Promise.all([
      getOaPlatformList(),
      getOaMessageTypes(),
      getAdminList({ page: 1, pageSize: 500 }),
    ]);

    const platformRows: any[] = Array.isArray(platformList)
      ? platformList
      : platformList?.data || [];
    platforms.value = platformRows
      .filter((p: any) => p.enabled === 1)
      .sort((a: any, b: any) => (b.sort || 0) - (a.sort || 0));
    activePlatformTab.value = platforms.value[0]?.platform_code || '';

    // 消息类型按平台分组
    const typesData = (typesRes as any)?.data ?? typesRes ?? {};
    messageTypesMap.value = typesData;

    // 机器人：启用的 + 当前场景已绑定的（禁用也要能回显勾选）
    const robotRes = await getOaRobotList({
      page: 1,
      pageSize: 500,
    });
    const robotRows: any[] = robotRes?.items || robotRes?.data || [];
    const boundIdSet = new Set(pendingRobotIds.map((id) => Number(id)));
    allRobots.value = robotRows.filter((r: any) => {
      const onPlatform = platforms.value.some(
        (p: any) => p.platform_code === r.platform_code,
      );
      if (!onPlatform) return false;
      return Number(r.status) === 1 || boundIdSet.has(Number(r.id));
    });

    // 员工列表
    const adminRows: any[] = adminRes?.items || adminRes?.data || [];
    adminList.value = adminRows.map((a: any) => ({
      id: a.id,
      name: a.nick_name || a.name || a.username || `员工${a.id}`,
    }));

    // 数据加载完后处理回显
    if (pendingRobotIds.length > 0) {
      selectedRobots.value = groupRobotsByPlatform(pendingRobotIds);
    }
    await refreshAppMembers();

    // 初始化每个平台的默认消息类型（如未回显则默认 text）
    for (const platform of platforms.value) {
      const code = platform.platform_code;
      ensureAtSlot(code);
      if (!selectedMessageType.value[code]) {
        const types = messageTypesMap.value[code] || [];
        const defaultType = types.find((t) => t.message_type === 'text');
        selectedMessageType.value[code] = defaultType?.message_type || types[0]?.message_type || '';
        payloadValues.value[code] = {};
      }
    }
  } catch (e) {
    console.error('加载场景数据失败', e);
    message.error('加载场景数据失败，请刷新重试');
  } finally {
    loading.value = false;
  }
}

function groupRobotsByPlatform(robotIds: number[]): Record<string, number[]> {
  const result: Record<string, number[]> = {};
  for (const id of robotIds) {
    const robot = allRobots.value.find((r) => r.id === id);
    if (robot) {
      if (!result[robot.platform_code]) {
        result[robot.platform_code] = [];
      }
      result[robot.platform_code].push(id);
    }
  }
  return result;
}

/**
 * 组装当前表单的场景草稿（保存与测试发送共用）
 */
async function assembleSceneDraft() {
  const baseValues = await formApi.getValues();
  const message_config: Record<string, any> = {};
  for (const platform of platforms.value) {
    const code = platform.platform_code;
    const messageType = selectedMessageType.value[code];
    if (!messageType) continue;
    message_config[code] = {
      message_type: messageType,
      payload: payloadValues.value[code] || {},
    };
  }
  const robot_ids: number[] = [];
  for (const platformCode of Object.keys(selectedRobots.value)) {
    robot_ids.push(...(selectedRobots.value[platformCode] || []));
  }
  const at_users: Record<
    string,
    { admin_ids: number[]; userids: string[] }
  > = {};
  for (const platformCode of Object.keys(selectedAtUsers.value)) {
    if (isWorkWechatApp(platformCode)) continue;
    const slot = selectedAtUsers.value[platformCode] || {
      admin_ids: [],
      userids: [],
    };
    if (slot.admin_ids.length > 0 || slot.userids.length > 0) {
      at_users[platformCode] = {
        admin_ids: slot.admin_ids,
        userids: slot.userids,
      };
    }
  }
  return {
    ...baseValues,
    message_config,
    robot_ids,
    at_users,
    targets: sceneTargets.value,
  };
}

/**
 * 测试发送：用当前草稿 + 示例传参同步投递，结果展示在弹窗内
 */
async function handleTestSend() {
  const draft = await assembleSceneDraft();
  formSceneCode.value = String(draft.scene_code || formSceneCode.value || '');
  if (!draft.robot_ids || draft.robot_ids.length === 0) {
    message.warning('请先勾选至少一个推送机器人');
    return;
  }
  if (!draft.message_config || Object.keys(draft.message_config).length === 0) {
    message.warning('请先配置至少一个平台的消息类型');
    return;
  }
  const targetErr = targetsPanelRef.value?.validateBeforeSubmit?.() || '';
  if (targetErr) {
    message.warning(targetErr);
    return;
  }
  testing.value = true;
  testResults.value = [];
  testSummary.value = '正在测试发送...';
  try {
    const result = await testSendOaScene({
      id: Number(draft.id || 0) || undefined,
      scene_code: String(draft.scene_code || ''),
      scene_name: String(draft.scene_name || ''),
      message_config: draft.message_config,
      robot_ids: draft.robot_ids,
      at_users: draft.at_users,
      targets: draft.targets,
      test_params: { ...testParams.value },
    });
    const rows = Array.isArray(result?.results) ? result.results : [];
    testResults.value = rows;
    const total = result?.total ?? rows.length;
    const succ =
      result?.success_count ?? rows.filter((r: any) => r.success).length;
    const fail = total - succ;
    testSummary.value = `共 ${total} 条，成功 ${succ}，失败 ${fail}`;
    if (fail === 0) {
      message.success(testSummary.value);
    } else if (succ === 0) {
      message.error(testSummary.value);
    } else {
      message.warning(testSummary.value);
    }
  } catch (e: any) {
    testSummary.value = e?.message || '测试发送失败';
    message.error(testSummary.value);
  } finally {
    testing.value = false;
  }
}

function robotsOfPlatform(platformCode: string): any[] {
  return allRobots.value.filter((r: any) => r.platform_code === platformCode);
}

function checkedRobotsOfPlatform(platformCode: string): number[] {
  return selectedRobots.value[platformCode] || [];
}

function toggleRobot(platformCode: string, robotId: number, checked: boolean) {
  const current = new Set(selectedRobots.value[platformCode] || []);
  if (checked) current.add(robotId);
  else current.delete(robotId);
  selectedRobots.value = { ...selectedRobots.value, [platformCode]: Array.from(current) };
  if (isWorkWechatApp(platformCode)) {
    refreshAppMembers();
  }
}

function toggleAtUser(platformCode: string, adminId: number, checked: boolean) {
  ensureAtSlot(platformCode);
  const current = new Set(adminIdsOf(platformCode));
  if (checked) current.add(adminId);
  else current.delete(adminId);
  selectedAtUsers.value = {
    ...selectedAtUsers.value,
    [platformCode]: {
      admin_ids: Array.from(current),
      userids: useridsOf(platformCode),
    },
  };
}

function toggleAtMember(platformCode: string, userid: string, checked: boolean) {
  ensureAtSlot(platformCode);
  const current = new Set(useridsOf(platformCode));
  if (checked) current.add(userid);
  else current.delete(userid);
  selectedAtUsers.value = {
    ...selectedAtUsers.value,
    [platformCode]: {
      admin_ids: adminIdsOf(platformCode),
      userids: Array.from(current),
    },
  };
}

function toggleAllRobots(platformCode: string, e: any) {
  const checked = (e?.target as HTMLInputElement)?.checked;
  const robotIds = robotsOfPlatform(platformCode).map((r) => r.id);
  selectedRobots.value = {
    ...selectedRobots.value,
    [platformCode]: checked ? robotIds : [],
  };
  if (isWorkWechatApp(platformCode)) {
    refreshAppMembers();
  }
}

function toggleAllAtUsers(platformCode: string, e: any) {
  const checked = (e?.target as HTMLInputElement)?.checked;
  const adminIds = adminList.value.map((a) => a.id);
  ensureAtSlot(platformCode);
  selectedAtUsers.value = {
    ...selectedAtUsers.value,
    [platformCode]: {
      admin_ids: checked ? adminIds : [],
      userids: useridsOf(platformCode),
    },
  };
}

function toggleAllAtMembers(platformCode: string, e: any) {
  const checked = (e?.target as HTMLInputElement)?.checked;
  const allIds = (membersByPlatform.value[platformCode] || []).map((m) => m.userid);
  ensureAtSlot(platformCode);
  selectedAtUsers.value = {
    ...selectedAtUsers.value,
    [platformCode]: {
      admin_ids: adminIdsOf(platformCode),
      userids: checked ? allIds : [],
    },
  };
}

/**
 * 按已选应用 API 机器人合并拉取群成员（userid 去重）
 */
async function refreshAppMembers() {
  const appCodes = platforms.value
    .map((p) => p.platform_code)
    .filter((code) => isWorkWechatApp(code));
  for (const code of appCodes) {
    const robotIds = selectedRobots.value[code] || [];
    if (robotIds.length === 0) {
      membersByPlatform.value = { ...membersByPlatform.value, [code]: [] };
      continue;
    }
    try {
      const list = await getOaRobotChatMembers({ robot_ids: robotIds });
      const rows: any[] = Array.isArray(list) ? list : list?.data || [];
      membersByPlatform.value = {
        ...membersByPlatform.value,
        [code]: rows.map((m) => ({
          userid: String(m.userid),
          name: String(m.name || ''),
        })),
      };
    } catch (e) {
      console.error('加载应用群成员失败', e);
      membersByPlatform.value = { ...membersByPlatform.value, [code]: [] };
    }
  }
}

/**
 * 获取指定平台当前消息类型对应的 payload_schema（解析 JSON）
 */
function currentPayloadSchema(platformCode: string): PayloadFieldSchema[] {
  const messageType = selectedMessageType.value[platformCode];
  if (!messageType) return [];
  const types = messageTypesMap.value[platformCode] || [];
  const typeInfo = types.find((t) => t.message_type === messageType);
  if (!typeInfo?.payload_schema) return [];
  try {
    return JSON.parse(typeInfo.payload_schema);
  } catch {
    return [];
  }
}

/**
 * 获取指定平台 payload 字段当前值
 */
function getPayloadValue(platformCode: string, fieldName: string): any {
  return payloadValues.value[platformCode]?.[fieldName];
}

/**
 * 设置指定平台 payload 字段值（不可变更新）
 */
function setPayloadValue(platformCode: string, fieldName: string, value: any) {
  const current = payloadValues.value[platformCode] || {};
  payloadValues.value = {
    ...payloadValues.value,
    [platformCode]: { ...current, [fieldName]: value },
  };
}

/**
 * 切换平台的消息类型时，清空 payload
 */
function handleMessageTypeChange(platformCode: string, messageType: string) {
  selectedMessageType.value = {
    ...selectedMessageType.value,
    [platformCode]: messageType,
  };
  payloadValues.value = {
    ...payloadValues.value,
    [platformCode]: {},
  };
}

const isEmpty = computed(() => platforms.value.length === 0);

watch(
  () => platforms.value,
  (list) => {
    const validCodes = new Set(list.map((p) => p.platform_code));
    const newRobots: Record<string, number[]> = {};
    const newAtUsers: Record<string, { admin_ids: number[]; userids: string[] }> =
      {};
    for (const code of validCodes) {
      newRobots[code] = selectedRobots.value[code] || [];
      newAtUsers[code] = selectedAtUsers.value[code] || {
        admin_ids: [],
        userids: [],
      };
    }
    selectedRobots.value = newRobots;
    selectedAtUsers.value = newAtUsers;
  },
);
</script>

<template>
  <Modal
    :title="`${isUpdate === true ? '编辑' : '新增'}通知场景`"
    class="w-[80%]"
  >
    <Spin :spinning="loading">
      <!-- 基础信息表单 -->
      <Form />

      <!-- 启用平台 Tab -->
      <div class="mt-4">
        <div class="mb-2 font-medium">
          各平台消息配置 + 关联机器人 + @ 人员
        </div>
        <div v-if="isEmpty" class="py-4 text-center text-gray-400">
          暂无启用的平台，请先在「系统配置 → OA 通知」中启用平台
        </div>
        <Tabs v-else v-model:active-key="activePlatformTab">
          <Tabs.TabPane
            v-for="platform in platforms"
            :key="platform.platform_code"
            :tab="platform.name"
          >
            <div class="oa-scene-tab">
              <!-- 1. 消息类型选择 -->
              <div class="section">
                <div class="section-title">消息类型</div>
                <RadioGroup
                  :value="selectedMessageType[platform.platform_code]"
                  size="small"
                  @update:value="
                    (val) => handleMessageTypeChange(platform.platform_code, val)
                  "
                >
                  <Radio
                    v-for="opt in (messageTypesMap[platform.platform_code] || [])"
                    :key="opt.message_type"
                    :value="opt.message_type"
                  >
                    {{ opt.name }}
                  </Radio>
                </RadioGroup>
              </div>

              <!-- 2. 消息内容表单（动态 payload_schema） -->
              <div class="section">
                <div class="section-title">消息内容</div>
                <div class="payload-form">
                  <template
                    v-for="field in currentPayloadSchema(platform.platform_code)"
                    :key="field.name"
                  >
                    <!-- 企微模板卡片：用专用编辑器 -->
                    <div
                      v-if="field.component === 'TemplateCardEditor'"
                      class="payload-row"
                    >
                      <label class="payload-label">{{ field.label }}</label>
                      <TemplateCardForm
                        :model-value="getPayloadValue(platform.platform_code, 'template_card') || {}"
                        @update:model-value="
                          (val) => setPayloadValue(platform.platform_code, 'template_card', val)
                        "
                      />
                    </div>

                    <!-- 图片素材选择 -->
                    <div
                      v-else-if="field.component === 'GalleryPickLink'"
                      class="payload-row"
                    >
                      <label class="payload-label">
                        {{ field.label }}
                        <span v-if="field.required" class="required">*</span>
                      </label>
                      <div class="payload-image">
                        <Input
                          :value="getPayloadValue(platform.platform_code, field.name)"
                          :placeholder="field.props?.placeholder"
                          size="small"
                          read-only
                        />
                        <GalleryPickLink
                          :accept-types="field.props?.acceptTypes || [0]"
                          @select="
                            (urls) => setPayloadValue(platform.platform_code, field.name, urls[0] || '')
                          "
                        />
                      </div>
                    </div>

                    <!-- 文本域 -->
                    <div v-else-if="field.component === 'Textarea'" class="payload-row">
                      <label class="payload-label">
                        {{ field.label }}
                        <span v-if="field.required" class="required">*</span>
                      </label>
                      <Textarea
                        :value="getPayloadValue(platform.platform_code, field.name)"
                        :rows="field.props?.rows || 3"
                        :placeholder="field.props?.placeholder"
                        @update:value="
                          (val) => setPayloadValue(platform.platform_code, field.name, val)
                        "
                      />
                    </div>

                    <!-- 单选按钮组 -->
                    <div v-else-if="field.component === 'RadioGroup'" class="payload-row">
                      <label class="payload-label">
                        {{ field.label }}
                        <span v-if="field.required" class="required">*</span>
                      </label>
                      <RadioGroup
                        :value="getPayloadValue(platform.platform_code, field.name)"
                        :options="field.props?.options"
                        size="small"
                        @update:value="
                          (val) => setPayloadValue(platform.platform_code, field.name, val)
                        "
                      />
                    </div>

                    <!-- 下拉选择 -->
                    <div v-else-if="field.component === 'Select'" class="payload-row">
                      <label class="payload-label">
                        {{ field.label }}
                        <span v-if="field.required" class="required">*</span>
                      </label>
                      <Select
                        :value="getPayloadValue(platform.platform_code, field.name)"
                        :options="field.props?.options"
                        :placeholder="field.props?.placeholder"
                        size="small"
                        @update:value="
                          (val) => setPayloadValue(platform.platform_code, field.name, val)
                        "
                      />
                    </div>

                    <!-- 数字输入 -->
                    <div v-else-if="field.component === 'InputNumber'" class="payload-row">
                      <label class="payload-label">
                        {{ field.label }}
                        <span v-if="field.required" class="required">*</span>
                      </label>
                      <InputNumber
                        :value="getPayloadValue(platform.platform_code, field.name)"
                        :placeholder="field.props?.placeholder"
                        size="small"
                        style="width: 100%"
                        @update:value="
                          (val) => setPayloadValue(platform.platform_code, field.name, val)
                        "
                      />
                    </div>

                    <!-- 默认：单行文本 -->
                    <div v-else class="payload-row">
                      <label class="payload-label">
                        {{ field.label }}
                        <span v-if="field.required" class="required">*</span>
                      </label>
                      <Input
                        :value="getPayloadValue(platform.platform_code, field.name)"
                        :placeholder="field.props?.placeholder"
                        size="small"
                        @update:value="
                          (val) => setPayloadValue(platform.platform_code, field.name, val)
                        "
                      />
                    </div>
                  </template>

                  <Empty
                    v-if="currentPayloadSchema(platform.platform_code).length === 0"
                    description="该消息类型无需配置内容"
                    :image-style="{ height: '40px' }"
                  />
                </div>
              </div>

              <!-- 3. 机器人多选 -->
              <div class="section">
                <div class="mb-2 flex items-center">
                  <Checkbox
                    :checked="
                      robotsOfPlatform(platform.platform_code).length > 0 &&
                      checkedRobotsOfPlatform(platform.platform_code).length ===
                        robotsOfPlatform(platform.platform_code).length
                    "
                    @change="toggleAllRobots(platform.platform_code, $event)"
                  >
                    <span class="font-medium">推送机器人（全选）</span>
                  </Checkbox>
                </div>
                <div
                  v-if="robotsOfPlatform(platform.platform_code).length === 0"
                  class="text-gray-400"
                >
                  该平台暂无启用的机器人
                </div>
                <Checkbox.Group
                  v-else
                  :value="checkedRobotsOfPlatform(platform.platform_code)"
                  class="flex flex-wrap gap-2"
                >
                  <Checkbox
                    v-for="robot in robotsOfPlatform(platform.platform_code)"
                    :key="robot.id"
                    :value="robot.id"
                    :checked="
                      checkedRobotsOfPlatform(platform.platform_code).includes(robot.id)
                    "
                    @change="
                      toggleRobot(
                        platform.platform_code,
                        robot.id,
                        ($event.target as HTMLInputElement).checked,
                      )
                    "
                  >
                    {{ robot.name
                    }}{{ Number(robot.status) === 0 ? '（已禁用）' : '' }}
                  </Checkbox>
                </Checkbox.Group>
              </div>

              <!-- 4. 应用 API：投递目标（人/多群/@）；其他平台：平台级 @ -->
              <div v-if="isWorkWechatApp(platform.platform_code)" class="section">
                <div class="section-title">投递目标</div>
                <SceneTargetsPanel
                  ref="targetsPanelRef"
                  v-model="sceneTargets"
                  :admin-list="adminList"
                  :platform-code="platform.platform_code"
                />
              </div>
              <div v-else class="section">
                <div class="mb-2 flex items-center">
                  <Checkbox
                    :checked="
                      adminList.length > 0 &&
                      adminIdsOf(platform.platform_code).length ===
                        adminList.length
                    "
                    @change="toggleAllAtUsers(platform.platform_code, $event)"
                  >
                    <span class="font-medium">@ 系统员工</span>
                  </Checkbox>
                </div>
                <div v-if="adminList.length === 0" class="text-gray-400">
                  暂无员工可选
                </div>
                <Checkbox.Group
                  v-else
                  :value="adminIdsOf(platform.platform_code)"
                  class="flex flex-wrap gap-2"
                >
                  <Checkbox
                    v-for="admin in adminList"
                    :key="admin.id"
                    :value="admin.id"
                    :checked="
                      adminIdsOf(platform.platform_code).includes(admin.id)
                    "
                    @change="
                      toggleAtUser(
                        platform.platform_code,
                        admin.id,
                        ($event.target as HTMLInputElement).checked,
                      )
                    "
                  >
                    {{ admin.name }}
                  </Checkbox>
                </Checkbox.Group>
              </div>
            </div>
          </Tabs.TabPane>
        </Tabs>

        <!-- 业务传参示例 + 测试结果（全平台共用，与 dispatch 覆盖字段对齐） -->
        <div class="section dispatch-params">
          <div class="section-title">业务传参（测试用）</div>
          <Alert
            type="info"
            show-icon
            class="mb-3"
            message="业务方调用示例"
            :description="`OaNotifyService::dispatch('${formSceneCode || 'scene_code'}', ['content' => '...', 'title' => '...'])；非空示例值会覆盖场景 payload 对应字段`"
          />
          <div
            v-for="field in DISPATCH_PARAM_FIELDS"
            :key="field.key"
            class="payload-row mb-2"
          >
            <label class="payload-label">
              <code>{{ field.label }}</code>
              <span class="param-hint">{{ field.hint }}</span>
            </label>
            <Input
              v-model:value="testParams[field.key]"
              :placeholder="`示例值（可选）`"
              size="small"
              allow-clear
            />
          </div>

          <div v-if="testResults.length > 0 || testSummary" class="test-results">
            <Alert
              v-if="testSummary"
              :type="
                testResults.length === 0
                  ? 'info'
                  : testResults.every((r) => r.success)
                    ? 'success'
                    : testResults.some((r) => r.success)
                      ? 'warning'
                      : 'error'
              "
              :message="testSummary"
              show-icon
              class="mb-2"
            />
            <div
              v-for="(item, idx) in testResults"
              :key="`${item.robot_id}-${idx}`"
              class="result-item"
            >
              <Tag :color="item.success ? 'success' : 'error'">
                {{ item.success ? '成功' : '失败' }}
              </Tag>
              <span class="result-name">{{ item.robot_name }}</span>
              <span class="result-type">({{ item.platform_code }})</span>
              <span v-if="item.target_label" class="result-target">
                → {{ item.target_label }}
              </span>
              <span v-if="item.cost_ms" class="result-cost">
                {{ item.cost_ms }}ms
              </span>
              <div v-if="!item.success && item.message" class="result-error">
                {{ item.message }}
              </div>
            </div>
          </div>
        </div>
      </div>
    </Spin>

    <template #prepend-footer>
      <Button type="default" :loading="testing" @click="handleTestSend">
        测试发送
      </Button>
    </template>
  </Modal>
</template>

<style scoped>
.oa-scene-tab {
  max-height: 600px;
  overflow-y: auto;
  padding: 12px;
}

.section {
  margin-bottom: 20px;
  padding-bottom: 16px;
  border-bottom: 1px dashed var(--ant-color-border-secondary, #e5e6eb);
}

.section:last-child {
  border-bottom: none;
}

.section-title {
  margin-bottom: 12px;
  font-size: 13px;
  font-weight: 600;
  color: var(--ant-color-text, #1d2129);
}

.payload-form {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.payload-row {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.payload-label {
  font-size: 12px;
  color: var(--ant-color-text-secondary, #4e5969);
}

.payload-label .required {
  color: var(--ant-color-error, #f53f3f);
  margin-left: 2px;
}

.payload-image {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.dispatch-params {
  margin-top: 8px;
}

.param-hint {
  margin-left: 8px;
  font-weight: 400;
  color: var(--ant-color-text-tertiary, #86909c);
}

.test-results {
  margin-top: 12px;
  padding-top: 12px;
  border-top: 1px dashed var(--ant-color-border-secondary, #e5e6eb);
}

.result-item {
  padding: 8px 0;
  font-size: 12px;
  border-bottom: 1px solid var(--ant-color-split, #f2f3f5);
}

.result-name {
  margin-left: 6px;
  font-weight: 500;
}

.result-type,
.result-target,
.result-cost {
  margin-left: 6px;
  color: var(--ant-color-text-tertiary, #86909c);
}

.result-error {
  margin-top: 4px;
  color: var(--ant-color-error, #f53f3f);
  word-break: break-all;
}
</style>
