import {
  CheckCircleOutlined,
  EditOutlined,
  ExclamationCircleOutlined,
  FormOutlined,
} from '@ant-design/icons';
import { Dropdown, Input, message, Modal, Select, theme } from 'antd';
import { modelsMap } from 'generated/models.index';
import React, { useCallback, useEffect, useRef, useState } from 'react';
import { useAgent } from './AgentContext';
import { AgentType } from './agentAttributes';
import {
  getInspectorActions,
  InspectedElementInfo,
  InspectorAction,
} from './inspectorActions';
import { generatePrompt } from './promptGenerator';
import {
  patchBooleanProp,
  patchEnumProp,
  patchStringProp,
  readBooleanProp,
} from './propPatcher';

const TYPE_LABELS: Record<AgentType, string> = {
  'list-column': '表格列',
  'form-field': '表单字段',
  'show-field': '详情字段',
  'list-search-bar': '搜索栏',
  'list-header': '列表头部',
  'list-row-actions': '行操作',
  'list-bulk-actions': '批量操作',
  'canvas-component': '画布组件',
  'show-header': '详情页工具栏',
  'app-header': 'App 顶部导航',
  'app-title': 'Logo 和标题',
};

/** Get all field names for a resource from the generated models map. */
function getModelFields(resource: string): { name: string; type: string }[] {
  // modelsMap keys are PascalCase (e.g. "Event"), resource is camelCase (e.g. "event")
  const key = resource.charAt(0).toUpperCase() + resource.slice(1);
  const entry = (modelsMap as Record<string, { model: Record<string, any> }>)[
    key
  ];
  if (!entry?.model) return [];
  return Object.values(entry.model).map((f) => ({
    name: f.name as string,
    type: f.type as string,
  }));
}

/** Collect fields already rendered on the current page. */
function getVisibleFields(type: AgentType): string[] {
  const selector =
    type === 'list-column'
      ? '[data-agent-type="list-column"][data-agent-field]'
      : type === 'form-field'
        ? '[data-agent-type="form-field"][data-agent-field]'
        : '[data-agent-type="show-field"][data-agent-field]';
  return Array.from(document.querySelectorAll<HTMLElement>(selector))
    .map((el) => el.dataset.agentField!)
    .filter(Boolean);
}

/** Returns fields that exist in the model but are not currently displayed. */
function getHiddenFields(
  resource: string,
  type: AgentType,
): { name: string; type: string }[] {
  const visible = new Set(getVisibleFields(type));
  return getModelFields(resource).filter((f) => !visible.has(f.name));
}

/** Confirm modal shown after user picks a field from the sub-menu. */
interface FieldConfirmModalProps {
  open: boolean;
  actionLabel: string;
  fieldName: string;
  onOk: () => void;
  onCancel: () => void;
}

