/**
 * ConfirmationDialog — 工具执行确认对话框（v0.3.2 批量审批版本）
 *
 * 当 Agent 并行调用多个 requiresPermission=true 或 riskLevel>=HIGH 的工具时，
 * 通过此对话框批量请求用户确认。
 *
 * v0.3.2 关键改进：
 * 1. state 从单值改为数组，支持同时显示多个 pending 请求
 * 2. 弹框打开时主动调用 getPendingConfirmations 拉取已积压请求，
 *    解决并行 IPC 事件在前端 state 中互相覆盖丢失的问题
 * 3. 同工具多次调用按 toolName 分组展示（如 read_file (×5)）
 * 4. 支持批量勾选 / 批量批准 / 批量拒绝
 * 5. remember/autoExecute 按 toolName 去重应用到所有选中项
 *
 * 监听 IPC 事件 `tool:confirmationRequest`，显示工具详情，
 * 用户确认/拒绝后通过 `tool:confirmationResponseBatch` IPC 通道批量发送结果。
 */

import { useState, useEffect, useCallback, useMemo } from 'react';
import {
  Dialog, DialogTitle, DialogContent, DialogActions,
  Button, Typography, Box, Chip, Alert, FormControlLabel, Checkbox,
  Accordion, AccordionSummary, AccordionDetails,
  LinearProgress, List, ListItem, ListItemIcon, ListItemText,
  IconButton, Tooltip, Divider,
} from '@mui/material';
import { ShieldAlert, ChevronDown, Timer, RefreshCw } from 'lucide-react';

interface ConfirmationRequest {
  toolCallId: string;
  toolName: string;
  args: Record<string, unknown>;
  riskLevel: string;
  reason: string;
  /** 过期时间戳（ms），由后端 ConfirmationHook 注入，用于倒计时 */
  expiresAt?: number;
}

const RISK_COLORS: Record<string, 'default' | 'success' | 'warning' | 'error' | 'info'> = {
  safe: 'success',
  low: 'info',
  medium: 'warning',
  high: 'error',
  critical: 'error',
};

/**
 * 按工具名分组后的请求组
 */
interface GroupedRequests {
  toolName: string;
  riskLevel: string;
  /** 共享同一 riskLevel 的多个请求（riskLevel 来自 toolDef，同工具必然相同） */
  requests: ConfirmationRequest[];
}