const FieldConfirmModal: React.FC<FieldConfirmModalProps> = ({
  open,
  actionLabel,
  fieldName,
  onOk,
  onCancel,
}) => {
  const { token } = theme.useToken();
  return (
    <Modal
      title={
        <span style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
          <span
            style={{
              display: 'inline-flex',
              alignItems: 'center',
              justifyContent: 'center',
              width: 28,
              height: 28,
              borderRadius: '50%',
              background: token.colorSuccessBg,
              color: token.colorSuccess,
              fontSize: 14,
              flexShrink: 0,
            }}
          >
            <CheckCircleOutlined />
          </span>
          <span style={{ fontWeight: 600, fontSize: 15 }}>确认操作</span>
        </span>
      }
      open={open}
      onOk={onOk}
      onCancel={onCancel}
      okText="确认"
      cancelText="取消"
      zIndex={10010}
      width={400}
      styles={{
        header: {
          padding: '16px 20px 12px',
          borderBottom: `1px solid ${token.colorBorderSecondary}`,
          marginBottom: 0,
        },
        body: { padding: '16px 20px 8px' },
        footer: { padding: '12px 20px 16px' },
      }}
      okButtonProps={{ style: { borderRadius: 6 } }}
      cancelButtonProps={{ style: { borderRadius: 6 } }}
    >
      <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
        <div
          style={{
            padding: '8px 12px',
            background: token.colorFillQuaternary,
            borderRadius: token.borderRadiusLG,
            border: `1px solid ${token.colorBorderSecondary}`,
          }}
        >
          <div
            style={{
              fontSize: 11,
              fontWeight: 500,
              color: token.colorTextTertiary,
              letterSpacing: '0.02em',
              textTransform: 'uppercase',
              marginBottom: 4,
            }}
          >
            操作
          </div>
          <div style={{ fontSize: 13, color: token.colorText }}>
            {actionLabel}
          </div>
        </div>
        <div
          style={{
            padding: '8px 12px',
            background: token.colorPrimaryBg,
            borderRadius: token.borderRadiusLG,
            border: `1px solid ${token.colorPrimaryBorder}`,
          }}
        >
          <div
            style={{
              fontSize: 11,
              fontWeight: 500,
              color: token.colorTextTertiary,
              letterSpacing: '0.02em',
              textTransform: 'uppercase',
              marginBottom: 4,
            }}
          >
            选中字段
          </div>
          <div
            style={{
              fontSize: 14,
              fontWeight: 600,
              color: token.colorPrimary,
              fontFamily: 'monospace',
            }}
          >
            {fieldName}
          </div>
        </div>
      </div>
    </Modal>
  );
};

interface ConfirmModalProps {
  open: boolean;
  action: InspectorAction | null;
  onOk: () => void;
  onCancel: () => void;
}

const ConfirmModal: React.FC<ConfirmModalProps> = ({
  open,
  action,
  onOk,
  onCancel,
}) => {
  const { token } = theme.useToken();
  return (
    <Modal
      title={
        <span style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
          <ExclamationCircleOutlined style={{ color: token.colorWarning }} />
          <span style={{ fontWeight: 600, fontSize: 15 }}>{action?.label}</span>
        </span>
      }
      open={open}
      onOk={onOk}
      onCancel={onCancel}
      okText="确认"
      cancelText="取消"
      zIndex={10010}
      width={360}
      styles={{
        header: { borderBottom: 'none', paddingBottom: 8 },
        body: { padding: '4px 20px 8px' },
        footer: { borderTop: 'none' },
      }}
    >
      {action?.confirmDescription && (
        <p
          style={{
            margin: 0,
            fontSize: 13,
            color: token.colorTextSecondary,
            lineHeight: '1.6',
          }}
        >
          {action.confirmDescription}
        </p>
      )}
    </Modal>
  );
};

interface FreeInputModalProps {
  open: boolean;
  mode: 'freeInput' | 'requiresInput';
  action: InspectorAction | null;
  value: string;
  onChange: (v: string) => void;
  onOk: () => void;
  onCancel: () => void;
}

const FreeInputModal: React.FC<FreeInputModalProps> = ({
  open,
  mode,
  action,
  value,
  onChange,
  onOk,
  onCancel,
}) => {
  const { token } = theme.useToken();
  const isRequiresInput = mode === 'requiresInput';
  const Icon = isRequiresInput ? EditOutlined : FormOutlined;
  const actionLabel = action?.label;

  return (
    <Modal
      title={
        <span style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
          <span
            style={{
              display: 'inline-flex',
              alignItems: 'center',
              justifyContent: 'center',
              width: 28,
              height: 28,
              borderRadius: '50%',
              background: isRequiresInput
                ? token.colorPrimaryBg
                : token.colorInfoBg,
              color: isRequiresInput ? token.colorPrimary : token.colorInfo,
              fontSize: 14,
              flexShrink: 0,
            }}
          >
            <Icon />
          </span>
          <span style={{ fontWeight: 600, fontSize: 15 }}>
            {isRequiresInput ? '补充说明' : '输入自定义需求'}
          </span>
        </span>
      }
      open={open}
      onOk={onOk}
      onCancel={onCancel}
      okText="确认发送"
      cancelText="取消"
      zIndex={10010}
      width={480}
      styles={{
        header: {
          padding: '16px 20px 12px',
          borderBottom: `1px solid ${token.colorBorderSecondary}`,
          marginBottom: 0,
        },
        body: { padding: '16px 20px 8px' },
        footer: { padding: '12px 20px 16px' },
      }}
      okButtonProps={{
        style: { borderRadius: 6 },
        disabled: mode === 'requiresInput' && !value.trim(),
      }}
      cancelButtonProps={{ style: { borderRadius: 6 } }}
    >
      <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
        {/* 操作上下文提示区 */}
        {actionLabel && (
          <div
            style={{
              display: 'flex',
              alignItems: 'flex-start',
              gap: 8,
              padding: '8px 12px',
              background: token.colorFillQuaternary,
              borderRadius: token.borderRadiusLG,
              border: `1px solid ${token.colorBorderSecondary}`,
            }}
          >
            <span
              style={{
                fontSize: 11,
                fontWeight: 500,
                color: token.colorTextTertiary,
                whiteSpace: 'nowrap',
                marginTop: 1,
                letterSpacing: '0.02em',
                textTransform: 'uppercase',
              }}
            >
              当前操作
            </span>
            <span
              style={{
                fontSize: 13,
                color: token.colorTextSecondary,
                fontWeight: 500,
                lineHeight: '20px',
              }}
            >
              {actionLabel}
            </span>
          </div>
        )}

        {/* 说明文字 */}
        <p
          style={{
            margin: 0,
            fontSize: 13,
            color: token.colorTextTertiary,
            lineHeight: '20px',
          }}
        >
          {isRequiresInput
            ? '请补充具体要求，AI 将在执行操作时参考你的说明。'
            : '请描述你希望 AI 执行的自定义操作。'}
        </p>

        {/* TextArea */}
        <Input.TextArea
          autoFocus
          rows={4}
          value={value}
          onChange={(e) => onChange(e.target.value)}
          placeholder={
            isRequiresInput
              ? action?.inputPlaceholder || '请补充具体要求...'
              : '请描述你想要的自定义操作...'
          }
          style={{
            borderRadius: token.borderRadiusLG,
            fontSize: 13,
            lineHeight: '1.6',
            resize: 'none',
          }}
          styles={{ textarea: { padding: '10px 12px' } }}
          onPressEnter={(e) => {
            if (e.metaKey || e.ctrlKey) {
              if (mode === 'requiresInput' && !value.trim()) return;
              onOk();
            }
          }}
        />

        {/* 快捷键提示 */}
        <p
          style={{
            margin: 0,
            fontSize: 12,
            color: token.colorTextQuaternary,
            textAlign: 'right',
          }}
        >
          按 ⌘ Enter 快速确认
        </p>
      </div>
    </Modal>
  );
};

// ── QuickSelectModal ───────────────────────────────────────────────────────────────────

interface QuickSelectModalProps {
  open: boolean;
  action: InspectorAction | null;
  onOk: (value: string) => void;
  onCancel: () => void;
}

const QuickSelectModal: React.FC<QuickSelectModalProps> = ({
  open,
  action,
  onOk,
  onCancel,
}) => {
  const { token } = theme.useToken();
  const [value, setValue] = useState<string>('');

  useEffect(() => {
    if (open) setValue('');
  }, [open]);

  return (
    <Modal
      title={
        <span style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
          <span style={{ fontWeight: 600, fontSize: 15 }}>
            {action?.label ?? '选择'}
          </span>
        </span>
      }
      open={open}
      onOk={() => value && onOk(value)}
      onCancel={onCancel}
      okText="确认"
      cancelText="取消"
      okButtonProps={{
        disabled: !value,
        style: { borderRadius: token.borderRadius },
      }}
      cancelButtonProps={{ style: { borderRadius: token.borderRadius } }}
      zIndex={10010}
      width={400}
      styles={{
        body: { padding: '16px 20px 8px' },
        footer: { padding: '12px 20px 16px' },
      }}
    >
      <Select
        autoFocus
        style={{ width: '100%' }}
        placeholder="请选择..."
        value={value || undefined}
        onChange={setValue}
        options={action?.quickSelectOptions?.map((o) => ({
          label: o.label,
          value: o.value,
        }))}
        size="large"
      />
    </Modal>
  );
};