export function ConfirmationDialog(): React.JSX.Element | null {
  const [requests, setRequests] = useState<ConfirmationRequest[]>([]);
  const [selectedIds, setSelectedIds] = useState<Set<string>>(new Set());
  const [remember, setRemember] = useState(false);
  const [autoExecute, setAutoExecute] = useState(false);
  const [remainingMs, setRemainingMs] = useState<number>(0);
  // 记录首次接收时的剩余时间，作为进度条总量（固定不变）
  const [initialMs, setInitialMs] = useState<number>(0);
  // #40 修复: autoExecute 永久自动执行风险高，勾选时弹出二次确认避免误点击
  const [confirmAutoExecute, setConfirmAutoExecute] = useState(false);

  // ===== 弹框打开时主动拉取已积压的 pending 请求 =====
  // 解决：并行工具触发的多个 IPC 事件可能在本组件 mount 前已到达，
  // 或在 React state 更新批次中被覆盖。主动拉取确保不丢请求。
  const refreshPending = useCallback(async (mergeNew?: ConfirmationRequest) => {
    try {
      const result = await window.metona?.tool?.getPendingConfirmations();
      const pendingList: ConfirmationRequest[] = result?.success ? result.data : [];
      // 合并新到的 IPC 请求（若 pending 快照已包含则去重）
      const merged = [...pendingList];
      if (mergeNew) {
        const exists = merged.some((r) => r.toolCallId === mergeNew.toolCallId);
        if (!exists) merged.push(mergeNew);
      }
      // 按 toolCallId 去重（防止 refresh 与 IPC 事件重复添加）
      const dedupedMap = new Map<string, ConfirmationRequest>();
      for (const r of merged) dedupedMap.set(r.toolCallId, r);
      const deduped = Array.from(dedupedMap.values());

      setRequests(deduped);
      // 默认全选
      setSelectedIds(new Set(deduped.map((r) => r.toolCallId)));
    } catch {
      // 拉取失败时回退到只显示新到的请求
      if (mergeNew) {
        setRequests([mergeNew]);
        setSelectedIds(new Set([mergeNew.toolCallId]));
      }
    }
  }, []);

  useEffect(() => {
    // 监听来自主进程的确认请求（通过 preload 暴露的 metona.tool API）
    const cleanup = window.metona?.tool?.onConfirmationRequest((data: unknown) => {
      const req = data as ConfirmationRequest;
      // 每次新请求到达时主动拉取完整 pending 列表，防止 state 覆盖丢失
      refreshPending(req);
      setRemember(false);
      setAutoExecute(false);
      // 初始化倒计时（使用本次请求的过期时间作为初始值）
      if (req.expiresAt) {
        const remain = Math.max(0, req.expiresAt - Date.now());
        setRemainingMs(remain);
        setInitialMs(remain);
      }
    });
    return cleanup;
  }, [refreshPending]);

  // ===== 监听 Agent 状态变化：INIT（新 run 开始）或 TERMINATED（run 结束/abort）时清空前端 state =====
  // 解决：abort 场景下后端 clearPending() 清空了 Map，但前端 requests state 不会自动同步，
  // 弹框会停留在已失效的请求上。用户操作后批量 IPC 返回 0 resolved，逻辑无害但 UX 差。
  // 新会话 INIT 时也清空，防止上一会话的残留请求污染新会话 UI。
  useEffect(() => {
    if (!window.metona?.agent?.onStateChange) return;
    const unsubscribe = window.metona.agent.onStateChange((state: unknown) => {
      const data = state as { state?: string; current?: string };
      const stateValue = data.state ?? data.current ?? '';
      // INIT: 新 run 开始（新会话或新消息）；TERMINATED: run 结束（正常完成/abort/超时/死循环）
      if (stateValue === 'INIT' || stateValue === 'TERMINATED') {
        setRequests([]);
        setSelectedIds(new Set());
      }
    });
    return unsubscribe;
  }, []);

  // 倒计时：每 200ms 更新剩余时间（取所有请求中最早过期的）
  useEffect(() => {
    if (requests.length === 0) return;
    const interval = setInterval(() => {
      // 取所有请求中最早过期的剩余时间
      const earliestExpires = requests
        .map((r) => r.expiresAt)
        .filter((v): v is number => typeof v === 'number')
        .sort((a, b) => a - b)[0];
      if (!earliestExpires) {
        setRemainingMs(0);
        return;
      }
      const remaining = earliestExpires - Date.now();
      if (remaining <= 0) {
        setRemainingMs(0);
        clearInterval(interval);
      } else {
        setRemainingMs(remaining);
      }
    }, 200);
    return () => clearInterval(interval);
  }, [requests]);

  // 按工具名分组（同工具多次调用折叠为一组）
  const grouped: GroupedRequests[] = useMemo(() => {
    const map = new Map<string, GroupedRequests>();
    for (const r of requests) {
      const existing = map.get(r.toolName);
      if (existing) {
        existing.requests.push(r);
      } else {
        map.set(r.toolName, {
          toolName: r.toolName,
          riskLevel: r.riskLevel,
          requests: [r],
        });
      }
    }
    return Array.from(map.values());
  }, [requests]);

  const handleToggleSelect = useCallback((toolCallId: string) => {
    setSelectedIds((prev) => {
      const next = new Set(prev);
      if (next.has(toolCallId)) {
        next.delete(toolCallId);
      } else {
        next.add(toolCallId);
      }
      return next;
    });
  }, []);

  const handleToggleGroupSelect = useCallback((group: GroupedRequests) => {
    const groupIds = group.requests.map((r) => r.toolCallId);
    setSelectedIds((prev) => {
      const next = new Set(prev);
      const allSelected = groupIds.every((id) => next.has(id));
      if (allSelected) {
        groupIds.forEach((id) => next.delete(id));
      } else {
        groupIds.forEach((id) => next.add(id));
      }
      return next;
    });
  }, []);

  const handleSelectAll = useCallback(() => {
    setSelectedIds(new Set(requests.map((r) => r.toolCallId)));
  }, [requests]);

  const handleDeselectAll = useCallback(() => {
    setSelectedIds(new Set());
  }, []);

  const handleRespond = useCallback((approved: boolean, onlySelected: boolean = true) => {
    // 决定要处理的 toolCallId 列表
    // onlySelected=true: 仅处理勾选项（用于"批准选中"）
    // onlySelected=false: 处理全部请求（用于"拒绝全部" / "批准全部"）
    const targetIds = onlySelected
      ? Array.from(selectedIds)
      : requests.map((r) => r.toolCallId);

    if (targetIds.length === 0) return;

    // 通过批量 IPC 通道发送响应
    // autoExecute 仅在批准时生效（拒绝时无需持久化）
    window.metona?.tool?.sendConfirmationResponseBatch({
      toolCallIds: targetIds,
      approved,
      remember,
      autoExecute: approved && autoExecute,
    });

    if (onlySelected) {
      // "批准选中"：只移除已处理的，保留未选中的 pending
      // 防止未选中的 pending 被清空后丢失（用户看不到，会超时失败）
      const targetSet = new Set(targetIds);
      const remaining = requests.filter((r) => !targetSet.has(r.toolCallId));
      setRequests(remaining);
      // 更新选中项：清空已处理的，保留未选中的（但实际上未选中的本来就不在 selectedIds 中）
      setSelectedIds(new Set());
      // 主动刷新后端 pending 列表，拉取可能新到达的请求
      // 用 setTimeout 避免与 setRequests 同批次，确保后端已处理完批量响应
      if (remaining.length === 0) {
        setTimeout(() => refreshPending(), 50);
      }
    } else {
      // "拒绝全部 / 批准全部"：清空所有
      setRequests([]);
      setSelectedIds(new Set());
    }
  }, [requests, selectedIds, remember, autoExecute, refreshPending]);

  if (requests.length === 0) return null;

  // 取所有请求中最早过期的，用于倒计时显示
  const earliestExpires = requests
    .map((r) => r.expiresAt)
    .filter((v): v is number => typeof v === 'number')
    .sort((a, b) => a - b)[0];

  const selectedCount = selectedIds.size;
  const totalCount = requests.length;
  const allSelected = selectedCount === totalCount;

  // 综合风险等级：取所有请求中最高的
  const highestRisk = requests.reduce<string>((highest, r) => {
    const order = ['safe', 'low', 'medium', 'high', 'critical'];
    return order.indexOf(r.riskLevel) > order.indexOf(highest) ? r.riskLevel : highest;
  }, 'safe');

  const riskColor = RISK_COLORS[highestRisk] ?? 'default';
  const remainingSec = Math.ceil(remainingMs / 1000);
  const isUrgent = remainingSec <= 10 && remainingSec > 0;
  const isExpired = remainingMs <= 0 && earliestExpires != null;
  const totalMs = initialMs || remainingMs;
  const progressPercent = totalMs > 0
    ? Math.max(0, Math.min(100, (remainingMs / totalMs) * 100))
    : 100;

  // 格式化参数显示
  const formatArg = (key: string, value: unknown): string => {
    if (typeof value === 'string') {
      return value.length > 200 ? value.slice(0, 200) + '...' : value;
    }
    if (value === null) return 'null';
    if (value === undefined) return 'undefined';
    try {
      return JSON.stringify(value, null, 2);
    } catch {
      return String(value);
    }
  };

  // 综合风险文案
  const batchReason = totalCount > 1
    ? `检测到 ${totalCount} 个并行工具调用请求确认（涉及 ${grouped.length} 个不同工具）。综合最高风险：${highestRisk}`
    : requests[0]?.reason ?? 'Agent 正在请求执行工具';

  return (
    <>
    <Dialog
      open={requests.length > 0}
      onClose={(_, reason) => {
        // 超时时禁止通过外部点击/ESC 关闭（与"拒绝全部"按钮 disabled 一致）
        // 防止超时后用户误触关闭，导致后端 pending 状态不一致
        if (isExpired) return;
        // 审查修复: 内层二次确认 Dialog 打开时，外层禁用 ESC/backdrop 关闭
        // 防止 ESC 穿透到外层导致意外拒绝所有工具执行
        if (confirmAutoExecute) return;
        // 只允许"拒绝全部"语义的关闭方式（点击外部 / ESC）
        // reason: 'backdropClick' | 'escapeKeyDown' | 'closeButtonClick'
        if (reason === 'backdropClick' || reason === 'escapeKeyDown') {
          handleRespond(false, false);
        }
      }}
      maxWidth="md"
      fullWidth
      slotProps={{
        paper: {
          sx: { bgcolor: 'background.paper' },
        },
      }}
    >
      <DialogTitle sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
        <ShieldAlert size={20} color="var(--mui-palette-warning-main)" />
        <Typography variant="h6" component="span">
          工具执行确认 {totalCount > 1 && `（${totalCount} 个并行请求）`}
        </Typography>
        <Box sx={{ flex: 1 }} />
        <Tooltip title="刷新 pending 列表">
          <IconButton size="small" onClick={() => refreshPending()}>
            <RefreshCw size={16} />
          </IconButton>
        </Tooltip>
      </DialogTitle>

      <DialogContent>
        <Alert severity={riskColor === 'error' ? 'error' : 'warning'} sx={{ mb: 2 }}>
          {batchReason}
        </Alert>

        {earliestExpires && !isExpired && (
          <Box sx={{ mb: 2, display: 'flex', alignItems: 'center', gap: 1 }}>
            <Timer
              size={16}
              color={isUrgent ? 'var(--mui-palette-error-main)' : 'var(--mui-palette-text-secondary)'}
              style={isUrgent ? { animation: 'metona-pulse 1s ease-in-out infinite' } : undefined}
            />
            <Typography
              variant="caption"
              sx={{
                color: isUrgent ? 'error.main' : 'text.secondary',
                fontWeight: isUrgent ? 700 : 500,
                minWidth: 80,
                animation: isUrgent ? 'metona-pulse 1s ease-in-out infinite' : 'none',
                '@keyframes metona-pulse': {
                  '0%, 100%': { opacity: 1 },
                  '50%': { opacity: 0.4 },
                },
              }}
            >
              {totalCount > 1 ? '最早过期 ' : '剩余 '}{remainingSec}s
            </Typography>
            <LinearProgress
              variant="determinate"
              value={progressPercent}
              color={isUrgent ? 'error' : 'primary'}
              sx={{ flex: 1, height: 6, borderRadius: 3 }}
            />
          </Box>
        )}

        {/* 选择控制条 */}
        <Box sx={{ mb: 1, display: 'flex', alignItems: 'center', gap: 1 }}>
          <Button size="small" onClick={handleSelectAll} disabled={allSelected}>
            全选
          </Button>
          <Button size="small" onClick={handleDeselectAll} disabled={selectedCount === 0}>
            全不选
          </Button>
          <Typography variant="caption" color="text.secondary" sx={{ ml: 'auto' }}>
            已选 {selectedCount} / {totalCount}
          </Typography>
        </Box>

        <Divider sx={{ mb: 1 }} />

        {/* 分组列表 */}
        <List sx={{ maxHeight: 400, overflow: 'auto', py: 0 }}>
          {grouped.map((group) => {
            const groupIds = group.requests.map((r) => r.toolCallId);
            const groupAllSelected = groupIds.every((id) => selectedIds.has(id));
            const groupSomeSelected = groupIds.some((id) => selectedIds.has(id));
            const groupRiskColor = RISK_COLORS[group.riskLevel] ?? 'default';
            const isMulti = group.requests.length > 1;

            return (
              <Accordion
                key={group.toolName}
                defaultExpanded
                sx={{ bgcolor: 'background.default', mb: 0.5 }}
              >
                <AccordionSummary expandIcon={<ChevronDown size={16} />}>
                  <Box sx={{ display: 'flex', alignItems: 'center', gap: 1, width: '100%', pr: 1 }}>
                    <Checkbox
                      size="small"
                      checked={groupAllSelected}
                      indeterminate={!groupAllSelected && groupSomeSelected}
                      onChange={(e) => {
                        e.stopPropagation();
                        handleToggleGroupSelect(group);
                      }}
                      onClick={(e) => e.stopPropagation()}
                    />
                    <Typography variant="body2" sx={{ fontWeight: 600 }}>
                      {group.toolName}
                    </Typography>
                    {isMulti && (
                      <Chip
                        label={`×${group.requests.length}`}
                        size="small"
                        color="primary"
                        variant="outlined"
                        sx={{ height: 20, fontSize: 11 }}
                      />
                    )}
                    <Chip
                      label={group.riskLevel}
                      color={groupRiskColor}
                      size="small"
                      sx={{ height: 20, fontSize: 11 }}
                    />
                  </Box>
                </AccordionSummary>
                <AccordionDetails sx={{ pt: 0 }}>
                  {group.requests.map((req, idx) => {
                    const isSelected = selectedIds.has(req.toolCallId);
                    return (
                      <ListItem
                        key={req.toolCallId}
                        sx={{
                          py: 0.5,
                          bgcolor: isSelected ? 'action.selected' : 'transparent',
                          borderRadius: 1,
                        }}
                        secondaryAction={
                          isMulti ? (
                            <Typography variant="caption" color="text.secondary">
                              #{idx + 1}
                            </Typography>
                          ) : undefined
                        }
                      >
                        <ListItemIcon sx={{ minWidth: 36 }}>
                          <Checkbox
                            size="small"
                            checked={isSelected}
                            onChange={() => handleToggleSelect(req.toolCallId)}
                          />
                        </ListItemIcon>
                        <ListItemText
                          primary={
                            <Box
                              component="pre"
                              sx={{
                                fontFamily: 'monospace',
                                fontSize: 11,
                                color: 'text.primary',
                                whiteSpace: 'pre-wrap',
                                wordBreak: 'break-word',
                                margin: 0,
                                maxHeight: 200,
                                overflow: 'auto',
                              }}
                            >
                              {Object.entries(req.args).map(([key, value]) => (
                                <Box key={key} component="div" sx={{ mb: 0.5 }}>
                                  <Typography
                                    component="span"
                                    variant="caption"
                                    sx={{ color: 'info.main', fontWeight: 700 }}
                                  >
                                    {key}:
                                  </Typography>
                                  <Typography
                                    component="span"
                                    variant="caption"
                                    sx={{ color: 'text.primary', ml: 1 }}
                                  >
                                    {formatArg(key, value)}
                                  </Typography>
                                </Box>
                              ))}
                              {Object.keys(req.args).length === 0 && (
                                <Typography variant="caption" color="text.secondary">
                                  （无参数）
                                </Typography>
                              )}
                            </Box>
                          }
                        />
                      </ListItem>
                    );
                  })}
                </AccordionDetails>
              </Accordion>
            );
          })}
        </List>

        <Divider sx={{ my: 1 }} />

        <FormControlLabel
          control={
            <Checkbox
              checked={remember}
              onChange={(e) => setRemember(e.target.checked)}
              size="small"
            />
          }
          label={
            <Typography variant="caption" color="text.secondary">
              在本次会话中记住此决定（同工具不再询问）
            </Typography>
          }
        />

        <FormControlLabel
          control={
            <Checkbox
              checked={autoExecute}
              onChange={(e) => {
                // #40 修复: autoExecute 永久自动执行风险高，勾选时弹出二次确认避免误点击
                if (e.target.checked) {
                  setConfirmAutoExecute(true);
                } else {
                  setAutoExecute(false);
                }
              }}
              size="small"
            />
          }
          label={
            <Typography variant="caption" color="text.secondary">
              永久自动执行选中工具（跨会话不再询问，可在设置中关闭）
              {selectedCount > 0 && autoExecute && (
                <Box component="span" sx={{ color: 'warning.main', ml: 1 }}>
                  · 将应用到 {new Set(Array.from(selectedIds).map((id) => requests.find((r) => r.toolCallId === id)?.toolName).filter(Boolean) as string[]).size} 个工具
                </Box>
              )}
            </Typography>
          }
        />
      </DialogContent>

      <DialogActions sx={{ px: 3, pb: 2 }}>
        <Button
          onClick={() => handleRespond(false, false)}
          color="error"
          variant="outlined"
          size="small"
          disabled={isExpired}
        >
          拒绝全部 ({totalCount})
        </Button>
        <Button
          onClick={() => handleRespond(true, false)}
          color="success"
          variant="outlined"
          size="small"
          disabled={isExpired || allSelected}
          title={allSelected ? '已全部选中，请使用"批准选中"' : '批准全部请求'}
        >
          批准全部
        </Button>
        <Button
          onClick={() => handleRespond(true, true)}
          color="success"
          variant="contained"
          size="small"
          autoFocus
          disabled={isExpired || selectedCount === 0}
        >
          {isExpired
            ? '已超时'
            : selectedCount === totalCount
              ? `确认执行 (${selectedCount})`
              : `批准选中 (${selectedCount})`}
        </Button>
      </DialogActions>
    </Dialog>

      {/* #40 修复: autoExecute 二次确认 Dialog — 避免误点击导致永久自动执行 */}
      {/* 审查修复: MUI v9 移除了 disableEscapeKeyDown 顶层 prop，改为在 onClose 中按 reason 拦截 escapeKeyDown；
          onKeyDown stopPropagation 阻止 ESC 事件穿透到外层 Dialog */}
      <Dialog
        open={confirmAutoExecute}
        onClose={(_, reason) => {
          // 禁用 ESC 关闭（仅允许点击遮罩/按钮关闭），与原 disableEscapeKeyDown 行为一致
          if (reason === 'escapeKeyDown') return;
          setConfirmAutoExecute(false);
        }}
        maxWidth="xs"
        fullWidth
        onKeyDown={(e) => e.stopPropagation()}
      >
        <DialogTitle sx={{ fontSize: 14 }}>确认永久自动执行？</DialogTitle>
        <DialogContent>
          <Typography variant="body2" sx={{ color: 'text.secondary' }}>
            勾选后，选中的工具将永久自动执行（跨会话不再询问），包括未来的潜在危险操作。此设置可在「设置 → 工具管理」中关闭。
          </Typography>
          <Typography variant="body2" sx={{ mt: 1, color: 'warning.main', fontWeight: 600 }}>
            确定要启用吗？
          </Typography>
        </DialogContent>
        <DialogActions>
          <Button onClick={() => setConfirmAutoExecute(false)} color="inherit">取消</Button>
          <Button
            onClick={() => {
              setAutoExecute(true);
              // 勾选永久自动执行时，自动勾选会话内记忆（保持一致）
              setRemember(true);
              setConfirmAutoExecute(false);
            }}
            color="warning"
            variant="contained"
          >
            确认自动执行
          </Button>
        </DialogActions>
      </Dialog>
    </>
  );
}