// ── QuickInputModal ───────────────────────────────────────────────────────────────────

interface QuickInputModalProps {
  open: boolean;
  action: InspectorAction | null;
  onOk: (value: string) => void;
  onCancel: () => void;
}

const QuickInputModal: React.FC<QuickInputModalProps> = ({
  open,
  action,
  onOk,
  onCancel,
}) => {
  const { token } = theme.useToken();
  const [value, setValue] = useState('');

  useEffect(() => {
    if (open) setValue('');
  }, [open]);

  return (
    <Modal
      title={
        <span style={{ fontWeight: 600, fontSize: 15 }}>
          {action?.label ?? '修改'}
        </span>
      }
      open={open}
      onOk={() => onOk(value.trim())}
      onCancel={onCancel}
      okText="确认"
      cancelText="取消"
      okButtonProps={{ style: { borderRadius: token.borderRadius } }}
      cancelButtonProps={{ style: { borderRadius: token.borderRadius } }}
      zIndex={10010}
      width={400}
      styles={{
        body: { padding: '16px 20px 8px' },
        footer: { padding: '12px 20px 16px' },
      }}
    >
      <Input
        autoFocus
        size="large"
        value={value}
        onChange={(e) => setValue(e.target.value)}
        placeholder={action?.quickInputPlaceholder ?? '输入新值'}
        onPressEnter={() => onOk(value.trim())}
      />
    </Modal>
  );
};

function buildMenuItems(
  actions: InspectorAction[],
  handleAction: (a: InspectorAction) => void,
  hiddenFields: { name: string; type: string }[],
  onFieldPick: (action: InspectorAction, field: string) => void,
): any[] {
  return actions.map((action) => {
    if (action.fieldSubMenu) {
      const fieldChildren =
        hiddenFields.length > 0
          ? [
              {
                key: `${action.label}::__header`,
                label: (
                  <span
                    style={{
                      fontSize: 11,
                      color: '#8c8c8c',
                      fontWeight: 500,
                      letterSpacing: '0.02em',
                    }}
                  >
                    选择需要添加的字段
                  </span>
                ),
                disabled: true,
              },
              ...hiddenFields.map((f) => ({
                key: `${action.label}::${f.name}`,
                label: (
                  <span
                    style={{
                      display: 'flex',
                      alignItems: 'center',
                      justifyContent: 'space-between',
                      gap: 12,
                    }}
                  >
                    <span>{f.name}</span>
                    <span
                      style={{
                        fontSize: 11,
                        color: '#1677ff',
                        background: '#e6f4ff',
                        padding: '1px 6px',
                        borderRadius: 4,
                        fontFamily: 'monospace',
                        flexShrink: 0,
                      }}
                    >
                      {f.type}
                    </span>
                  </span>
                ),
                onClick: () => onFieldPick(action, f.name),
              })),
            ]
          : [{ key: '__empty', label: '（无可添加字段）', disabled: true }];
      return {
        key: action.label,
        label: action.label,
        children: fieldChildren,
      };
    }
    if (action.children && action.children.length > 0) {
      return {
        key: action.label,
        label: action.label,
        children: buildMenuItems(
          action.children,
          handleAction,
          hiddenFields,
          onFieldPick,
        ),
      };
    }
    return {
      key: action.label,
      label: action.label,
      onClick: () => handleAction(action),
    };
  });
}

function findAgentElement(x: number, y: number): HTMLElement | null {
  const elements = document.elementsFromPoint(x, y);
  for (const el of elements) {
    if (el instanceof HTMLElement && el.dataset.agentType) {
      return el;
    }
  }
  return null;
}

function parseElementInfo(
  el: HTMLElement,
  x: number,
  y: number,
): InspectedElementInfo {
  return {
    type: el.dataset.agentType as AgentType,
    field: el.dataset.agentField,
    resource: el.dataset.agentResource || '',
    file: el.dataset.agentFile,
    meta: el.dataset.agentMeta ? JSON.parse(el.dataset.agentMeta) : undefined,
    x,
    y,
  };
}

export const ElementInspector: React.FC = () => {
  const agent = useAgent();
  const [highlight, setHighlight] = useState<DOMRect | null>(null);
  const [label, setLabel] = useState('');
  const [menuInfo, setMenuInfo] = useState<InspectedElementInfo | null>(null);
  const [menuRect, setMenuRect] = useState<DOMRect | null>(null);
  const [menuOpen, setMenuOpen] = useState(false);
  const [freeInputVisible, setFreeInputVisible] = useState(false);
  const [freeInputValue, setFreeInputValue] = useState('');
  const [freeInputMode, setFreeInputMode] = useState<
    'freeInput' | 'requiresInput'
  >('freeInput');
  const [quickSelectVisible, setQuickSelectVisible] = useState(false);
  const [quickInputVisible, setQuickInputVisible] = useState(false);
  const pendingActionRef = useRef<InspectorAction | null>(null);
  const pendingMenuInfoRef = useRef<InspectedElementInfo | null>(null);

  // requiresConfirm state
  const [confirmVisible, setConfirmVisible] = useState(false);

  // Field sub-menu state
  const [fieldConfirmVisible, setFieldConfirmVisible] = useState(false);
  const [fieldConfirmField, setFieldConfirmField] = useState('');
  const pendingFieldActionRef = useRef<InspectorAction | null>(null);

  const inspecting = agent?.inspecting ?? false;

  // Fetch hidden fields when menu opens
  const hiddenFields = menuOpen
    ? getHiddenFields(menuInfo?.resource ?? '', menuInfo?.type ?? 'list-column')
    : [];

  const handleMouseMove = useCallback((e: MouseEvent) => {
    const el = findAgentElement(e.clientX, e.clientY);
    if (el) {
      const rect = el.getBoundingClientRect();
      setHighlight(rect);
      const type = el.dataset.agentType as AgentType;
      const field = el.dataset.agentField;
      setLabel(`${TYPE_LABELS[type] || type}${field ? ': ' + field : ''}`);
    } else {
      setHighlight(null);
      setLabel('');
    }
  }, []);

  const handleClick = useCallback(
    (e: MouseEvent) => {
      e.preventDefault();
      e.stopPropagation();
      const el = findAgentElement(e.clientX, e.clientY);
      if (!el) return;

      const rect = el.getBoundingClientRect();
      const info = parseElementInfo(el, e.clientX, e.clientY);
      // keep highlight visible while menu is open
      setHighlight(rect);
      setMenuRect(rect);
      setMenuInfo(info);
      setMenuOpen(true);
    },
    [agent],
  );

  const handleKeyDown = useCallback(
    (e: KeyboardEvent) => {
      if (e.key === 'Escape') {
        agent?.stopInspecting();
        setHighlight(null);
      }
    },
    [agent],
  );

  useEffect(() => {
    if (!inspecting || menuOpen) return;
    document.addEventListener('mousemove', handleMouseMove, true);
    document.addEventListener('click', handleClick, true);
    document.addEventListener('keydown', handleKeyDown, true);
    return () => {
      document.removeEventListener('mousemove', handleMouseMove, true);
      document.removeEventListener('click', handleClick, true);
      document.removeEventListener('keydown', handleKeyDown, true);
    };
  }, [inspecting, menuOpen, handleMouseMove, handleClick, handleKeyDown]);

  // Clear transient UI state when inspect mode is stopped externally
  // (e.g. dev-shell toggle button calls agent.stopInspecting() directly,
  // bypassing all the individual event handlers that normally reset state).
  useEffect(() => {
    if (!inspecting) {
      setHighlight(null);
      setLabel('');
      setMenuOpen(false);
      setMenuInfo(null);
      setMenuRect(null);
    }
  }, [inspecting]);

  const applyAction = useCallback(
    (action: InspectorAction, prompt?: string) => {
      if (!agent) return;
      const resolvedMenuInfo = pendingMenuInfoRef.current || menuInfo;
      if (!resolvedMenuInfo) return;
      const userPrompt = prompt || action.promptTemplate || '';
      const finalPrompt = generatePrompt({
        skill: action.skill,
        pageInfo: agent.pageInfo,
        userPrompt,
        inspectedElement: resolvedMenuInfo,
      });
      agent.setSelectedSkillId(action.skill);
      agent.setSelectedSubSkillId(null);
      agent.setUserPrompt(userPrompt);
      agent.setInspectedElement(resolvedMenuInfo);
      agent.sendPrompt(finalPrompt);
      agent.stopInspecting();
      setMenuOpen(false);
      setMenuInfo(null);
      setMenuRect(null);
      setHighlight(null);
      pendingMenuInfoRef.current = null;
    },
    [agent, menuInfo],
  );

  // 快捷操作：直接替换 code 中的 prop，通过 canvas-patch 推送
  const applyPatch = useCallback(
    async (newCode: string) => {
      const resolvedMenuInfo = pendingMenuInfoRef.current || menuInfo;
      if (!resolvedMenuInfo) return;
      const itemId = resolvedMenuInfo.meta?.canvasItemId;
      if (!itemId) {
        message.error('找不到 Canvas Item ID');
        return;
      }
      try {
        const res = await fetch('/canvas-patch', {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({ itemId, code: newCode }),
        });
        if (!res.ok) throw new Error('请求失败');
      } catch {
        message.error('画布更新失败，请确认 dev server 是否运行');
      }
      agent?.stopInspecting();
      setMenuOpen(false);
      setMenuInfo(null);
      setMenuRect(null);
      setHighlight(null);
      pendingMenuInfoRef.current = null;
      pendingActionRef.current = null;
    },
    [agent, menuInfo],
  );

  const handleMenuAction = useCallback(
    (action: InspectorAction) => {
      // quickToggle: 直接切换 boolean prop，无需弹框
      if (action.quickToggle && action.propName) {
        const currentCode = menuInfo?.meta?.code ?? '';
        pendingMenuInfoRef.current = menuInfo;
        const currentVal = readBooleanProp(
          currentCode,
          action.propName,
          action.defaultValue ?? true,
        );
        const newCode = patchBooleanProp(
          currentCode,
          action.propName,
          !currentVal,
        );
        setMenuOpen(false);
        applyPatch(newCode);
        return;
      }

      // quickSelect: 弹出下拉选择框
      if (action.quickSelect) {
        pendingActionRef.current = action;
        pendingMenuInfoRef.current = menuInfo;
        setMenuOpen(false);
        setQuickSelectVisible(true);
        return;
      }

      // quickInput: 弹出输入框
      if (action.quickInput) {
        pendingActionRef.current = action;
        pendingMenuInfoRef.current = menuInfo;
        setMenuOpen(false);
        setQuickInputVisible(true);
        return;
      }

      // openDialog: 弹出自由对话框（复用 freeInput 逻辑）
      if (action.openDialog) {
        pendingActionRef.current = { ...action, freeInput: true, skill: null };
        pendingMenuInfoRef.current = menuInfo;
        setFreeInputValue('');
        setFreeInputMode('freeInput');
        setFreeInputVisible(true);
        setMenuOpen(false);
        return;
      }

      if (action.freeInput) {
        pendingActionRef.current = action;
        pendingMenuInfoRef.current = menuInfo;
        setFreeInputValue('');
        setFreeInputMode('freeInput');
        setFreeInputVisible(true);
        setMenuOpen(false);
        return;
      }
      if (action.requiresInput) {
        pendingActionRef.current = action;
        pendingMenuInfoRef.current = menuInfo;
        setFreeInputValue('');
        setFreeInputMode('requiresInput');
        setFreeInputVisible(true);
        setMenuOpen(false);
        return;
      }
      if (action.requiresConfirm) {
        pendingActionRef.current = action;
        pendingMenuInfoRef.current = menuInfo;
        setConfirmVisible(true);
        setMenuOpen(false);
        return;
      }
      applyAction(action);
    },
    [applyAction, menuInfo],
  );

  const handleConfirmOk = useCallback(() => {
    const action = pendingActionRef.current;
    if (action) applyAction(action);
    setConfirmVisible(false);
    pendingActionRef.current = null;
  }, [applyAction]);

  const handleConfirmCancel = useCallback(() => {
    agent?.stopInspecting();
    setConfirmVisible(false);
    pendingActionRef.current = null;
    pendingMenuInfoRef.current = null;
    setMenuInfo(null);
    setMenuRect(null);
    setHighlight(null);
  }, [agent]);

  const handleFieldPick = useCallback(
    (action: InspectorAction, field: string) => {
      pendingFieldActionRef.current = action;
      pendingMenuInfoRef.current = menuInfo;
      setFieldConfirmField(field);
      setFieldConfirmVisible(true);
      setMenuOpen(false);
    },
    [menuInfo],
  );

  const handleFieldConfirmOk = useCallback(() => {
    const action = pendingFieldActionRef.current;
    if (action) {
      const prompt = `${action.promptTemplate}：${fieldConfirmField}`;
      applyAction(action, prompt);
    }
    setFieldConfirmVisible(false);
    pendingFieldActionRef.current = null;
  }, [applyAction, fieldConfirmField]);

  const handleFieldConfirmCancel = useCallback(() => {
    agent?.stopInspecting();
    setFieldConfirmVisible(false);
    pendingFieldActionRef.current = null;
    pendingMenuInfoRef.current = null;
    setMenuInfo(null);
    setMenuRect(null);
    setHighlight(null);
  }, [agent]);

  const handleFreeInputOk = useCallback(() => {
    const action = pendingActionRef.current;
    if (action) {
      if (freeInputMode === 'requiresInput') {
        const userInput = freeInputValue.trim();
        const parts = [action.promptTemplate || ''];
        const prefix =
          'promptPrefix' in action
            ? action.promptPrefix
            : action.promptSuffix
              ? ''
              : '修改为：';
        if (userInput)
          parts.push(prefix ? `${prefix}\n${userInput}` : userInput);
        if (action.promptSuffix) parts.push(action.promptSuffix);
        const combined = parts.filter(Boolean).join('\n\n');
        applyAction(action, combined);
      } else {
        applyAction(action, freeInputValue);
      }
    }
    setFreeInputVisible(false);
    pendingActionRef.current = null;
  }, [applyAction, freeInputValue, freeInputMode]);

  const handleFreeInputCancel = useCallback(() => {
    agent?.stopInspecting();
    setFreeInputVisible(false);
    pendingActionRef.current = null;
    pendingMenuInfoRef.current = null;
    setMenuInfo(null);
    setMenuRect(null);
    setHighlight(null);
  }, [agent]);

  const handleQuickSelectOk = useCallback(
    (value: string) => {
      const action = pendingActionRef.current;
      const currentCode = pendingMenuInfoRef.current?.meta?.code ?? '';
      if (action?.propName) {
        const newCode = patchEnumProp(currentCode, action.propName, value);
        applyPatch(newCode);
      }
      setQuickSelectVisible(false);
    },
    [applyPatch],
  );

  const handleQuickSelectCancel = useCallback(() => {
    setQuickSelectVisible(false);
    pendingActionRef.current = null;
    pendingMenuInfoRef.current = null;
    agent?.stopInspecting();
    setHighlight(null);
  }, [agent]);

  const handleQuickInputOk = useCallback(
    (value: string) => {
      const action = pendingActionRef.current;
      const currentCode = pendingMenuInfoRef.current?.meta?.code ?? '';
      if (action?.propName) {
        const newCode = patchStringProp(currentCode, action.propName, value);
        applyPatch(newCode);
      }
      setQuickInputVisible(false);
    },
    [applyPatch],
  );
  const handleQuickInputCancel = useCallback(() => {
    setQuickInputVisible(false);
    pendingActionRef.current = null;
    pendingMenuInfoRef.current = null;
    agent?.stopInspecting();
    setHighlight(null);
  }, [agent]);

  const handleMenuOpenChange = useCallback(
    (open: boolean) => {
      if (!open) {
        agent?.stopInspecting();
        setMenuOpen(false);
        setMenuInfo(null);
        setMenuRect(null);
        setHighlight(null);
      }
    },
    [agent],
  );

  if (!agent) return null;

  const actions = menuInfo ? getInspectorActions(menuInfo) : [];

  const menuItems = buildMenuItems(
    actions,
    handleMenuAction,
    hiddenFields,
    handleFieldPick,
  );

  return (
    <>
      {/* Overlay — captures mouse events during inspect mode */}
      {inspecting && !menuOpen && (
        <div
          style={{
            position: 'fixed',
            inset: 0,
            zIndex: 10000,
            cursor: 'crosshair',
          }}
        />
      )}

      {/* Highlight box — rendered independently so it persists while menu is open */}
      {highlight && (
        <>
          <div
            style={{
              position: 'fixed',
              left: highlight.left,
              top: highlight.top,
              width: highlight.width,
              height: highlight.height,
              border: '2px solid #1890ff',
              background: 'rgba(24,144,255,0.1)',
              pointerEvents: 'none',
              zIndex: 10001,
              borderRadius: 2,
            }}
          />
          {/* Label */}
          {label && (
            <div
              style={{
                position: 'fixed',
                left: highlight.left,
                top: Math.max(0, highlight.top - 26),
                background: '#1890ff',
                color: '#fff',
                fontSize: 12,
                padding: '2px 8px',
                borderRadius: '4px 4px 0 0',
                pointerEvents: 'none',
                zIndex: 10002,
                whiteSpace: 'nowrap',
              }}
            >
              {label}
            </div>
          )}
        </>
      )}

      {/* Action menu — anchor positioned at the clicked element's right-bottom */}
      <Dropdown
        menu={{ items: menuItems }}
        open={menuOpen}
        onOpenChange={handleMenuOpenChange}
        placement="bottomRight"
        trigger={['click']}
      >
        <div
          style={{
            position: 'fixed',
            left: menuRect ? menuRect.right : 0,
            top: menuRect ? menuRect.bottom : 0,
            width: 1,
            height: 1,
            zIndex: menuOpen ? 10003 : -1,
            pointerEvents: menuOpen ? 'auto' : 'none',
          }}
        />
      </Dropdown>

      {/* Free input modal */}
      <FreeInputModal
        open={freeInputVisible}
        mode={freeInputMode}
        action={pendingActionRef.current}
        value={freeInputValue}
        onChange={setFreeInputValue}
        onOk={handleFreeInputOk}
        onCancel={handleFreeInputCancel}
      />

      {/* requiresConfirm modal */}
      <ConfirmModal
        open={confirmVisible}
        action={pendingActionRef.current}
        onOk={handleConfirmOk}
        onCancel={handleConfirmCancel}
      />

      {/* Field sub-menu confirm modal */}
      <FieldConfirmModal
        open={fieldConfirmVisible}
        actionLabel={pendingFieldActionRef.current?.label ?? ''}
        fieldName={fieldConfirmField}
        onOk={handleFieldConfirmOk}
        onCancel={handleFieldConfirmCancel}
      />

      {/* Quick select modal */}
      <QuickSelectModal
        open={quickSelectVisible}
        action={pendingActionRef.current}
        onOk={handleQuickSelectOk}
        onCancel={handleQuickSelectCancel}
      />

      {/* Quick input modal */}
      <QuickInputModal
        open={quickInputVisible}
        action={pendingActionRef.current}
        onOk={handleQuickInputOk}
        onCancel={handleQuickInputCancel}
      />
    </>
  );
};

export default ElementInspector;
