import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import type { KeyboardEvent as ReactKeyboardEvent, MouseEvent as ReactMouseEvent } from 'react';
import { Clipboard, Clock3, Download, Eye, MessageSquare, PlayCircle, RefreshCw, ShieldAlert, ShieldCheck, SkipForward, Square, TimerReset, UserRoundPlus } from 'lucide-react';
import Avatar3D from '@/components/digital/Avatar3D';
import { basePath } from '@/lib/basePath';
import {
  dispatchPlanNow,
  getDigitalEmployeeWorkday,
  getSchedulerJobs,
  governanceCommand,
  postDigitalEmployeeWorkdayAction,
  recordApprovalAction,
  restartManagedService,
  triggerCronCheck,
} from '@/lib/api';
import { isTauri } from '@/lib/tauri';
import type {
  CronJob,
  DigitalEmployeeDailyReport,
  DigitalEmployeeDecision,
  DigitalEmployeeDuty,
  DigitalEmployeeManagedService,
  DigitalEmployeeRunDetail,
  DigitalEmployeeTaskAgentState,
  DigitalEmployeeTaskExecutionSummary,
  DigitalEmployeeWorkEvent,
  DigitalEmployeeWorkdayProjection,
  GovernanceCommandKind,
} from '@/types/api';
import type { DigitalNavigationTarget } from './navigation';

const bp = basePath;
const digitalAssetBase = isTauri() ? './digital-assets' : `${bp}/digital-assets`;
const avatarAssetBase = `${digitalAssetBase}/avatars`;
const DIGITAL_EMPLOYEE_TIME_ZONE = 'Asia/Shanghai';

type EmployeeVisualState = 'skill' | 'browser' | 'call' | 'redial' | 'evidence' | 'decision' | 'reporting';
type EventStatusFilter = 'all' | 'running' | 'success' | 'danger';
type TaskListFilter = 'all' | 'selected' | 'pending';
type TaskAgentControlCommand = Extract<GovernanceCommandKind, 'retry_task' | 'skip_task' | 'cancel_task'>;
type ApprovalActionKind = 'comment' | 'delegate' | 'mark_timeout' | 'mark_risk' | 'clear_risk';

interface DigitalPlanItem {
  id: string;
  planId: string;
  title: string;
  summary: string;
  implemented: boolean;
  selectable: boolean;
  selected: boolean;
  status: string;
  statusLabel: string;
  statusTone: 'running' | 'success' | 'danger' | 'warning' | 'waiting' | 'info' | string;
  scheduleText: string;
  resultText: string;
  conversationId?: string | null;
  stepCount: number;
  taskCount: number;
  schedulerJob?: CronJob | null;
  source: 'plan_template';
}

interface ManagementSyncStatus {
  running: boolean;
  syncing: boolean;
  enabled: boolean;
  endpoint: string | null;
  missingCredentials?: string[];
  pending: number;
  failed: number;
  lastSyncAt: string | null;
  lastSyncError: string | null;
  failureSummary?: ManagementSyncFailureSummary;
  recentFailures?: ManagementSyncFailure[];
}

interface ManagementSyncFailureSummary {
  total: number;
  dueForRetry: number;
  backoff: number;
  byEntityType: Array<{ entityType: string; count: number }>;
}

interface ManagementSyncAttempt {
  attemptNo: number;
  status: string;
  error: string | null;
  endpoint?: string | null;
  startedAt: string;
  finishedAt: string;
}

interface ManagementSyncFailure {
  id: string;
  entityType: string;
  entityId: string;
  entitySummary?: ManagementSyncEntitySummary | null;
  operation: string;
  attempts: number;
  lastAttemptAt: string | null;
  nextRetryAt?: string | null;
  dueForRetry?: boolean;
  managementRecordUrl?: string | null;
  attemptHistory?: ManagementSyncAttempt[];
  error: string | null;
  createdAt: string;
  updatedAt: string;
}

interface ManagementSyncEntitySummary {
  title?: string | null;
  status?: string | null;
  summary?: string | null;
}

interface ApprovalActionDraft {
  comment: string;
  delegateTo: string;
  dueAt: string;
}

const EMPTY_APPROVAL_ACTION_DRAFT: ApprovalActionDraft = {
  comment: '',
  delegateTo: '',
  dueAt: '',
};

// 技术侧 PlanTemplate 是任务模板来源；用户侧只展示为“任务”，运行时 Task/PlanStep 展示为“步骤”。

interface EmployeeVisualStateOption {
  id: EmployeeVisualState;
  label: string;
  shortLabel: string;
  phase: string;
  src: string;
  bubble: string;
}

const EMPLOYEE_STATE_VALUES: EmployeeVisualState[] = ['skill', 'browser', 'call', 'redial', 'evidence', 'decision', 'reporting'];
const EVENT_STATUS_FILTERS: Array<{ id: EventStatusFilter; label: string }> = [
  { id: 'all', label: '全部' },
  { id: 'running', label: '执行中' },
  { id: 'success', label: '已完成' },
  { id: 'danger', label: '异常' },
];
const WORKDAY_GUIDE_DISMISSED_STORAGE_KEY = 'qimingclaw:digital-workday-guide-dismissed-date';
const LEGACY_WORKDAY_GUIDE_DISMISSED_STORAGE_KEY = 'sgrobot:digital-workday-guide-dismissed-date';
const MAIN_RUN_DETAIL_LIMIT = 80;
const EVENT_HISTORY_RENDER_LIMIT = 300;
const WORKDAY_GUIDE_STEPS = [
  { title: '确认日期', body: '先确认今天的值班日期，避免把昨天或明天的任务混在一起。' },
  { title: '选择任务', body: '从岗位职责里勾选今天要执行的任务，未接入能力保持待扩展。' },
  { title: '任务执行', body: '点击任务执行后，数字员工开始按已选任务推进工作。' },
  { title: '查看过程', body: '右侧滚动显示运行明细，任务中心可继续查看明细。' },
];

const EMPLOYEE_STATE_OPTIONS: Record<EmployeeVisualState, EmployeeVisualStateOption> = {
  skill: {
    id: 'skill',
    label: '查看Skill',
    shortLabel: '技能',
    phase: '查看Skill与计划',
    src: `${avatarAssetBase}/states/employee-idle.png`,
    bubble: '我正在查看可用Skill、任务计划和今天要勾选的执行内容。',
  },
  browser: {
    id: 'browser',
    label: '操作浏览器',
    shortLabel: '浏览器',
    phase: '操作浏览器执行',
    src: `${avatarAssetBase}/states/employee-browser.png`,
    bubble: '我正在打开页面、读取信息、填写表单，并把执行过程同步到右侧。',
  },
  call: {
    id: 'call',
    label: '电话外呼',
    shortLabel: '外呼',
    phase: '电话外呼与重拨',
    src: `${avatarAssetBase}/states/employee-running.png`,
    bubble: '我正在按工单名单外呼现场人员，记录接通、未接通和后续重拨。',
  },
  redial: {
    id: 'redial',
    label: '重拨跟进',
    shortLabel: '重拨',
    phase: '未接通人员重拨',
    src: `${avatarAssetBase}/states/employee-redial.png`,
    bubble: '我正在跟进未接通人员，按间隔重拨并更新每个人的通知状态。',
  },
  evidence: {
    id: 'evidence',
    label: '数据核验',
    shortLabel: '核验',
    phase: '核验执行证据',
    src: `${avatarAssetBase}/states/employee-evidence.png`,
    bubble: '我正在核验页面数据、执行证据和任务结果，确认交付内容可信。',
  },
  decision: {
    id: 'decision',
    label: '等待决策',
    shortLabel: '决策',
    phase: '等待人工确认',
    src: `${avatarAssetBase}/states/employee-decision.png`,
    bubble: '我已完成前置处理，现在需要人工确认后再继续推进。',
  },
  reporting: {
    id: 'reporting',
    label: '汇报成果',
    shortLabel: '汇报',
    phase: '汇报今日成果',
    src: `${avatarAssetBase}/states/employee-reporting.png`,
    bubble: '我正在整理运行明细和日报，方便你直接查看成果和异常。',
  },
};

function todayInputDate(): string {
  const date = new Date();
  return [
    date.getFullYear(),
    String(date.getMonth() + 1).padStart(2, '0'),
    String(date.getDate()).padStart(2, '0'),
  ].join('-');
}

function displayInputDate(date: string): string {
  return (date || todayInputDate()).split('-').join('/');
}

function badgeClass(tone?: string): string {
  if (tone === 'success') return 'de-badge-success';
  if (tone === 'danger') return 'de-badge-danger';
  if (tone === 'warning' || tone === 'running') return 'de-badge-warning';
  return 'de-badge-info';
}

function approvalRiskTone(value?: string | null): string {
  const normalized = compactText(value).toLowerCase();
  if (['high', 'critical', 'risk', 'marked'].includes(normalized)) return 'danger';
  if (['medium', 'warning'].includes(normalized)) return 'warning';
  if (['normal', 'low', 'clear'].includes(normalized)) return 'success';
  return 'info';
}

function approvalRiskLabel(value?: string | null): string {
  const normalized = compactText(value).toLowerCase();
  if (['high', 'critical', 'risk', 'marked'].includes(normalized)) return '高风险';
  if (['medium', 'warning'].includes(normalized)) return '中风险';
  if (['normal', 'low', 'clear'].includes(normalized)) return '风险正常';
  return '未标记风险';
}

function approvalSlaTone(value?: string | null): string {
  const normalized = compactText(value).toLowerCase();
  if (['timeout', 'overdue', 'expired'].includes(normalized)) return 'danger';
  if (['tracked', 'due_soon', 'warning'].includes(normalized)) return 'warning';
  if (['met', 'normal'].includes(normalized)) return 'success';
  return 'info';
}

function approvalSlaLabel(value?: string | null): string {
  const normalized = compactText(value).toLowerCase();
  if (['timeout', 'overdue', 'expired'].includes(normalized)) return '已超时';
  if (['tracked', 'due_soon', 'warning'].includes(normalized)) return 'SLA跟踪';
  if (['met', 'normal'].includes(normalized)) return 'SLA正常';
  return '未设置SLA';
}

function approvalActionLabel(value?: string | null): string {
  const normalized = compactText(value).toLowerCase();
  if (normalized === 'comment') return '评论';
  if (normalized === 'delegate') return '转交';
  if (normalized === 'mark_timeout') return '标记超时';
  if (normalized === 'mark_risk') return '标记风险';
  if (normalized === 'clear_risk') return '清除风险';
  return normalized || '暂无动作';
}

function dutyCardClass(planItem: DigitalPlanItem, selected: boolean): string {
  const classes = ['de-template-card-row', 'de-duty-card', 'de-duty-card--compact'];
  if (!planItem.implemented) classes.push('de-duty-card--disabled');
  if (selected) classes.push('de-duty-card--selected');
  if (planItem.statusTone === 'running') classes.push('de-duty-card--running');
  return classes.join(' ');
}

function compactPlanText(value?: string | null): string {
  return String(value || '').replace(/\s+/g, ' ').trim();
}

function cronExpressionFromJob(job?: CronJob | null): string {
  if (!job) return '';
  if (job.expression) return job.expression;
  if (typeof job.schedule === 'string') return job.schedule;
  if (job.schedule && typeof job.schedule === 'object') {
    const schedule = job.schedule as Record<string, unknown>;
    const expr = schedule.expr ?? schedule.expression ?? schedule.cron;
    if (typeof expr === 'string') return expr;
  }
  return '';
}

function scheduleTextFromJob(job?: CronJob | null): string {
  const expr = cronExpressionFromJob(job);
  if (!expr) return '未定时';
  const parts = expr.trim().split(/\s+/);
  const minute = parts[0] ?? '';
  const hour = parts[1] ?? '';
  if (parts.length >= 2 && /^\d+$/.test(minute) && /^\d+$/.test(hour)) {
    return `已定时 ${hour.padStart(2, '0')}:${minute.padStart(2, '0')} 执行`;
  }
  return `调度注册 ${expr}`;
}

function readRecordString(value: unknown, keys: string[]): string {
  if (!value || typeof value !== 'object') return '';
  const record = value as Record<string, unknown>;
  for (const key of keys) {
    const field = record[key];
    if (typeof field === 'string' && field.trim()) return field.trim();
  }
  return '';
}

function templateIdForSchedulerJob(job: CronJob): string {
  const direct = compactPlanText(job.template_id);
  if (direct) return direct;
  const delivery = readRecordString(job.delivery, ['template_id', 'plan_template_id', 'templateId']);
  if (delivery) return delivery;
  const schedule = readRecordString(job.schedule, ['template_id', 'plan_template_id', 'templateId']);
  if (schedule) return schedule;
  return job.id.replace(/^schedule-/, '');
}

function selectedDutyMatchesTemplate(selectedIds: Set<string>, templateId: string, scheduleId?: string): boolean {
  if (selectedIds.has(templateId) || (scheduleId && selectedIds.has(scheduleId))) return true;
  return Array.from(selectedIds).some((id) => hasRuntimeSuffixForTemplate(id, templateId));
}

function hasRuntimeSuffixForTemplate(value: string, templateId: string): boolean {
  if (!value.startsWith(`${templateId}-`)) return false;
  return /^-\d{8,}$/.test(value.slice(templateId.length));
}

function dutyMatchesTemplate(duty: DigitalEmployeeDuty, templateId: string, title?: string | null): boolean {
  if (duty.id === templateId || duty.conversation_id === templateId) return true;
  if (hasRuntimeSuffixForTemplate(duty.id, templateId) || (duty.conversation_id ? hasRuntimeSuffixForTemplate(duty.conversation_id, templateId) : false)) return true;
  const normalizedTitle = compactPlanText(title).toLowerCase();
  return Boolean(normalizedTitle && compactPlanText(duty.title).toLowerCase() === normalizedTitle);
}

function linkedDutyForTemplate(templateId: string, title: string | null | undefined, duties: DigitalEmployeeDuty[]): DigitalEmployeeDuty | null {
  const matches = duties.filter((duty) => dutyMatchesTemplate(duty, templateId, title));
  return matches.find((duty) => duty.selected)
    ?? matches.find((duty) => duty.id === templateId || duty.conversation_id === templateId)
    ?? matches[0]
    ?? null;
}

function submissionDutyIdForPlanTemplate(planItem: DigitalPlanItem, duties: DigitalEmployeeDuty[]): string {
  return linkedDutyForTemplate(planItem.id, planItem.title, duties)?.id ?? planItem.id;
}

function templateStepCount(job: CronJob): number {
  if (typeof job.step_count === 'number' && Number.isFinite(job.step_count)) return job.step_count;
  return Array.isArray(job.skill_ids) ? job.skill_ids.length : 0;
}

function triggerKindLabel(job: CronJob): string {
  const trigger = compactPlanText(job.trigger_kind || readRecordString(job.schedule, ['kind'])).toLowerCase();
  if (trigger === 'cron') return '定时任务';
  if (trigger === 'webhook') return '触发任务';
  return '手动任务';
}

function buildPlanTemplateItem(job: CronJob, duties: DigitalEmployeeDuty[], selected: boolean): DigitalPlanItem {
  const templateId = templateIdForSchedulerJob(job);
  const linkedDuty = linkedDutyForTemplate(templateId, job.name, duties);
  const stepCount = templateStepCount(job);
  const skillCount = Array.isArray(job.skill_ids) ? job.skill_ids.length : stepCount;
  const status = linkedDuty?.status ?? job.last_status ?? (job.enabled ? 'plan_template' : 'disabled');
  const statusLabel = linkedDuty?.status_label ?? (job.enabled ? triggerKindLabel(job) : '已停用');
  const statusTone = linkedDuty?.status_tone ?? (job.enabled ? 'info' : 'waiting');
  return {
    id: templateId,
    planId: templateId,
    title: compactPlanText(job.name) || templateId,
    summary: compactPlanText(job.prompt) || `任务：${templateId}`,
    implemented: job.enabled,
    selectable: true,
    selected,
    status,
    statusLabel,
    statusTone,
    scheduleText: linkedDuty?.schedule_text ?? scheduleTextFromJob(job),
    resultText: linkedDuty?.result_text ?? `${stepCount} 个步骤，${skillCount} 个Skill`,
    conversationId: linkedDuty?.conversation_id ?? templateId,
    stepCount,
    taskCount: skillCount,
    schedulerJob: job,
    source: 'plan_template',
  };
}

function isPlanItemExecutable(planItem: DigitalPlanItem): boolean {
  return planItem.implemented;
}

function planExecutionDisabledReason(planItem: DigitalPlanItem): string {
  if (!planItem.implemented) return '当前任务未接入执行能力。';
  return '';
}

function eventMatchesPlanItem(event: DigitalEmployeeWorkEvent, planItem: DigitalPlanItem): boolean {
  const haystack = `${event.conversation_id ?? ''} ${event.plan_title} ${event.task_title} ${event.step_title ?? ''} ${event.detail}`;
  return haystack.includes(planItem.id) || haystack.includes(planItem.title);
}

function fallbackSummaryForPlanItem(
  planItem: DigitalPlanItem,
  events: DigitalEmployeeWorkEvent[],
): DigitalEmployeeTaskExecutionSummary {
  const matched = events.filter((event) => eventMatchesPlanItem(event, planItem));
  const successCount = matched.filter(isSuccessfulEvent).length;
  const failureCount = matched.filter(isFailedEvent).length;
  const runningCount = matched.filter(isRunningEvent).length;
  const waitingCount = Math.max(matched.length - successCount - failureCount - runningCount, 0);
  const latest = matched.length > 0 ? matched[matched.length - 1] : undefined;
  return {
    id: planItem.id,
    plan_id: planItem.planId,
    title: planItem.title,
    description: planItem.summary,
    selected: true,
    total_count: matched.length,
    success_count: successCount,
    failure_count: failureCount,
    running_count: runningCount,
    waiting_count: waitingCount,
    latest_status_label: latest?.status_label ?? planItem.statusLabel,
    latest_status_tone: latest?.status_tone ?? planItem.statusTone,
    business_summary: matched.length > 0
      ? `${planItem.title} 今日执行 ${matched.length} 次，成功 ${successCount} 次，失败 ${failureCount} 次。`
      : `${planItem.title} 尚未产生执行记录。`,
    ai_summary: matched.length > 0
      ? `${planItem.title} 今日执行 ${matched.length} 次，成功 ${successCount} 次，失败 ${failureCount} 次。`
      : `${planItem.title} 尚未产生执行记录。`,
  };
}

function summaryMatchesPlanItem(summary: DigitalEmployeeTaskExecutionSummary, planItem: DigitalPlanItem): boolean {
  const summaryPlanId = summary.plan_id ?? '';
  if (summary.id === planItem.id || summaryPlanId === planItem.planId) return true;
  if (hasRuntimeSuffixForTemplate(summary.id, planItem.id) || hasRuntimeSuffixForTemplate(summaryPlanId, planItem.planId)) return true;
  return compactPlanText(summary.title).toLowerCase() === compactPlanText(planItem.title).toLowerCase();
}

function runDetailFromEvent(event: DigitalEmployeeWorkEvent): DigitalEmployeeRunDetail {
  return {
    id: event.id,
    time: event.time,
    task_name: event.plan_title,
    step_name: event.step_title,
    operation_name: event.task_title,
    status_label: event.status_label,
    status_tone: event.status_tone,
    business_detail: eventBusinessResult(event),
    raw_detail: event.detail,
    updated_at: event.updated_at,
    conversation_id: event.conversation_id,
  };
}

function cronExprForDailyTime(value: string): string {
  const [hour = '9', minute = '0'] = value.split(':');
  const safeHour = Math.min(Math.max(Number(hour) || 9, 0), 23);
  const safeMinute = Math.min(Math.max(Number(minute) || 0, 0), 59);
  return `${safeMinute} ${safeHour} * * *`;
}

function eventStatusText(event: DigitalEmployeeWorkEvent): string {
  return event.status_label || event.status || '已同步';
}

function compactText(value?: string | null): string {
  return String(value || '').replace(/\s+/g, ' ').trim();
}

function eventScheduleTime(event: DigitalEmployeeWorkEvent): string {
  const source = `${event.plan_title} ${event.step_title ?? ''}`;
  const match = source.match(/(?:^|\D)(\d{1,2})[:：](\d{2})(?:\D|$)/);
  if (match?.[1] && match[2]) return `${match[1].padStart(2, '0')}:${match[2]}`;
  const fallback = compactText(event.time);
  return fallback || '即时触发';
}

function formatBeijingDateTime(value?: string | null): string {
  const raw = compactText(value);
  if (!raw) return '';
  const date = new Date(raw);
  if (Number.isNaN(date.getTime())) return '';
  const parts = new Intl.DateTimeFormat('zh-CN', {
    timeZone: DIGITAL_EMPLOYEE_TIME_ZONE,
    month: '2-digit',
    day: '2-digit',
    hour: '2-digit',
    minute: '2-digit',
    hour12: false,
  }).formatToParts(date);
  const part = (type: string) => parts.find((item) => item.type === type)?.value ?? '';
  return `${part('month')}/${part('day')} ${part('hour')}:${part('minute')}`;
}

function summarizeSyncError(value?: string | null): string {
  const error = compactText(value);
  if (!error) return '';
  return error.length > 140 ? `${error.slice(0, 140)}...` : error;
}

function syncStatusTone(status: ManagementSyncStatus | null): 'info' | 'success' | 'warning' | 'danger' {
  if (!status) return 'info';
  if (!status.enabled || !status.endpoint) return 'warning';
  if ((status.missingCredentials?.length ?? 0) > 0) return 'warning';
  if (status.failed > 0 || status.lastSyncError) return 'danger';
  if (status.syncing || status.pending > 0) return 'warning';
  return status.lastSyncAt ? 'success' : 'info';
}

function syncStatusLabel(status: ManagementSyncStatus | null): string {
  if (!status) return '未连接';
  if (!status.enabled) return '已停用';
  if (!status.endpoint) return '未配置';
  if ((status.missingCredentials?.length ?? 0) > 0) return '缺少凭据';
  if (status.syncing) return '同步中';
  if (status.failed > 0 || status.lastSyncError) return '同步异常';
  if (status.pending > 0) return '待同步';
  return status.lastSyncAt ? '已同步' : '等待数据';
}

function syncStatusSummary(status: ManagementSyncStatus | null): string {
  if (!status) return '当前环境未连接 qimingclaw 同步桥。';
  if (!status.enabled) return '管理端同步已停用。';
  if (!status.endpoint) return '管理端同步地址未配置。';
  if ((status.missingCredentials?.length ?? 0) > 0) {
    return `管理端同步凭据未完整：${status.missingCredentials?.join('、')}`;
  }
  const error = summarizeSyncError(status.lastSyncError);
  if (status.failed > 0 || error) {
    const retrySummary = status.failureSummary
      ? [
          status.failureSummary.dueForRetry > 0
            ? `${status.failureSummary.dueForRetry} 条可重试`
            : '',
          status.failureSummary.backoff > 0
            ? `${status.failureSummary.backoff} 条退避中`
            : '',
          failureGroupSummary(status.failureSummary),
        ].filter(Boolean).join('，')
      : '';
    return [
      status.failed > 0 ? `${status.failed} 条失败` : '',
      status.pending > 0 ? `${status.pending} 条待同步` : '',
      retrySummary,
      error ? `失败原因：${error}` : '',
    ].filter(Boolean).join('，');
  }
  if (status.syncing) return `正在同步，待同步 ${status.pending} 条。`;
  if (status.pending > 0) return `仍有 ${status.pending} 条待同步记录。`;
  return status.lastSyncAt
    ? `最近同步：${formatBeijingDateTime(status.lastSyncAt) || status.lastSyncAt}`
    : '等待本地 outbox 数据。';
}

function entityTypeLabel(entityType: string): string {
  const labels: Record<string, string> = {
    plan: 'Plan',
    task: 'Task',
    run: 'Run',
    event: 'Event',
    artifact: 'Artifact',
    approval: 'Approval',
  };
  return labels[entityType] || entityType || 'Entity';
}

function failureGroupSummary(summary: ManagementSyncFailureSummary): string {
  const groups = summary.byEntityType
    .slice(0, 3)
    .map((group) => `${entityTypeLabel(group.entityType)} ${group.count}`)
    .join(' / ');
  return groups ? `类型：${groups}` : '';
}

function syncFailureSummary(failure: ManagementSyncFailure): string {
  const error = summarizeSyncError(failure.error);
  const title = compactText(failure.entitySummary?.title);
  return [
    title,
    `${entityTypeLabel(failure.entityType)} / ${failure.operation}`,
    `重试 ${failure.attempts} 次`,
    failure.dueForRetry ? '等待补偿' : `下次 ${syncFailureRetryTime(failure)}`,
    error,
  ].filter(Boolean).join(' · ');
}

function syncFailureTime(failure: ManagementSyncFailure): string {
  return formatBeijingDateTime(failure.lastAttemptAt || failure.updatedAt || failure.createdAt) || '未尝试';
}

function syncFailureRetryTime(failure: ManagementSyncFailure): string {
  if (failure.dueForRetry) return '可重试';
  return formatBeijingDateTime(failure.nextRetryAt) || '待计算';
}

function syncAttemptStatusLabel(status: string): string {
  if (status === 'synced') return '已同步';
  if (status === 'failed') return '失败';
  return status || '未知';
}

function syncAttemptTone(status: string): 'success' | 'danger' | 'info' {
  if (status === 'synced') return 'success';
  if (status === 'failed') return 'danger';
  return 'info';
}

function buildSyncFailureDiagnostic(
  failure: ManagementSyncFailure,
  status: ManagementSyncStatus | null,
): string {
  return JSON.stringify(
    {
      generatedAt: new Date().toISOString(),
      source: 'qimingclaw-digital-employee',
      failure,
      sync: status
        ? {
            running: status.running,
            syncing: status.syncing,
            enabled: status.enabled,
            endpoint: status.endpoint,
            missingCredentials: status.missingCredentials ?? [],
            pending: status.pending,
            failed: status.failed,
            lastSyncAt: status.lastSyncAt,
            lastSyncError: status.lastSyncError,
            failureSummary: status.failureSummary ?? null,
          }
        : null,
    },
    null,
    2,
  );
}

function syncFailureDiagnosticFileName(failure: ManagementSyncFailure): string {
  const entity = [failure.entityType, failure.entityId]
    .filter(Boolean)
    .join('-')
    .replace(/[^a-z0-9._-]+/gi, '-')
    .replace(/^-+|-+$/g, '')
    .slice(0, 80);
  return `qimingclaw-sync-failure-${entity || failure.id || 'diagnostic'}.json`;
}

function downloadTextFile(filename: string, content: string, mimeType = 'application/json;charset=utf-8'): void {
  const blob = new Blob([content], { type: mimeType });
  const url = URL.createObjectURL(blob);
  const link = document.createElement('a');
  link.href = url;
  link.download = filename;
  document.body.appendChild(link);
  link.click();
  link.remove();
  window.setTimeout(() => URL.revokeObjectURL(url), 1000);
}

function dailyReportFileName(date: string): string {
  return `qimingclaw-digital-report-${date}.txt`;
}

function buildDailyReportDownloadText(
  dateLabel: string,
  report: DigitalEmployeeDailyReport,
  summaries: DigitalEmployeeTaskExecutionSummary[],
  details: DigitalEmployeeRunDetail[],
): string {
  return [
    report.title || `${dateLabel} 数字员工日报`,
    `日期：${dateLabel}`,
    `生成时间：${report.generated_at ? formatBeijingDateTime(report.generated_at) : '暂未生成'}`,
    `生成来源：${report.generated_by === 'ai' ? 'AI' : 'qimingclaw adapter'}`,
    '',
    '## 摘要',
    report.summary || '暂无摘要。',
    '',
    '## 指标',
    `任务总数：${report.totals.task_count}`,
    `执行次数：${report.totals.execution_count}`,
    `成功次数：${report.totals.success_count}`,
    `失败次数：${report.totals.failure_count}`,
    `运行中：${report.totals.running_count ?? 0}`,
    '',
    '## 任务汇总',
    ...(summaries.length > 0
      ? summaries.map((summary) => `- ${summary.title}：${summary.latest_status_label}，执行 ${summary.total_count} 次，成功 ${summary.success_count}，失败 ${summary.failure_count}。${summary.ai_summary || summary.business_summary || ''}`)
      : ['暂无任务汇总。']),
    '',
    '## 运行明细',
    ...(details.length > 0
      ? details.map((detail) => `- ${detail.time || '--:--'} ${detail.task_name} / ${detail.step_name || detail.operation_name || '任务执行'}：${detail.status_label}，${detail.business_detail}`)
      : ['暂无运行明细。']),
    '',
    '## 详情',
    ...((report.detail_lines ?? []).length > 0 ? report.detail_lines : ['暂无详情。']),
  ].join('\n');
}

async function readManagementSyncStatus(): Promise<ManagementSyncStatus | null> {
  const bridge = window.QimingClawBridge?.digital;
  if (!bridge?.getSyncStatus) return null;
  try {
    return await bridge.getSyncStatus();
  } catch {
    return null;
  }
}

function eventDisplayTime(event: DigitalEmployeeWorkEvent): string {
  const beijingTime = formatBeijingDateTime(event.updated_at);
  if (beijingTime) {
    return beijingTime;
  }
  return compactText(event.time) || '待同步';
}

function runDetailDisplayTime(detail: DigitalEmployeeRunDetail): string {
  return formatBeijingDateTime(detail.updated_at) || compactText(detail.time) || '--:--';
}

function eventBusinessResult(event: DigitalEmployeeWorkEvent): string {
  const detail = compactText(event.detail)
    .replace(/^触发来源[:：]\s*$/u, '')
    .replace(/触发来源[:：]\s*(?=。|，|,|;|；|$)/u, '')
    .trim();
  if (!detail) {
    if (isSuccessfulEvent(event)) return '真实事件已完成，结果详情未回传。';
    if (isRunningEvent(event)) return '真实事件执行中，等待结果回传。';
    if (isFailedEvent(event)) return '执行异常，点击查看详情。';
    return '结果详情待同步。';
  }
  if (/^runner unavailable/i.test(detail)) {
    return '执行链路异常，点击查看详情。';
  }
  return detail.length > 72 ? `${detail.slice(0, 72)}...` : detail;
}

function eventTimingSummary(event: DigitalEmployeeWorkEvent): string {
  return `计划时间 ${eventScheduleTime(event)} · 执行时间 ${eventDisplayTime(event)}`;
}

function eventMatchesFilter(event: DigitalEmployeeWorkEvent, filter: EventStatusFilter): boolean {
  if (filter === 'all') return true;
  if (filter === 'running') return isRunningEvent(event);
  if (filter === 'success') return isSuccessfulEvent(event);
  return isFailedEvent(event);
}

function projectionSelectedDutyIds(projection: DigitalEmployeeWorkdayProjection): Set<string> {
  return new Set(
    projection.duties
      .filter((duty) => duty.selected)
      .map((duty) => duty.id),
  );
}

function managedServiceSummary(service: DigitalEmployeeManagedService): string {
  const deps = service.dependent_tasks.length > 0 ? `，影响 ${service.dependent_tasks.slice(0, 2).join('、')}` : '';
  return `${service.name} ${service.status_label}${service.error ? `：${service.error}` : deps}`;
}

function canRestartManagedService(service: DigitalEmployeeManagedService): boolean {
  return service.service_id === 'fileServer' || service.service_id === 'guiServer';
}

function taskAgentSummary(agent: DigitalEmployeeTaskAgentState): string {
  const next = agent.next_action === 'retry_or_skip' ? '重试或跳过' : agent.next_action === 'watch_progress' ? '观察进度' : agent.next_action;
  return `${agent.title} ${agent.status_label}，下一步 ${next}`;
}

function taskAgentControlLabel(command: TaskAgentControlCommand): string {
  switch (command) {
    case 'retry_task': return '重试';
    case 'skip_task': return '跳过';
    case 'cancel_task': return '取消';
    default: return command;
  }
}

function isDecisionOpen(status?: string): boolean {
  return ['pending', 'requested'].includes(String(status || '').toLowerCase());
}

function isExecutionPanelInteractiveTarget(target: EventTarget | null): boolean {
  if (!(target instanceof Element)) return false;
  if (target.closest('button, a, input, select, textarea, [role="tab"]')) {
    return true;
  }
  const roleButton = target.closest('[role="button"]');
  return Boolean(roleButton && !roleButton.classList.contains('de-workday-execution--clickable'));
}

function rotateEvents(events: DigitalEmployeeWorkEvent[], offset: number): DigitalEmployeeWorkEvent[] {
  if (events.length <= 4) return events;
  return events.slice(offset).concat(events.slice(0, offset)).slice(0, 4);
}

function isRunningEvent(event: DigitalEmployeeWorkEvent): boolean {
  const status = `${event.status} ${event.status_tone}`.toLowerCase();
  return status.includes('running') || status.includes('execut') || status.includes('progress');
}

function isSuccessfulEvent(event: DigitalEmployeeWorkEvent): boolean {
  const status = `${event.status} ${event.status_tone}`.toLowerCase();
  return status.includes('success') || status.includes('complete') || status.includes('done');
}

function isFailedEvent(event: DigitalEmployeeWorkEvent): boolean {
  const status = `${event.status} ${event.status_tone}`.toLowerCase();
  return status.includes('danger') || status.includes('fail') || status.includes('error') || status.includes('异常');
}

function isCallEvent(event: DigitalEmployeeWorkEvent): boolean {
  const text = `${event.plan_title} ${event.task_title} ${event.step_title ?? ''} ${event.detail}`.toLowerCase();
  return ['外呼', '电话', '拨打', '接通', '未接通', '重拨', '人员'].some((keyword) => text.includes(keyword));
}

function isRedialEvent(event: DigitalEmployeeWorkEvent): boolean {
  const text = `${event.plan_title} ${event.task_title} ${event.step_title ?? ''} ${event.detail}`.toLowerCase();
  return ['重拨', '未接通', '再拨', '回拨', 'retry', 'callback'].some((keyword) => text.includes(keyword));
}

function isEvidenceEvent(event: DigitalEmployeeWorkEvent): boolean {
  const text = `${event.plan_title} ${event.task_title} ${event.step_title ?? ''} ${event.detail}`.toLowerCase();
  return ['核验', '校验', '证据', '汇总', '报告', '结果', '交付', '看板', '同步'].some((keyword) => text.includes(keyword));
}

function getVisualStateOverride(): EmployeeVisualState | null {
  if (typeof window === 'undefined') return null;
  const value = new URLSearchParams(window.location.search).get('visual');
  return EMPLOYEE_STATE_VALUES.includes(value as EmployeeVisualState) ? (value as EmployeeVisualState) : null;
}

function visualStateForEvent(event: DigitalEmployeeWorkEvent): EmployeeVisualState {
  if (isRedialEvent(event)) return 'redial';
  if (isCallEvent(event)) return 'call';
  if (isEvidenceEvent(event)) return 'evidence';
  return 'browser';
}

function resolveEmployeeVisualState(args: {
  confirmed: boolean;
  currentEvent: DigitalEmployeeWorkEvent | null;
  pendingDecisionCount: number;
  eventsCount: number;
}): EmployeeVisualState {
  if (args.currentEvent) return visualStateForEvent(args.currentEvent);
  if (!args.confirmed && args.eventsCount === 0) return 'skill';
  if (args.pendingDecisionCount > 0) return 'decision';
  if (args.eventsCount > 0) return 'browser';
  return 'skill';
}

function readGuideDismissedDate(): string | null {
  if (typeof window === 'undefined') return null;
  try {
    return window.sessionStorage.getItem(WORKDAY_GUIDE_DISMISSED_STORAGE_KEY)
      ?? window.sessionStorage.getItem(LEGACY_WORKDAY_GUIDE_DISMISSED_STORAGE_KEY);
  } catch {
    return null;
  }
}

function rememberGuideDismissedDate(date: string): void {
  if (typeof window === 'undefined') return;
  try {
    window.sessionStorage.setItem(WORKDAY_GUIDE_DISMISSED_STORAGE_KEY, date);
    window.sessionStorage.removeItem(LEGACY_WORKDAY_GUIDE_DISMISSED_STORAGE_KEY);
  } catch {
    // Session storage can be unavailable in restricted browser contexts.
  }
}

export default function CommandDeck({ onNavigate }: { onNavigate: (target: DigitalNavigationTarget) => void }) {
  const [selectedDate, setSelectedDate] = useState(todayInputDate());
  const [workdayProjection, setWorkdayProjection] = useState<DigitalEmployeeWorkdayProjection | null>(null);
  const [schedulerJobs, setSchedulerJobs] = useState<CronJob[]>([]);
  const [selectedDutyIds, setSelectedDutyIds] = useState<Set<string>>(new Set());
  const [projectionLoading, setProjectionLoading] = useState(true);
  const [actionBusy, setActionBusy] = useState<string | null>(null);
  const [actionNotice, setActionNotice] = useState<string | null>(null);
  const [actionError, setActionError] = useState<string | null>(null);
  const [approvalActionDrafts, setApprovalActionDrafts] = useState<Record<string, ApprovalActionDraft>>({});
  const [planDataError, setPlanDataError] = useState<string | null>(null);
  const [selectionDirty, setSelectionDirty] = useState(false);
  const [taskListFilter, setTaskListFilter] = useState<TaskListFilter>('selected');
  const [feedOffset, setFeedOffset] = useState(0);
  const [feedManuallyPaused, setFeedManuallyPaused] = useState(false);
  const [feedInteractionPaused, setFeedInteractionPaused] = useState(false);
  const [eventHistoryOpen, setEventHistoryOpen] = useState(false);
  const [selectedEvent, setSelectedEvent] = useState<DigitalEmployeeWorkEvent | null>(null);
  const [eventStatusFilter, setEventStatusFilter] = useState<EventStatusFilter>('all');
  const [taskManagerOpen, setTaskManagerOpen] = useState(false);
  const [schedulePlanItem, setSchedulePlanItem] = useState<DigitalPlanItem | null>(null);
  const [executePlanItem, setExecutePlanItem] = useState<DigitalPlanItem | null>(null);
  const [scheduleTime, setScheduleTime] = useState('09:00');
  const [profileSettingsOpen, setProfileSettingsOpen] = useState(false);
  const [reportPreviewOpen, setReportPreviewOpen] = useState(false);
  const [selectedSyncFailure, setSelectedSyncFailure] = useState<ManagementSyncFailure | null>(null);
  const [profileForm, setProfileForm] = useState({
    name: '',
    company: '',
    position: '',
    currentStatus: 'working',
  });
  const [reportScheduleTime, setReportScheduleTime] = useState('18:00');
  const [guideOpen, setGuideOpen] = useState(false);
  const [guideDismissedDate, setGuideDismissedDate] = useState<string | null>(() => readGuideDismissedDate());
  const [managementSyncStatus, setManagementSyncStatus] = useState<ManagementSyncStatus | null>(null);
  const mountedRef = useRef(false);
  const selectionDirtyRef = useRef(false);

  useEffect(() => {
    mountedRef.current = true;
    return () => { mountedRef.current = false; };
  }, []);

  const fetchProjection = useCallback(async () => {
    let latestProjection: DigitalEmployeeWorkdayProjection | null = null;
    let latestJobs: CronJob[] | null = null;

    const syncDefaultSelection = () => {
      if (selectionDirtyRef.current || !latestJobs) return;
      const projectionIds = latestProjection?.source === 'live'
        ? projectionSelectedDutyIds(latestProjection)
        : new Set<string>();
      const matchedTemplateIds = latestJobs
        .map((job) => templateIdForSchedulerJob(job))
        .filter((templateId) => selectedDutyMatchesTemplate(projectionIds, templateId));
      const defaultTemplateIds = matchedTemplateIds.length > 0
        ? matchedTemplateIds
        : latestJobs.slice(0, 3).map((job) => templateIdForSchedulerJob(job));
      setSelectedDutyIds(new Set(defaultTemplateIds));
    };

    const projectionPromise = getDigitalEmployeeWorkday(selectedDate)
      .then((projection) => {
        if (!mountedRef.current) return;
        latestProjection = projection;
        setWorkdayProjection(projection);
        setActionError(null);
        syncDefaultSelection();
      })
      .catch((error: unknown) => {
        if (!mountedRef.current) return;
        setActionError(error instanceof Error ? error.message : '数字员工首页数据同步失败');
      });

    const jobsPromise = getSchedulerJobs()
      .then((jobs) => {
        if (!mountedRef.current) return;
        latestJobs = jobs.filter((job) => (
          job.job_type === 'plan_template' || readRecordString(job.delivery, ['mode']) === 'plan_template'
        ));
        setSchedulerJobs(latestJobs);
        setPlanDataError(null);
        syncDefaultSelection();
      })
      .catch((error: unknown) => {
        if (!mountedRef.current) return;
        setPlanDataError(error instanceof Error ? error.message : '任务加载失败');
      });

    const syncStatusPromise = readManagementSyncStatus()
      .then((status) => {
        if (!mountedRef.current) return;
        setManagementSyncStatus(status);
      });

    await Promise.allSettled([projectionPromise, jobsPromise, syncStatusPromise]);
    if (mountedRef.current) {
      setProjectionLoading(false);
    }
  }, [selectedDate]);

  useEffect(() => {
    setProjectionLoading(true);
    void fetchProjection();
  }, [fetchProjection]);

  useEffect(() => {
    const intervalMs = workdayProjection?.workday.confirmed ? 8000 : 30000;
    const timer = window.setInterval(() => { void fetchProjection(); }, intervalMs);
    return () => window.clearInterval(timer);
  }, [fetchProjection, workdayProjection?.workday.confirmed]);

  useEffect(() => {
    const feedPaused = feedManuallyPaused || feedInteractionPaused || eventHistoryOpen || selectedEvent !== null;
    if (feedPaused) return undefined;
    const timer = window.setInterval(() => {
      setFeedOffset((current) => {
        const length = workdayProjection?.source === 'live' ? workdayProjection.events.length : 0;
        return length > 0 ? (current + 1) % length : 0;
      });
    }, 3200);
    return () => window.clearInterval(timer);
  }, [eventHistoryOpen, feedInteractionPaused, feedManuallyPaused, selectedEvent, workdayProjection?.events.length, workdayProjection?.source]);

  const isLiveProjection = workdayProjection?.source === 'live';
  const liveProjectionDuties = useMemo(
    () => (isLiveProjection ? (workdayProjection?.duties ?? []) : []),
    [isLiveProjection, workdayProjection?.duties],
  );
  const planItems = useMemo(() => {
    return schedulerJobs
      .slice()
      .sort((left, right) => {
        const leftId = templateIdForSchedulerJob(left);
        const rightId = templateIdForSchedulerJob(right);
        const leftSelected = selectedDutyIds.has(leftId) ? 1 : 0;
        const rightSelected = selectedDutyIds.has(rightId) ? 1 : 0;
        if (leftSelected !== rightSelected) return rightSelected - leftSelected;
        const leftRun = new Date(left.next_run || '').getTime();
        const rightRun = new Date(right.next_run || '').getTime();
        const leftHasRun = Number.isFinite(leftRun);
        const rightHasRun = Number.isFinite(rightRun);
        if (leftHasRun !== rightHasRun) return leftHasRun ? -1 : 1;
        if (leftHasRun && rightHasRun && leftRun !== rightRun) return leftRun - rightRun;
        return compactPlanText(left.name).localeCompare(compactPlanText(right.name), 'zh-CN');
      })
      .map((job) => {
        const templateId = templateIdForSchedulerJob(job);
        return buildPlanTemplateItem(job, liveProjectionDuties, selectedDutyIds.has(templateId));
      });
  }, [liveProjectionDuties, schedulerJobs, selectedDutyIds]);
  const selectedDuties = useMemo(
    () => planItems.filter((planItem) => selectedDutyIds.has(planItem.id)),
    [planItems, selectedDutyIds],
  );
  const selectedSubmissionDutyIds = useMemo(
    () => selectedDuties.map((planItem) => submissionDutyIdForPlanTemplate(planItem, liveProjectionDuties)),
    [liveProjectionDuties, selectedDuties],
  );
  const totalDuties = planItems;
  const pendingDuties = planItems.filter((planItem) => !selectedDutyIds.has(planItem.id));
  const visibleTaskItems = taskListFilter === 'selected'
    ? selectedDuties
    : taskListFilter === 'pending'
      ? pendingDuties
      : totalDuties;
  const allEvents = isLiveProjection ? (workdayProjection?.events ?? []) : [];
  const rotatingEvents = rotateEvents(allEvents, feedOffset);
  const visibleEvents = allEvents;
  const pendingDecisions = (isLiveProjection ? (workdayProjection?.decisions ?? []) : []).filter((decision) => (
    isDecisionOpen(decision.status)
  ));
  const feedPaused = feedManuallyPaused || feedInteractionPaused || eventHistoryOpen || selectedEvent !== null;
  const filteredHistoryEvents = useMemo(
    () => allEvents.filter((event) => eventMatchesFilter(event, eventStatusFilter)),
    [allEvents, eventStatusFilter],
  );
  const visibleHistoryEvents = filteredHistoryEvents.slice(0, EVENT_HISTORY_RENDER_LIMIT);
  const runningEvents = allEvents.filter(isRunningEvent);
  const completedEvents = allEvents.filter(isSuccessfulEvent);
  const failedEvents = allEvents.filter(isFailedEvent);
  const currentEvent = rotatingEvents[0] ?? runningEvents[0] ?? null;
  const employee = workdayProjection?.employee;
  const workday = workdayProjection?.workday;
  const delivery = workdayProjection?.delivery;
  const managedServices = isLiveProjection ? (workdayProjection?.managed_services ?? []) : [];
  const managedServiceIssues = managedServices.filter((service) => service.requires_human_action || service.status === 'degraded');
  const taskAgents = isLiveProjection ? (workdayProjection?.task_agents ?? []) : [];
  const actionableTaskAgents = taskAgents.filter((agent) => agent.can_retry || agent.can_skip || agent.can_cancel);
  const routeSummary = isLiveProjection ? workdayProjection?.route_summary : null;
  const latestRoute = routeSummary?.latest ?? null;
  const diagnosticSummary = isLiveProjection ? workdayProjection?.diagnostic_summary : null;
  const diagnosticIssueCount = diagnosticSummary ? diagnosticSummary.doctor.error + diagnosticSummary.doctor.warn : 0;
  const auditRiskCount = diagnosticSummary ? diagnosticSummary.audit.error + diagnosticSummary.audit.warn : 0;
  const latestDiagnosticIssue = diagnosticSummary?.latest_issue ?? null;
  const dailyReport = isLiveProjection ? workdayProjection?.daily_report : undefined;
  const runDetails = isLiveProjection
    ? (workdayProjection?.run_details?.length ? workdayProjection.run_details : allEvents.map(runDetailFromEvent))
    : [];
  const visibleRunDetails = runDetails.slice(0, MAIN_RUN_DETAIL_LIMIT);
  const executionSummaries = isLiveProjection ? (workdayProjection?.execution_summaries ?? []) : [];
  const taskSummaryCards = selectedDuties.map((planItem) => (
    executionSummaries.find((summary) => summaryMatchesPlanItem(summary, planItem))
    ?? fallbackSummaryForPlanItem(planItem, allEvents)
  ));
  const selectedDateLabel = displayInputDate(selectedDate);
  const visibleTaskListLabel = taskListFilter === 'all'
    ? '全部任务'
    : taskListFilter === 'pending'
      ? '待选择任务'
      : '今日已选任务';
  const visibleTaskListHint = taskListFilter === 'all'
    ? `总任务 ${totalDuties.length} 项，不代表当天都会执行。`
    : taskListFilter === 'pending'
      ? `当前日期 ${selectedDateLabel} 还有 ${pendingDuties.length} 项未选择。`
      : `当前日期 ${selectedDateLabel} 已选择 ${selectedDuties.length} 项任务。`;
  const readyReportTotals = dailyReport?.status === 'ready' ? dailyReport.totals : null;
  const reportTaskCount = readyReportTotals?.task_count ?? taskSummaryCards.length;
  const reportExecutionCount = readyReportTotals?.execution_count ?? taskSummaryCards.reduce((total, summary) => total + summary.total_count, 0);
  const reportSuccessCount = readyReportTotals?.success_count ?? taskSummaryCards.reduce((total, summary) => total + summary.success_count, 0);
  const reportFailureCount = readyReportTotals?.failure_count ?? taskSummaryCards.reduce((total, summary) => total + summary.failure_count, 0);
  const reportPreviewLines = dailyReport
    ? [dailyReport.summary, ...(dailyReport.detail_lines ?? [])].filter((line): line is string => Boolean(line && line.trim()))
    : [];
  const reportPreviewAvailable = dailyReport?.status === 'ready' && reportPreviewLines.length > 0;
  const currentStatus = workday?.current_status ?? employee?.current_status ?? 'working';
  const currentStatusLabel = workday?.current_status_label ?? employee?.current_status_label ?? (currentStatus === 'resting' ? '休息中' : '工作中');
  const isResting = currentStatus === 'resting';
  const isDemoProjection = workdayProjection?.source === 'demo';
  const projectionSourceLabel = isDemoProjection ? '演示兜底' : '真实数据';
  const projectionSourceClass = isDemoProjection ? 'de-badge-warning' : 'de-badge-success';
  const managementSyncTone = syncStatusTone(managementSyncStatus);
  const managementSyncLabel = syncStatusLabel(managementSyncStatus);
  const managementSyncSummary = syncStatusSummary(managementSyncStatus);
  const managementSyncError = summarizeSyncError(managementSyncStatus?.lastSyncError);
  const managementSyncFailures = managementSyncStatus?.recentFailures ?? [];
  const resolvedVisualState = resolveEmployeeVisualState({
    confirmed: Boolean(workday?.confirmed),
    currentEvent,
    pendingDecisionCount: pendingDecisions.length,
    eventsCount: allEvents.length,
  });
  const visualStateOverride = getVisualStateOverride();
  const employeeVisualState = visualStateOverride ?? resolvedVisualState;
  const activeVisual = EMPLOYEE_STATE_OPTIONS[employeeVisualState];
  const bubbleText = visualStateOverride || currentEvent || pendingDecisions.length > 0
    ? activeVisual.bubble
    : (workday?.bubble_text ?? activeVisual.bubble);
  const workdaySummaryText = totalDuties.length > 0
    ? `已加载 ${totalDuties.length} 项任务，当前选择 ${selectedDuties.length} 项；右侧展示真实执行状态、运行明细和日报。`
    : (workday?.summary ?? '等待同步当天任务计划。');
  const currentActionTitle = currentEvent?.task_title
    ?? (actionableTaskAgents[0] ? actionableTaskAgents[0].title : managedServiceIssues[0] ? managedServiceIssues[0].name : workday?.confirmed ? '等待下一条执行事件' : '等待确认任务设置');
  const currentActionDetail = currentEvent
    ? `${currentEvent.plan_title}：${eventBusinessResult(currentEvent)}（${eventTimingSummary(currentEvent)}）`
    : actionableTaskAgents[0]
      ? taskAgentSummary(actionableTaskAgents[0])
    : managedServiceIssues[0]
      ? managedServiceSummary(managedServiceIssues[0])
    : '任务执行后会显示正在处理的任务、步骤或汇总动作。';
  const nextStepText = pendingDecisions[0]
    ? `等待人工确认：${pendingDecisions[0].title}`
    : actionableTaskAgents[0]
      ? `Task Agent：${taskAgentSummary(actionableTaskAgents[0])}`
    : managedServiceIssues[0]
      ? `处理服务状态：${managedServiceSummary(managedServiceIssues[0])}`
    : workday?.confirmed
      ? (delivery?.lines[0] ?? '继续按计划轮询新工单，并把结果同步到运行明细。')
      : '请先确认今天要执行的任务，确认后数字员工会开始执行。';
  const needsWorkdayConfirmation = Boolean(workdayProjection && !workday?.confirmed);

  useEffect(() => {
    if (projectionLoading || !workdayProjection) return;
    if (workdayProjection.workday.confirmed) {
      setGuideOpen(false);
      return;
    }
  }, [guideDismissedDate, projectionLoading, selectedDate, workdayProjection]);

  useEffect(() => {
    if (!employee) return;
    setProfileForm({
      name: employee.name || '',
      company: employee.company || '',
      position: employee.position || employee.major || '',
      currentStatus: employee.current_status || workday?.current_status || 'working',
    });
  }, [employee, workday?.current_status]);

  useEffect(() => {
    setReportScheduleTime(dailyReport?.report_schedule_time || '18:00');
  }, [dailyReport?.report_schedule_time]);

  useEffect(() => {
    setReportPreviewOpen(false);
  }, [selectedDate]);

  const toggleDuty = useCallback((planItem: DigitalPlanItem) => {
    if (!planItem.selectable || !planItem.implemented) return;
    setSelectedDutyIds((current) => {
      const next = new Set(current);
      if (next.has(planItem.id)) {
        next.delete(planItem.id);
      } else {
        next.add(planItem.id);
      }
      return next;
    });
    selectionDirtyRef.current = true;
    setSelectionDirty(true);
    setActionNotice(null);
  }, []);

  const confirmWorkday = useCallback(async () => {
    if (selectedDutyIds.size === 0) {
      setActionError('请至少选择一项今天要执行的任务。');
      return;
    }
    if (isResting) {
      setActionError('当前状态为休息中，请切换为工作中后再执行任务。');
      return;
    }
    setActionBusy('confirm_workday');
    setActionError(null);
    setActionNotice(null);
    try {
      const projection = await postDigitalEmployeeWorkdayAction({
        action: 'confirm_workday',
        date: selectedDate,
        duty_ids: selectedSubmissionDutyIds,
      });
      if (!mountedRef.current) return;
      setWorkdayProjection(projection);
      setSelectedDutyIds(new Set(selectedDutyIds));
      selectionDirtyRef.current = true;
      setSelectionDirty(false);
      setGuideOpen(false);
      setActionNotice('任务设置已确认，数字员工开始按任务执行。');
    } catch (error) {
      if (mountedRef.current) {
        setActionError(error instanceof Error ? error.message : '确认任务设置失败');
      }
    } finally {
      if (mountedRef.current) setActionBusy(null);
    }
  }, [isResting, selectedDate, selectedDutyIds, selectedSubmissionDutyIds]);

  const flushManagementSync = useCallback(async () => {
    setActionBusy('flush_management_sync');
    setActionError(null);
    setActionNotice(null);
    try {
      const bridge = window.QimingClawBridge?.digital;
      if (!bridge?.flushSync) {
        setActionNotice('当前环境未连接 qimingclaw 同步桥。');
        return;
      }
      const syncStatus = await bridge.flushSync();
      if (!mountedRef.current) return;
      setManagementSyncStatus(syncStatus);
      const latestProjection = await getDigitalEmployeeWorkday(selectedDate);
      if (!mountedRef.current) return;
      setWorkdayProjection(latestProjection);
      const statusText = syncStatus.failed > 0
        ? `同步完成，仍有 ${syncStatus.failed} 条失败记录。`
        : syncStatus.pending > 0
          ? `同步完成，仍有 ${syncStatus.pending} 条待同步记录。`
          : '管理端同步完成。';
      setActionNotice(statusText);
    } catch (error) {
      if (mountedRef.current) {
        setActionError(error instanceof Error ? error.message : '同步管理端失败');
      }
    } finally {
      if (mountedRef.current) setActionBusy(null);
    }
  }, [selectedDate]);

  const copySyncFailureDiagnostic = useCallback(async (failure: ManagementSyncFailure) => {
    const diagnostic = buildSyncFailureDiagnostic(failure, managementSyncStatus);
    try {
      await navigator.clipboard.writeText(diagnostic);
      setActionError(null);
      setActionNotice('同步失败诊断已复制。');
    } catch (error) {
      setActionNotice(null);
      setActionError(error instanceof Error ? error.message : '复制同步失败诊断失败');
    }
  }, [managementSyncStatus]);

  const exportSyncFailureDiagnostic = useCallback((failure: ManagementSyncFailure) => {
    downloadTextFile(
      syncFailureDiagnosticFileName(failure),
      buildSyncFailureDiagnostic(failure, managementSyncStatus),
    );
    setActionError(null);
    setActionNotice('同步失败诊断已导出。');
  }, [managementSyncStatus]);

  const cancelAllTasks = useCallback(() => {
    setSelectedDutyIds(new Set());
    selectionDirtyRef.current = true;
    setSelectionDirty(true);
    setActionNotice('已一键取消当前选择，重新选择后点击任务执行生效。');
    setActionError(null);
  }, []);

  const saveProfileSettings = useCallback(async () => {
    setActionBusy('update_profile');
    setActionError(null);
    setActionNotice(null);
    try {
      const projection = await postDigitalEmployeeWorkdayAction({
        action: 'update_profile',
        date: selectedDate,
        name: profileForm.name,
        company: profileForm.company,
        position: profileForm.position,
        current_status: profileForm.currentStatus,
      });
      if (!mountedRef.current) return;
      setWorkdayProjection(projection);
      setProfileSettingsOpen(false);
      setActionNotice('数字员工特性设置已保存。');
    } catch (error) {
      if (mountedRef.current) {
        setActionError(error instanceof Error ? error.message : '保存特性设置失败');
      }
    } finally {
      if (mountedRef.current) setActionBusy(null);
    }
  }, [profileForm, selectedDate]);

  const saveReportSchedule = useCallback(async () => {
    setActionBusy('update_report_schedule');
    setActionError(null);
    setActionNotice(null);
    try {
      const projection = await postDigitalEmployeeWorkdayAction({
        action: 'update_report_schedule',
        date: selectedDate,
        report_schedule_time: reportScheduleTime,
      });
      if (!mountedRef.current) return;
      setWorkdayProjection(projection);
      setActionNotice(`日报生成时间已设置为 ${reportScheduleTime}。`);
    } catch (error) {
      if (mountedRef.current) {
        setActionError(error instanceof Error ? error.message : '设置日报时间失败');
      }
    } finally {
      if (mountedRef.current) setActionBusy(null);
    }
  }, [reportScheduleTime, selectedDate]);

  const generateDailyReport = useCallback(async () => {
    setActionBusy('generate_daily_report');
    setActionError(null);
    setActionNotice(null);
    try {
      const projection = await postDigitalEmployeeWorkdayAction({
        action: 'generate_daily_report',
        date: selectedDate,
        duty_ids: selectedSubmissionDutyIds,
        report_schedule_time: reportScheduleTime,
      });
      if (!mountedRef.current) return;
      const latestProjection = projection.daily_report?.status === 'ready'
        ? projection
        : await getDigitalEmployeeWorkday(selectedDate);
      if (!mountedRef.current) return;
      setWorkdayProjection(latestProjection);
      setActionNotice('日报已生成，可下载本地文本。');
      if (latestProjection.daily_report?.status === 'ready') {
        setReportPreviewOpen(true);
      }
    } catch (error) {
      if (mountedRef.current) {
        setActionError(error instanceof Error ? error.message : '生成日报失败');
      }
    } finally {
      if (mountedRef.current) setActionBusy(null);
    }
  }, [reportScheduleTime, selectedDate, selectedDutyIds, selectedSubmissionDutyIds]);

  const downloadDailyReport = useCallback(() => {
    if (!dailyReport || dailyReport.status !== 'ready') return;
    downloadTextFile(
      dailyReportFileName(selectedDate),
      buildDailyReportDownloadText(selectedDateLabel, dailyReport, taskSummaryCards, visibleRunDetails),
      'text/plain;charset=utf-8',
    );
    setActionNotice('日报文本已下载。');
  }, [dailyReport, selectedDate, selectedDateLabel, taskSummaryCards, visibleRunDetails]);

  const resolveDecision = useCallback(async (decision: DigitalEmployeeDecision, actionId: string) => {
    setActionBusy(`${decision.id}:${actionId}`);
    setActionError(null);
    setActionNotice(null);
    try {
      const projection = await postDigitalEmployeeWorkdayAction({
        action: 'decide_approval',
        date: selectedDate,
        decision_id: decision.id,
        decision: actionId,
      });
      if (!mountedRef.current) return;
      const actionLabel = decision.actions.find((action) => action.id === actionId)?.label ?? actionId;
      setWorkdayProjection(projection);
      setActionNotice(`已记录“${actionLabel}”处理结果，并写入 qimingclaw 本地运行状态。`);
    } catch (error) {
      if (mountedRef.current) {
        setActionError(error instanceof Error ? error.message : '处理决策失败');
      }
    } finally {
      if (mountedRef.current) setActionBusy(null);
    }
  }, [selectedDate]);

  const updateApprovalActionDraft = useCallback((decisionId: string, patch: Partial<ApprovalActionDraft>) => {
    setApprovalActionDrafts((current) => ({
      ...current,
      [decisionId]: { ...(current[decisionId] ?? EMPTY_APPROVAL_ACTION_DRAFT), ...patch },
    }));
  }, []);

  const submitApprovalAction = useCallback(async (
    decision: DigitalEmployeeDecision,
    action: ApprovalActionKind,
  ) => {
    const draft = approvalActionDrafts[decision.id] ?? EMPTY_APPROVAL_ACTION_DRAFT;
    const comment = compactText(draft.comment);
    const delegateTo = compactText(draft.delegateTo);
    const dueAt = compactText(draft.dueAt);

    if (action === 'comment' && !comment) {
      setActionError('请先填写审批评论。');
      return;
    }
    if (action === 'delegate' && !delegateTo) {
      setActionError('请先填写转交对象。');
      return;
    }

    const actionKey = `approval-action:${decision.id}:${action}`;
    setActionBusy(actionKey);
    setActionError(null);
    setActionNotice(null);
    try {
      const options: Record<string, string | null | undefined> = {
        actor: 'digital_employee_operator',
        source: 'digital-command-deck',
        comment: action === 'comment' ? comment : undefined,
        delegate_to: action === 'delegate' ? delegateTo : undefined,
        delegate_label: action === 'delegate' ? delegateTo : undefined,
        due_at: action === 'mark_timeout' ? (dueAt || new Date().toISOString()) : undefined,
        reason: action === 'mark_risk' || action === 'clear_risk' || action === 'mark_timeout'
          ? (comment || approvalActionLabel(action))
          : undefined,
      };
      const result = await recordApprovalAction(decision.id, action, options);
      if (!mountedRef.current) return;
      if (!result?.ok) {
        throw new Error(result?.error || '记录审批动作失败');
      }
      const latestProjection = await getDigitalEmployeeWorkday(selectedDate);
      if (!mountedRef.current) return;
      setWorkdayProjection(latestProjection);
      setApprovalActionDrafts((current) => ({
        ...current,
        [decision.id]: {
          ...(current[decision.id] ?? EMPTY_APPROVAL_ACTION_DRAFT),
          comment: action === 'comment' ? '' : current[decision.id]?.comment ?? '',
          delegateTo: action === 'delegate' ? '' : current[decision.id]?.delegateTo ?? '',
        },
      }));
      setActionNotice(`已记录审批动作：${approvalActionLabel(action)}。`);
    } catch (error) {
      if (mountedRef.current) {
        setActionError(error instanceof Error ? error.message : '记录审批动作失败');
      }
    } finally {
      if (mountedRef.current) setActionBusy(null);
    }
  }, [approvalActionDrafts, selectedDate]);

  const controlTaskAgent = useCallback(async (
    agent: DigitalEmployeeTaskAgentState,
    command: TaskAgentControlCommand,
  ) => {
    const actionKey = `task-agent:${agent.task_id}:${command}`;
    setActionBusy(actionKey);
    setActionError(null);
    setActionNotice(null);
    try {
      const response = await governanceCommand({
        command_kind: command,
        context_refs: {
          plan_id: agent.plan_id,
          task_id: agent.task_id,
          run_id: agent.latest_run_id,
          step_id: agent.step_id,
          task_agent_id: agent.agent_id,
        },
        payload: {
          source: 'digital-home-task-agent',
          task_agent_id: agent.agent_id,
          task_id: agent.task_id,
          plan_id: agent.plan_id,
          step_id: agent.step_id,
          latest_run_id: agent.latest_run_id,
          title: agent.title,
          requested_action: command,
          previous_state: agent.execution_state,
          next_action: agent.next_action,
        },
        correlation_id: `digital-home-task-agent-${agent.task_id}-${command}-${Date.now()}`,
      });
      if (!response.accepted) {
        throw new Error(response.message || `Task Agent 命令未被接受：${response.command_id || command}`);
      }
      setActionNotice(`Task Agent 已${taskAgentControlLabel(command)}：${agent.title}。`);
      await fetchProjection();
    } catch (error) {
      if (mountedRef.current) {
        setActionError(error instanceof Error ? error.message : 'Task Agent 控制失败');
      }
    } finally {
      if (mountedRef.current) setActionBusy(null);
    }
  }, [fetchProjection]);

  const restartService = useCallback(async (service: DigitalEmployeeManagedService) => {
    const actionKey = `managed-service:${service.service_id}:restart`;
    setActionBusy(actionKey);
    setActionError(null);
    setActionNotice(null);
    try {
      const response = await restartManagedService(service.service_id, {
        reason: 'digital_home_managed_service_issue',
        actor: 'digital_employee_ui',
      });
      if (!response.ok) {
        throw new Error(response.error || response.message || `${service.name} 重启失败`);
      }
      setActionNotice(`${service.name} 已提交安全重启。`);
      await fetchProjection();
    } catch (error) {
      if (mountedRef.current) {
        setActionError(error instanceof Error ? error.message : `${service.name} 重启失败`);
      }
    } finally {
      if (mountedRef.current) setActionBusy(null);
    }
  }, [fetchProjection]);

  const openDuty = useCallback((planItem: DigitalPlanItem) => {
    onNavigate({ tab: 'missions', date: selectedDate, missionId: planItem.conversationId || planItem.id });
  }, [onNavigate, selectedDate]);

  const createPlanSchedule = useCallback(async (planItem: DigitalPlanItem) => {
    const cronExpr = cronExprForDailyTime(scheduleTime);
    const stamp = Date.now();
    const scheduleId = `digital-home-${planItem.planId}-${scheduleTime.replace(':', '')}`;
    setActionBusy(`schedule:${planItem.id}`);
    setActionError(null);
    setActionNotice(null);
    try {
      const response = await governanceCommand({
        command_kind: 'create_schedule',
        context_refs: {
          plan_id: planItem.planId,
          schedule_id: scheduleId,
        },
        payload: {
          source: 'digital-home',
          plan_id: planItem.planId,
          name: `定时执行：${planItem.title}`,
          description: `按首页任务管理定时任务：${planItem.title}`,
          prompt: `请按计划执行：${planItem.title}。${planItem.summary}`,
          cron_expr: cronExpr,
          schedule: cronExpr,
        },
        correlation_id: `digital-home-create-schedule-${planItem.planId}-${stamp}`,
        idempotency_key: `digital-home-create-schedule-${planItem.planId}-${scheduleTime}-${stamp}`,
      });
      if (!response.accepted) {
        throw new Error(response.message || `调度命令未被接受：${response.command_id || 'create_schedule'}`);
      }
      setSchedulePlanItem(null);
      setActionNotice(`已提交定时：${planItem.title}，${scheduleTime} 按 cron 计划执行。`);
      await fetchProjection();
    } catch (error) {
      if (mountedRef.current) {
        setActionError(error instanceof Error ? error.message : '定时执行失败');
      }
    } finally {
      if (mountedRef.current) setActionBusy(null);
    }
  }, [fetchProjection, scheduleTime]);

  const confirmImmediatePlanExecution = useCallback(async (planItem: DigitalPlanItem) => {
    if (!isPlanItemExecutable(planItem)) {
      setActionError(planExecutionDisabledReason(planItem));
      setActionNotice(null);
      return;
    }
    setActionBusy(`execute:${planItem.id}`);
    setActionError(null);
    setActionNotice(null);
    try {
      const response = await dispatchPlanNow(planItem.planId);
      if (response.ok !== true) {
        throw new Error(response.error || '执行接口未接受请求');
      }
      const dispatchedCount = response.dispatched_tasks?.length ?? 0;
      const schedulerResult = await triggerCronCheck();
      const readyDispatched = schedulerResult.readyStepDispatch?.dispatched ?? 0;
      const readyFailed = schedulerResult.readyStepDispatch?.failed ?? 0;
      setExecutePlanItem(null);
      setActionNotice(
        readyDispatched > 0 || readyFailed > 0
          ? `已触发执行：${planItem.title}，新建 ${dispatchedCount} 个步骤，Ready 步骤自动派发 ${readyDispatched} 个${readyFailed > 0 ? `，失败 ${readyFailed} 个` : ''}。`
          : `已触发执行：${planItem.title}，已派发 ${dispatchedCount} 个步骤。`,
      );
      await fetchProjection();
    } catch (error) {
      if (mountedRef.current) {
        setActionError(error instanceof Error ? error.message : '执行失败');
      }
    } finally {
      if (mountedRef.current) setActionBusy(null);
    }
  }, [fetchProjection]);

  const dismissWorkdayGuide = useCallback(() => {
    setGuideOpen(false);
    setGuideDismissedDate(selectedDate);
    rememberGuideDismissedDate(selectedDate);
  }, [selectedDate]);

  const renderDutyChecklistCard = useCallback((planItem: DigitalPlanItem, mode: 'guide' | 'manager') => {
    const selected = selectedDutyIds.has(planItem.id);
    const executeDisabledReason = planExecutionDisabledReason(planItem);
    return (
      <div
        key={`${mode}-${planItem.id}`}
        className={`${dutyCardClass(planItem, selected)} ${mode === 'guide' ? 'de-duty-card--guide' : ''}`}
        title={planItem.summary}
      >
        <label className="de-task-manager-duty-check">
          <input
            type="checkbox"
            checked={selected}
            disabled={!planItem.selectable || !planItem.implemented}
            onChange={() => toggleDuty(planItem)}
          />
          <span>{selected ? '已选' : planItem.implemented ? '未选' : '待扩展'}</span>
        </label>
        <div className="de-template-card-main">
          <div className="de-template-card-head">
            <span className="de-template-card-name">{planItem.title}</span>
            <span className={`de-badge ${badgeClass(planItem.statusTone)}`}>
              {planItem.implemented ? planItem.statusLabel : '待扩展'}
            </span>
          </div>
          <p className="de-template-card-desc">{planItem.summary}</p>
          <div className="de-template-card-meta">
            <span>{planItem.scheduleText}</span>
            <span>{planItem.resultText}</span>
          </div>
          <div className="de-duty-card-foot">
            <button
              type="button"
              className="de-btn-secondary de-btn-sm"
              disabled={!planItem.implemented}
              onClick={() => openDuty(planItem)}
            >
              进入处理
            </button>
            <div className="de-duty-card-actions">
              <button
                type="button"
                className="de-btn-secondary de-btn-sm"
                disabled={!planItem.implemented || actionBusy === `schedule:${planItem.id}`}
                onClick={() => setSchedulePlanItem(planItem)}
              >
                <Clock3 size={13} aria-hidden="true" />
                <span>定时</span>
              </button>
              <button
                type="button"
                className="de-btn-primary de-btn-sm"
                disabled={!planItem.implemented || actionBusy === `execute:${planItem.id}`}
                title={executeDisabledReason || '立即执行此任务'}
                onClick={() => setExecutePlanItem(planItem)}
              >
                <PlayCircle size={13} aria-hidden="true" />
                <span>执行</span>
              </button>
            </div>
            {!planItem.implemented && <span className="de-duty-selected-mark">待扩展</span>}
          </div>
        </div>
      </div>
    );
  }, [actionBusy, openDuty, selectedDutyIds, toggleDuty]);

  const openEventDetail = useCallback((event: DigitalEmployeeWorkEvent) => {
    setSelectedEvent(event);
    setFeedInteractionPaused(true);
  }, []);

  const closeEventDetail = useCallback(() => {
    setSelectedEvent(null);
    setFeedInteractionPaused(false);
  }, []);

  const closeEventHistory = useCallback(() => {
    setEventHistoryOpen(false);
    setFeedInteractionPaused(false);
  }, []);

  const openExecutionHistory = useCallback(() => {
    setEventHistoryOpen(true);
    setFeedInteractionPaused(true);
  }, []);

  const handleExecutionPanelClick = useCallback((event: ReactMouseEvent<HTMLDivElement>) => {
    if (isExecutionPanelInteractiveTarget(event.target)) return;
    openExecutionHistory();
  }, [openExecutionHistory]);

  const handleExecutionPanelKeyDown = useCallback((event: ReactKeyboardEvent<HTMLDivElement>) => {
    if (event.key !== 'Enter' && event.key !== ' ') return;
    if (isExecutionPanelInteractiveTarget(event.target)) return;
    event.preventDefault();
    openExecutionHistory();
  }, [openExecutionHistory]);

  const openEvent = useCallback((event: DigitalEmployeeWorkEvent) => {
    setSelectedEvent(null);
    setEventHistoryOpen(false);
    setFeedInteractionPaused(false);
    onNavigate({ tab: 'missions', date: selectedDate, missionId: event.conversation_id || event.id });
  }, [onNavigate, selectedDate]);

  return (
    <div className="de-dashboard de-dashboard--compact" style={{ position: 'relative', height: '100%', minHeight: 0, display: 'flex', flexDirection: 'column', overflow: 'hidden' }}>
      <div className="de-connection-layer" aria-hidden="true">
        <svg className="de-connection-svg" viewBox="0 0 1200 800" preserveAspectRatio="none">
          <defs>
            <linearGradient id="connGrad1" x1="0%" y1="0%" x2="100%" y2="100%">
              <stop offset="0%" stopColor="rgba(79,172,254,0.25)" />
              <stop offset="100%" stopColor="rgba(0,242,254,0.1)" />
            </linearGradient>
            <filter id="connGlow"><feGaussianBlur stdDeviation="3" /></filter>
          </defs>
          <path d="M 80 180 Q 420 400, 580 350" stroke="url(#connGrad1)" strokeWidth="1.5" fill="none" filter="url(#connGlow)" />
          <path d="M 120 620 Q 380 400, 560 380" stroke="url(#connGrad1)" strokeWidth="1.2" fill="none" filter="url(#connGlow)" />
          <path d="M 640 360 Q 780 200, 1100 160" stroke="url(#connGrad1)" strokeWidth="1.3" fill="none" filter="url(#connGlow)" />
        </svg>
      </div>

      <div className="de-dashboard-content">
        <div className="de-dashboard-left">
          <div className="de-card de-person-card de-person-card--compact">
            <div className="de-card-title-bar">
              <span className="de-card-title-bar-text">数字员工</span>
              <button
                type="button"
                className="de-btn-secondary de-btn-sm"
                onClick={() => setProfileSettingsOpen(true)}
              >
                特性设置
              </button>
            </div>
            <div className="de-card-body">
              <div className="de-info-grid">
                <div className="de-info-item"><label>姓名</label><span>{employee?.name ?? '同步中'}</span></div>
                <div className="de-info-item"><label>单位</label><span>{employee?.company ?? '同步中'}</span></div>
                <div className="de-info-item"><label>岗位</label><span>{employee?.position ?? employee?.major ?? '同步中'}</span></div>
                <div className="de-info-item"><label>当前状态</label><span className={isResting ? 'de-status-resting' : 'de-status-working'}>{currentStatusLabel}</span></div>
              </div>
            </div>
          </div>

          <div className="de-card de-template-manager-card">
            <div className="de-card-title-bar">
              <span className="de-card-title-bar-text">任务设置</span>
            </div>
            <div className="de-card-body de-template-manager-body">
              <div className="de-workday-toolbar">
                <label>
                  <span>日期</span>
                  <input
                    type="date"
                    value={selectedDate}
                    onChange={(event) => {
                      selectionDirtyRef.current = false;
                      setSelectionDirty(false);
                      setActionNotice(null);
                      setSelectedDate(event.target.value || todayInputDate());
                    }}
                  />
                </label>
                <button
                  type="button"
                  className="de-btn-secondary de-btn-sm"
                  disabled={projectionLoading}
                  onClick={() => setTaskManagerOpen(true)}
                >
                  任务设置
                </button>
                <button
                  type="button"
                  className="de-btn-secondary de-btn-sm"
                  disabled={projectionLoading || actionBusy === 'flush_management_sync'}
                  onClick={flushManagementSync}
                  title="立即同步数字员工本地状态到管理端"
                >
                  <RefreshCw size={13} aria-hidden="true" />
                  <span>{actionBusy === 'flush_management_sync' ? '同步中...' : '同步管理端'}</span>
                </button>
              </div>

              <div className={`de-management-sync-strip de-management-sync-strip--${managementSyncTone}`} title={managementSyncError || managementSyncSummary}>
                <span className={`de-badge ${badgeClass(managementSyncTone)}`}>{managementSyncLabel}</span>
                <span>{managementSyncSummary}</span>
              </div>

              {managementSyncFailures.length > 0 && (
                <div className="de-management-sync-failures" aria-label="同步失败明细">
                  {managementSyncFailures.map((failure) => (
                    <button
                      key={failure.id}
                      type="button"
                      className="de-management-sync-failure"
                      title={failure.error || failure.id}
                      onClick={() => setSelectedSyncFailure(failure)}
                    >
                      <span>{syncFailureTime(failure)}</span>
                      <strong>{entityTypeLabel(failure.entityType)}</strong>
                      <em>{failure.id}</em>
                      <small>{syncFailureSummary(failure)}</small>
                    </button>
                  ))}
                </div>
              )}

              {(actionNotice || actionError || planDataError || workdayProjection?.demo_reason) && (
                <div className={`de-schedule-result ${actionError ? 'de-schedule-result--error' : 'de-schedule-result--success'}`} style={{ marginBottom: 10 }}>
                  {actionError || actionNotice || planDataError || workdayProjection?.demo_reason}
                </div>
              )}
              {managedServiceIssues.length > 0 && (
                <div className="de-management-sync-failures" aria-label="服务状态处理" style={{ marginBottom: 10 }}>
                  {managedServiceIssues.map((service) => {
                    const actionKey = `managed-service:${service.service_id}:restart`;
                    const restartable = canRestartManagedService(service);
                    return (
                      <div key={service.service_id} className="de-management-sync-failure" title={service.error || managedServiceSummary(service)}>
                        <span>{service.kind}</span>
                        <strong>{service.name}</strong>
                        <em>{service.status_label}</em>
                        <small>{managedServiceSummary(service)}</small>
                        {restartable && (
                          <button
                            type="button"
                            className="de-btn-secondary de-btn-sm"
                            disabled={actionBusy === actionKey}
                            onClick={(event) => {
                              event.stopPropagation();
                              void restartService(service);
                            }}
                            title={`安全重启 ${service.name}`}
                          >
                            <RefreshCw size={13} aria-hidden="true" />
                            <span>{actionBusy === actionKey ? '重启中...' : '重启'}</span>
                          </button>
                        )}
                      </div>
                    );
                  })}
                </div>
              )}
              {selectionDirty && !actionNotice && !actionError && (
                <div className="de-schedule-result de-schedule-result--success" style={{ marginBottom: 10 }}>
                  当前选择尚未确认，自动刷新不会覆盖你的勾选。
                </div>
              )}

              <div className="de-template-overview">
                <button type="button" className={`de-template-overview-item de-template-overview-item--total ${taskListFilter === 'all' ? 'active' : ''}`} onClick={() => setTaskListFilter('all')}>
                  <span className="de-template-overview-label">总任务</span>
                  <span className="de-template-overview-value">{totalDuties.length}</span>
                </button>
                <button type="button" className={`de-template-overview-item de-template-overview-item--scheduled ${taskListFilter === 'selected' ? 'active' : ''}`} onClick={() => setTaskListFilter('selected')}>
                  <span className="de-template-overview-label">已选择</span>
                  <span className="de-template-overview-value">{selectedDuties.length}</span>
                </button>
                <button type="button" className={`de-template-overview-item de-template-overview-item--runnable ${taskListFilter === 'pending' ? 'active' : ''}`} onClick={() => setTaskListFilter('pending')}>
                  <span className="de-template-overview-label">待选择</span>
                  <span className="de-template-overview-value">{pendingDuties.length}</span>
                </button>
              </div>

              <div className="de-task-date-context">
                <span>当前日期 {selectedDateLabel}</span>
                <em>{visibleTaskListHint}</em>
                <button type="button" className="de-btn-secondary de-btn-sm" onClick={cancelAllTasks} disabled={selectedDuties.length === 0}>
                  一键取消
                </button>
              </div>

              <div className="de-task-manager-preview de-task-manager-preview-scroll de-template-task-list">
                <div className="de-task-manager-preview-head">
                  <span>{selectedDateLabel}</span>
                  <strong>{visibleTaskListLabel} {visibleTaskItems.length}</strong>
                </div>
                {projectionLoading ? (
                  <div className="de-loading-skeleton" style={{ height: 96 }} />
                ) : planItems.length === 0 ? (
                  <p className="de-empty-text">暂无任务，首页不会再展示硬编码任务。</p>
                ) : visibleTaskItems.length === 0 ? (
                  <p className="de-empty-text">当前筛选下暂无任务，点击总任务查看全部内容。</p>
                ) : (
                  visibleTaskItems.map((planItem) => (
                    <div
                      key={planItem.id}
                      className={`de-task-manager-preview-row ${selectedDutyIds.has(planItem.id) ? 'is-selected' : ''}`}
                      title={planItem.summary}
                    >
                      <button
                        type="button"
                        className="de-template-task-main"
                        onClick={() => openDuty(planItem)}
                      >
                        <strong>{planItem.title}</strong>
                        <span>{planItem.resultText}</span>
                      </button>
                      <div className="de-template-item-actions">
                        <button
                          type="button"
                          className="de-btn-secondary de-btn-sm"
                          disabled={!planItem.implemented || actionBusy === `schedule:${planItem.id}`}
                          onClick={() => setSchedulePlanItem(planItem)}
                        >
                          <Clock3 size={13} aria-hidden="true" />
                          <span>定时</span>
                        </button>
                        <button
                          type="button"
                          className="de-btn-primary de-btn-sm"
                          disabled={!planItem.implemented || actionBusy === `execute:${planItem.id}`}
                          title={planExecutionDisabledReason(planItem) || '立即执行此任务'}
                          onClick={() => setExecutePlanItem(planItem)}
                        >
                          <PlayCircle size={13} aria-hidden="true" />
                          <span>执行</span>
                        </button>
                      </div>
                    </div>
                  ))
                )}
              </div>
            </div>
          </div>
        </div>

        <div className="de-dashboard-center" style={{ justifyContent: 'center', padding: '0 0 16px', overflow: 'visible' }}>
          <div className="de-avatar-wrapper" style={{ minHeight: 470, maxWidth: 560, transform: 'translateY(-6px)', display: 'flex', alignItems: 'flex-end', justifyContent: 'center' }}>
            <Avatar3D avatarSrc={activeVisual.src} altText={`数字员工-${activeVisual.label}`} statusLabel={activeVisual.label} />
          </div>

          <div className="de-speech-bubble de-speech-bubble--employee" style={{ top: '38%', left: '29%', right: 'auto', transform: 'translateX(-50%)', width: 268, padding: '10px 12px', zIndex: 16 }}>
            <span className="de-speech-label">数字员工播报</span>
            <p className="de-speech-text">{bubbleText}</p>
            <button
              type="button"
              className="de-speech-workflow de-execution-detail-trigger"
              onClick={openExecutionHistory}
              title="打开运行明细"
            >
              <span>当前动作</span>
              <strong>{currentActionTitle}</strong>
              <small>{currentActionDetail}</small>
              <span>下一步</span>
              <small>{nextStepText}</small>
            </button>
          </div>
        </div>

        <div className="de-dashboard-right">
          <div className="de-right-panels">
            <div
              className="de-workbench de-workday-execution de-workday-execution--clickable"
              role="button"
              tabIndex={0}
              aria-label="打开运行明细"
              title="打开运行明细"
              onClick={handleExecutionPanelClick}
              onKeyDown={handleExecutionPanelKeyDown}
            >
              <div className="de-card-title-bar de-workbench-head de-workbench-head--bar">
                <div className="de-workbench-title-row">
                  <h3>今日执行</h3>
                </div>
                <span className={`de-badge ${projectionSourceClass}`}>{projectionSourceLabel}</span>
              </div>

              <div className="de-workday-execution-body" aria-live="polite">
                <div className="de-execution-status-strip">
                  <span><em>已选任务</em><strong>{selectedDuties.length}</strong></span>
                  <span><em>运行记录</em><strong>{visibleEvents.length}</strong></span>
                  <span><em>已完成</em><strong>{completedEvents.length}</strong></span>
                  <span><em>异常</em><strong>{failedEvents.length}</strong></span>
                </div>

                {(diagnosticSummary || (routeSummary && routeSummary.total > 0)) && (
                  <div className="de-observation-strip-stack">
                    {routeSummary && routeSummary.total > 0 && (
                      <div className="de-route-summary-strip">
                        <span><em>入口路由</em><strong>{routeSummary.total}</strong></span>
                        <span><em>已映射</em><strong>{routeSummary.mapped_count}</strong></span>
                        <span className={routeSummary.attention_count > 0 ? 'is-warning' : ''}><em>需关注</em><strong>{routeSummary.attention_count}</strong></span>
                        <small>{latestRoute ? `${latestRoute.route_kind} / ${latestRoute.intent_kind} · ${latestRoute.status_label}` : '暂无路由决策'}</small>
                      </div>
                    )}

                    {diagnosticSummary && (
                      <div className="de-diagnostic-summary-strip">
                        <span className={diagnosticIssueCount > 0 ? 'is-warning' : ''}><em>诊断异常</em><strong>{diagnosticIssueCount}</strong></span>
                        <span className={auditRiskCount > 0 ? 'is-warning' : ''}><em>审计风险</em><strong>{auditRiskCount}</strong></span>
                        <span><em>估算请求</em><strong>{diagnosticSummary.cost.request_count}</strong></span>
                        <small>{latestDiagnosticIssue ? `${latestDiagnosticIssue.category} · ${latestDiagnosticIssue.message}` : '诊断、审计和成本投影正常'}</small>
                      </div>
                    )}
                  </div>
                )}

                <div className="de-task-summary-scroll">
                  <div className="de-task-summary-grid" aria-label="任务执行汇总">
                    {taskSummaryCards.length === 0 ? (
                      <p className="de-empty-text">左侧选择任务后，这里会按任务生成执行次数和成功情况。</p>
                    ) : (
                      taskSummaryCards.map((summary) => (
                        <button
                          type="button"
                          key={summary.id}
                          className={`de-task-summary-card de-live-feed-row--${summary.latest_status_tone || 'info'}`}
                          onClick={() => openDuty(selectedDuties.find((item) => item.id === summary.id) ?? selectedDuties[0]!)}
                          title={[summary.description, summary.ai_summary || summary.business_summary].filter(Boolean).join('\n')}
                        >
                          <span className="de-task-summary-title">{summary.title}</span>
                          <span className={`de-badge ${badgeClass(summary.latest_status_tone)}`}>{summary.latest_status_label}</span>
                          <div className="de-task-summary-counts">
                            <span><em>执行</em><strong>{summary.total_count}</strong></span>
                            <span><em>成功</em><strong>{summary.success_count}</strong></span>
                            <span><em>失败</em><strong>{summary.failure_count}</strong></span>
                          </div>
                        </button>
                      ))
                    )}
                  </div>
                </div>

                {actionableTaskAgents.length > 0 && (
                  <div className="de-task-agent-control-strip" aria-label="Task Agent 控制台">
                    {actionableTaskAgents.slice(0, 2).map((agent) => {
                      const retryBusy = actionBusy === `task-agent:${agent.task_id}:retry_task`;
                      const skipBusy = actionBusy === `task-agent:${agent.task_id}:skip_task`;
                      const cancelBusy = actionBusy === `task-agent:${agent.task_id}:cancel_task`;
                      return (
                        <div key={agent.agent_id} className={`de-task-agent-control de-live-feed-row--${agent.status_tone || 'info'}`}>
                          <div className="de-task-agent-control-main">
                            <span>Task Agent</span>
                            <strong>{agent.title}</strong>
                            <small>{agent.status_label} · {agent.next_action}</small>
                          </div>
                          <div className="de-task-agent-control-actions">
                            {agent.can_retry && (
                              <button
                                type="button"
                                className="de-btn-secondary de-btn-sm"
                                disabled={Boolean(actionBusy)}
                                title="记录重试任务命令"
                                onClick={() => { void controlTaskAgent(agent, 'retry_task'); }}
                              >
                                <RefreshCw size={13} aria-hidden="true" />
                                <span>{retryBusy ? '重试中' : '重试'}</span>
                              </button>
                            )}
                            {agent.can_skip && (
                              <button
                                type="button"
                                className="de-btn-secondary de-btn-sm"
                                disabled={Boolean(actionBusy)}
                                title="记录跳过任务命令"
                                onClick={() => { void controlTaskAgent(agent, 'skip_task'); }}
                              >
                                <SkipForward size={13} aria-hidden="true" />
                                <span>{skipBusy ? '跳过中' : '跳过'}</span>
                              </button>
                            )}
                            {agent.can_cancel && (
                              <button
                                type="button"
                                className="de-btn-secondary de-btn-sm de-task-agent-cancel-btn"
                                disabled={Boolean(actionBusy)}
                                title="记录取消任务命令"
                                onClick={() => { void controlTaskAgent(agent, 'cancel_task'); }}
                              >
                                <Square size={12} aria-hidden="true" />
                                <span>{cancelBusy ? '取消中' : '取消'}</span>
                              </button>
                            )}
                          </div>
                        </div>
                      );
                    })}
                  </div>
                )}

                <div className="de-stage-feed-tools">
                  <span>
                    展示 {visibleEvents.length} / 共 {allEvents.length} 条
                    {feedPaused ? ' · 已暂停' : ' · 自动滚动'}
                  </span>
                  <div>
                    <button
                      type="button"
                      className="de-btn-secondary de-btn-sm"
                      onClick={() => setFeedManuallyPaused((current) => !current)}
                    >
                      {feedManuallyPaused ? '继续滚动' : '暂停滚动'}
                    </button>
                    <button
                      type="button"
                      className="de-btn-secondary de-btn-sm"
                      onClick={openExecutionHistory}
                    >
                      查看全部记录
                    </button>
                  </div>
                </div>

                <div className="de-run-detail-panel">
                  <div className="de-run-detail-head">
                    <span>运行明细</span>
                    <small>展示 {visibleRunDetails.length} / 共 {runDetails.length} 条</small>
                  </div>
                  <div className="de-run-detail-list de-run-detail-list-scroll" aria-label="运行明细">
                    <div className="de-run-detail-row de-run-detail-row--head">
                      <span>时间</span>
                      <span>任务名称</span>
                      <span>步骤名称</span>
                      <span>执行状态</span>
                      <span>结果</span>
                    </div>
                    {visibleRunDetails.length === 0 ? (
                      <p className="de-empty-text">任务执行后，这里会滚动显示每个步骤的时间、任务、步骤和结果。</p>
                    ) : (
                      visibleRunDetails.map((detail) => (
                        <button
                          key={detail.id}
                          type="button"
                          className={`de-run-detail-row de-live-feed-row--${detail.status_tone || 'info'}`}
                          onClick={() => {
                            const event = allEvents.find((item) => item.id === detail.id);
                            if (event) openEventDetail(event);
                          }}
                          title={detail.business_detail}
                        >
                          <span>{runDetailDisplayTime(detail)}</span>
                          <strong>{detail.task_name}</strong>
                          <span>{detail.step_name || detail.operation_name || '执行步骤'}</span>
                          <span><i className={`de-badge ${badgeClass(detail.status_tone)}`}>{detail.status_label}</i></span>
                          <em>{detail.business_detail}</em>
                        </button>
                      ))
                    )}
                  </div>
                </div>
              </div>
            </div>

            <div className="de-report-summary">
              <div className="de-card-title-bar de-report-summary-head de-report-summary-head--bar">
                <div className="de-report-summary-title-row">
                  <h3>日报生成</h3>
                </div>
                <span className={`de-report-badge ${dailyReport?.status === 'ready' ? 'de-report-badge--ready' : 'de-report-badge--waiting'}`}>
                  {dailyReport?.status === 'ready' ? '已生成' : '待生成'}
                </span>
              </div>
              <div className="de-report-summary-body">
                <div className="de-report-schedule-row">
                  <label>
                    <span>生成时间</span>
                    <input
                      type="time"
                      value={reportScheduleTime}
                      onChange={(event) => setReportScheduleTime(event.target.value || '18:00')}
                    />
                  </label>
                  <button
                    type="button"
                    className="de-btn-secondary de-btn-sm"
                    disabled={actionBusy === 'update_report_schedule'}
                    onClick={() => { void saveReportSchedule(); }}
                  >
                    设置时间
                  </button>
                  <button
                    type="button"
                    className="de-btn-primary de-btn-sm"
                    disabled={actionBusy === 'generate_daily_report'}
                    onClick={() => { void generateDailyReport(); }}
                  >
                    {actionBusy === 'generate_daily_report' ? '生成中...' : '生成日报'}
                  </button>
                  <button
                    type="button"
                    className="de-btn-secondary de-btn-sm de-report-preview-btn"
                    disabled={!reportPreviewAvailable}
                    onClick={() => setReportPreviewOpen(true)}
                    title={reportPreviewAvailable ? '预览日报文字内容' : '生成日报后可预览文字内容'}
                  >
                    <Eye size={14} aria-hidden="true" />
                    预览日报
                  </button>
                  <button
                    type="button"
                    className="de-btn-secondary de-btn-sm de-report-download-btn"
                    disabled={!dailyReport?.pdf_available}
                    onClick={downloadDailyReport}
                    title={dailyReport?.pdf_available ? '下载本地日报文本' : '生成日报后可下载本地日报'}
                  >
                    <Download size={14} aria-hidden="true" />
                    下载日报
                  </button>
                </div>
                <div className="de-report-meta">
                  <p>{dailyReport?.summary ?? '点击生成日报后，AI 会基于当天所有任务写出总分结构日报。'}</p>
                  {(dailyReport?.detail_lines ?? []).slice(0, 3).map((line) => <p key={line}>{line}</p>)}
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>

      {reportPreviewOpen && dailyReport && (
        <div className="de-task-manager-modal-overlay de-report-preview-overlay" role="presentation" onClick={() => setReportPreviewOpen(false)}>
          <div
            className="de-report-preview-modal"
            role="dialog"
            aria-modal="true"
            aria-label="日报预览"
            onClick={(event) => event.stopPropagation()}
          >
            <div className="de-task-manager-modal-head">
              <div>
                <span className="de-drawer-eyebrow">DAILY REPORT</span>
                <h3>{dailyReport.title || '数字员工日报'}</h3>
                <p>{selectedDateLabel} 生成时间 {dailyReport.report_schedule_time}，来源：{dailyReport.generated_by === 'ai' ? 'AI 生成' : '规则兜底'}</p>
              </div>
              <button type="button" className="de-schedule-close" onClick={() => setReportPreviewOpen(false)}>×</button>
            </div>
            <div className="de-report-preview-summary">
              <div><span>任务总数</span><strong>{reportTaskCount}</strong></div>
              <div><span>执行次数</span><strong>{reportExecutionCount}</strong></div>
              <div><span>成功次数</span><strong>{reportSuccessCount}</strong></div>
              <div><span>失败次数</span><strong>{reportFailureCount}</strong></div>
            </div>
            <div className="de-report-preview-content">
              {reportPreviewLines.length === 0 ? (
                <p className="de-empty-text">当前日报暂无可预览文字。</p>
              ) : (
                reportPreviewLines.map((line, index) => (
                  <p key={`${index}-${line}`}>{line}</p>
                ))
              )}
            </div>
            <div className="de-event-modal-actions">
              <button type="button" className="de-btn-secondary de-btn-sm" onClick={() => setReportPreviewOpen(false)}>关闭</button>
              <button
                type="button"
                className="de-btn-secondary de-btn-sm de-report-download-btn"
                disabled={!dailyReport.pdf_available}
                onClick={downloadDailyReport}
              >
                <Download size={14} aria-hidden="true" />
                下载日报
              </button>
            </div>
          </div>
        </div>
      )}

      {profileSettingsOpen && (
        <div className="de-task-manager-modal-overlay" role="presentation" onClick={() => setProfileSettingsOpen(false)}>
          <div
            className="de-profile-settings-modal"
            role="dialog"
            aria-modal="true"
            aria-label="数字员工特性设置"
            onClick={(event) => event.stopPropagation()}
          >
            <div className="de-task-manager-modal-head">
              <div>
                <span className="de-drawer-eyebrow">PROFILE</span>
                <h3>特性设置</h3>
                <p>维护数字员工在首页展示的姓名、单位、岗位和当前状态。</p>
              </div>
              <button type="button" className="de-schedule-close" onClick={() => setProfileSettingsOpen(false)}>×</button>
            </div>
            <div className="de-profile-settings-grid">
              <label>
                <span>姓名</span>
                <input value={profileForm.name} onChange={(event) => setProfileForm((current) => ({ ...current, name: event.target.value }))} />
              </label>
              <label>
                <span>单位</span>
                <input value={profileForm.company} onChange={(event) => setProfileForm((current) => ({ ...current, company: event.target.value }))} />
              </label>
              <label>
                <span>岗位</span>
                <input value={profileForm.position} onChange={(event) => setProfileForm((current) => ({ ...current, position: event.target.value }))} />
              </label>
              <div className="de-profile-status-toggle">
                <span>当前状态</span>
                <div>
                  <button
                    type="button"
                    className={profileForm.currentStatus === 'working' ? 'active' : ''}
                    onClick={() => setProfileForm((current) => ({ ...current, currentStatus: 'working' }))}
                  >
                    工作中
                  </button>
                  <button
                    type="button"
                    className={profileForm.currentStatus === 'resting' ? 'active' : ''}
                    onClick={() => setProfileForm((current) => ({ ...current, currentStatus: 'resting' }))}
                  >
                    休息中
                  </button>
                </div>
              </div>
            </div>
            <div className="de-event-modal-actions">
              <button type="button" className="de-btn-secondary de-btn-sm" onClick={() => setProfileSettingsOpen(false)}>取消</button>
              <button
                type="button"
                className="de-btn-primary de-btn-sm"
                disabled={actionBusy === 'update_profile'}
                onClick={() => { void saveProfileSettings(); }}
              >
                {actionBusy === 'update_profile' ? '保存中...' : '保存设置'}
              </button>
            </div>
          </div>
        </div>
      )}

      {selectedSyncFailure && (
        <div className="de-task-manager-modal-overlay" role="presentation" onClick={() => setSelectedSyncFailure(null)}>
          <div
            className="de-event-detail-modal"
            role="dialog"
            aria-modal="true"
            aria-label="同步失败详情"
            onClick={(event) => event.stopPropagation()}
          >
            <div className="de-task-manager-modal-head">
              <div>
                <span className="de-drawer-eyebrow">SYNC FAILURE</span>
                <h3>同步失败详情</h3>
                <p>{entityTypeLabel(selectedSyncFailure.entityType)} / {selectedSyncFailure.operation}</p>
              </div>
              <button type="button" className="de-schedule-close" onClick={() => setSelectedSyncFailure(null)}>×</button>
            </div>
            <div className="de-event-detail-grid">
              <div><span>Outbox</span><strong>{selectedSyncFailure.id}</strong></div>
              <div><span>实体</span><strong>{selectedSyncFailure.entityId}</strong></div>
              {selectedSyncFailure.entitySummary?.title && (
                <div><span>业务</span><strong>{selectedSyncFailure.entitySummary.title}</strong></div>
              )}
              {selectedSyncFailure.entitySummary?.status && (
                <div><span>业务状态</span><strong>{selectedSyncFailure.entitySummary.status}</strong></div>
              )}
              <div><span>类型</span><strong>{entityTypeLabel(selectedSyncFailure.entityType)}</strong></div>
              <div><span>操作</span><strong>{selectedSyncFailure.operation}</strong></div>
              <div><span>重试</span><strong>{selectedSyncFailure.attempts} 次</strong></div>
              <div><span>上次尝试</span><strong>{syncFailureTime(selectedSyncFailure)}</strong></div>
              <div><span>下次重试</span><strong>{syncFailureRetryTime(selectedSyncFailure)}</strong></div>
              <div><span>状态</span><strong>{selectedSyncFailure.dueForRetry ? '等待补偿' : '退避中'}</strong></div>
            </div>
            <div className="de-event-detail-result">
              <span>失败原因</span>
              <p>{selectedSyncFailure.error || '暂无错误详情。'}</p>
            </div>
            {selectedSyncFailure.entitySummary?.summary && (
              <div className="de-event-detail-result">
                <span>业务摘要</span>
                <p>{selectedSyncFailure.entitySummary.summary}</p>
              </div>
            )}
            {(selectedSyncFailure.attemptHistory?.length ?? 0) > 0 && (
              <div className="de-sync-attempt-history">
                <span>重试历史</span>
                <div className="de-sync-attempt-list">
                  {selectedSyncFailure.attemptHistory?.map((attempt) => (
                    <div
                      key={`${attempt.attemptNo}-${attempt.finishedAt}`}
                      className={`de-sync-attempt-row de-sync-attempt-row--${syncAttemptTone(
                        attempt.status,
                      )}`}
                    >
                      <div>
                        <strong>第 {attempt.attemptNo} 次</strong>
                        <em>{syncAttemptStatusLabel(attempt.status)}</em>
                        <span>
                          {formatBeijingDateTime(attempt.finishedAt) ||
                            attempt.finishedAt}
                        </span>
                      </div>
                      {attempt.error && <small>{attempt.error}</small>}
                    </div>
                  ))}
                </div>
              </div>
            )}
            <div className="de-event-modal-actions">
              <button
                type="button"
                className="de-btn-secondary de-btn-sm"
                onClick={() => setSelectedSyncFailure(null)}
              >
                关闭
              </button>
              <button
                type="button"
                className="de-btn-secondary de-btn-sm"
                onClick={() => {
                  void copySyncFailureDiagnostic(selectedSyncFailure);
                }}
              >
                <Clipboard size={14} />
                复制诊断
              </button>
              <button
                type="button"
                className="de-btn-secondary de-btn-sm"
                onClick={() => exportSyncFailureDiagnostic(selectedSyncFailure)}
              >
                <Download size={14} />
                导出诊断
              </button>
              {selectedSyncFailure.managementRecordUrl && (
                <button
                  type="button"
                  className="de-btn-secondary de-btn-sm"
                  onClick={() =>
                    window.open(
                      selectedSyncFailure.managementRecordUrl || '',
                      '_blank',
                      'noopener,noreferrer',
                    )
                  }
                >
                  <Eye size={14} />
                  查看管理端记录
                </button>
              )}
              <button
                type="button"
                className="de-btn-primary de-btn-sm"
                disabled={actionBusy === 'flush_management_sync'}
                onClick={() => {
                  void flushManagementSync().then(() => setSelectedSyncFailure(null));
                }}
              >
                {actionBusy === 'flush_management_sync' ? '同步中...' : '立即重试'}
              </button>
            </div>
          </div>
        </div>
      )}

      {selectedEvent && (
        <div className="de-task-manager-modal-overlay" role="presentation" onClick={closeEventDetail}>
          <div
            className="de-event-detail-modal"
            role="dialog"
            aria-modal="true"
            aria-label="执行记录详情"
            onClick={(event) => event.stopPropagation()}
          >
            <div className="de-task-manager-modal-head">
              <div>
                <span className="de-drawer-eyebrow">EXECUTION DETAIL</span>
                <h3>执行记录详情</h3>
                <p>这条记录已被锁定，滚动不会把它刷掉。</p>
              </div>
              <button type="button" className="de-schedule-close" onClick={closeEventDetail}>×</button>
            </div>
            <div className="de-event-detail-grid">
              <div><span>业务</span><strong>{selectedEvent.plan_title}</strong></div>
              <div><span>操作</span><strong>{selectedEvent.task_title}</strong></div>
              <div><span>状态</span><strong>{eventStatusText(selectedEvent)}</strong></div>
              <div><span>计划时间</span><strong>{eventScheduleTime(selectedEvent)}</strong></div>
              <div><span>执行时间</span><strong>{eventDisplayTime(selectedEvent)}</strong></div>
              <div><span>数据来源</span><strong>{projectionSourceLabel}</strong></div>
            </div>
            <div className="de-event-detail-result">
              <span>操作结果</span>
              <p>{eventBusinessResult(selectedEvent)}</p>
            </div>
            <div className="de-event-modal-actions">
              <button type="button" className="de-btn-secondary de-btn-sm" onClick={closeEventDetail}>关闭</button>
              <button type="button" className="de-btn-primary de-btn-sm" onClick={() => openEvent(selectedEvent)}>
                打开任务中心详情
              </button>
            </div>
          </div>
        </div>
      )}

      {eventHistoryOpen && (
        <div className="de-task-manager-modal-overlay" role="presentation" onClick={closeEventHistory}>
          <div
            className="de-event-history-modal"
            role="dialog"
            aria-modal="true"
            aria-label="全部执行记录"
            onClick={(event) => event.stopPropagation()}
          >
            <div className="de-task-manager-modal-head">
              <div>
                <span className="de-drawer-eyebrow">EXECUTION HISTORY</span>
                <h3>运行明细</h3>
                <p>当前日期共 {allEvents.length} 条记录，本窗口展示最新 {Math.min(filteredHistoryEvents.length, EVENT_HISTORY_RENDER_LIMIT)} 条。</p>
              </div>
              <button type="button" className="de-schedule-close" onClick={closeEventHistory}>×</button>
            </div>
            <div className="de-event-history-toolbar">
              {EVENT_STATUS_FILTERS.map((filter) => (
                <button
                  key={filter.id}
                  type="button"
                  className={`de-filter-chip ${eventStatusFilter === filter.id ? 'active' : ''}`}
                  onClick={() => setEventStatusFilter(filter.id)}
                >
                  {filter.label}
                </button>
              ))}
            </div>
            <div className="de-event-history-list">
              {filteredHistoryEvents.length === 0 ? (
                <p className="de-empty-text">当前筛选下没有执行记录。</p>
              ) : (
                visibleHistoryEvents.map((event) => (
                  <button
                    key={event.id}
                    type="button"
                    className={`de-event-history-row de-live-feed-row--${event.status_tone || 'info'}`}
                    onClick={() => {
                      setSelectedEvent(event);
                      setEventHistoryOpen(false);
                      setFeedInteractionPaused(true);
                    }}
                  >
                    <span><em>业务</em><strong>{event.plan_title}</strong></span>
                    <span><em>操作</em><strong>{event.task_title}</strong></span>
                    <span><em>状态</em><strong>{eventStatusText(event)}</strong></span>
                    <span><em>操作结果</em><strong>{eventBusinessResult(event)}</strong><small>{eventTimingSummary(event)}</small></span>
                  </button>
                ))
              )}
            </div>
          </div>
        </div>
      )}

      {schedulePlanItem && (
        <div className="de-task-manager-modal-overlay de-plan-action-overlay" role="presentation" onClick={() => setSchedulePlanItem(null)}>
          <div
            className="de-plan-action-modal"
            role="dialog"
            aria-modal="true"
            aria-label="定时任务"
            onClick={(event) => event.stopPropagation()}
          >
            <div className="de-task-manager-modal-head">
              <div>
                <span className="de-drawer-eyebrow">PLAN SCHEDULE</span>
                <h3>定时任务</h3>
                <p>定时会把任务注册到后端调度链路，每天按设置时间自动派发。</p>
              </div>
              <button type="button" className="de-schedule-close" onClick={() => setSchedulePlanItem(null)}>×</button>
            </div>
            <div className="de-plan-action-body">
              <div className="de-event-detail-result">
                <span>任务</span>
                <p>{schedulePlanItem.title}</p>
              </div>
              <label className="de-plan-action-field">
                <span>每日定时时间</span>
                <input
                  type="time"
                  value={scheduleTime}
                  onChange={(event) => setScheduleTime(event.target.value || '09:00')}
                />
              </label>
              <div className="de-event-detail-grid de-plan-action-grid">
                <div><span>调度注册</span><strong>{cronExprForDailyTime(scheduleTime)}</strong></div>
                <div><span>任务步骤</span><strong>{schedulePlanItem.stepCount} 步</strong></div>
                <div><span>执行步骤</span><strong>{schedulePlanItem.taskCount} 项</strong></div>
              </div>
              <div className="de-schedule-result de-schedule-result--success">
                这里不是本地假定时；提交后如果后端调度链路不可用，会直接显示真实失败原因。
              </div>
            </div>
            <div className="de-event-modal-actions">
              <button type="button" className="de-btn-secondary de-btn-sm" onClick={() => setSchedulePlanItem(null)}>取消</button>
              <button
                type="button"
                className="de-btn-primary de-btn-sm"
                disabled={actionBusy === `schedule:${schedulePlanItem.id}`}
                onClick={() => { void createPlanSchedule(schedulePlanItem); }}
              >
                {actionBusy === `schedule:${schedulePlanItem.id}` ? '注册中...' : '确认定时'}
              </button>
            </div>
          </div>
        </div>
      )}

      {executePlanItem && (
        <div className="de-task-manager-modal-overlay de-plan-action-overlay" role="presentation" onClick={() => setExecutePlanItem(null)}>
          <div
            className="de-plan-action-modal"
            role="dialog"
            aria-modal="true"
            aria-label="执行任务"
            onClick={(event) => event.stopPropagation()}
          >
            <div className="de-task-manager-modal-head">
              <div>
                <span className="de-drawer-eyebrow">PLAN EXECUTION</span>
                <h3>执行任务</h3>
                <p>确认后立即创建并派发任务步骤，不需要先进入任务中心设置。</p>
              </div>
              <button type="button" className="de-schedule-close" onClick={() => setExecutePlanItem(null)}>×</button>
            </div>
            <div className="de-plan-action-body">
              <div className="de-event-detail-result">
                <span>任务</span>
                <p>{executePlanItem.title}</p>
              </div>
              <div className="de-event-detail-grid de-plan-action-grid">
                <div><span>当前状态</span><strong>{executePlanItem.statusLabel}</strong></div>
                <div><span>任务步骤</span><strong>{executePlanItem.stepCount} 步</strong></div>
                <div><span>执行步骤</span><strong>{executePlanItem.taskCount} 项</strong></div>
              </div>
              <div className={`de-schedule-result ${isPlanItemExecutable(executePlanItem) ? 'de-schedule-result--success' : 'de-schedule-result--pending'}`}>
                {isPlanItemExecutable(executePlanItem)
                  ? '确认后立即调用后端派发接口，按任务步骤进入真实执行链路。'
                  : planExecutionDisabledReason(executePlanItem)}
              </div>
            </div>
            <div className="de-event-modal-actions">
              <button type="button" className="de-btn-secondary de-btn-sm" onClick={() => setExecutePlanItem(null)}>取消</button>
              <button
                type="button"
                className="de-btn-primary de-btn-sm"
                disabled={actionBusy === `execute:${executePlanItem.id}` || !isPlanItemExecutable(executePlanItem)}
                onClick={() => { void confirmImmediatePlanExecution(executePlanItem); }}
              >
                {actionBusy === `execute:${executePlanItem.id}` ? '触发中...' : '确认执行'}
              </button>
            </div>
          </div>
        </div>
      )}

      {guideOpen && needsWorkdayConfirmation && (
        <div className="de-task-manager-modal-overlay de-workday-guide-overlay" role="presentation" onClick={dismissWorkdayGuide}>
          <div
            className="de-task-manager-modal de-workday-guide-modal"
            role="dialog"
            aria-modal="true"
            aria-label="开始今天的任务"
            onClick={(event) => event.stopPropagation()}
          >
            <div className="de-task-manager-modal-head de-workday-guide-head">
              <div>
                <span className="de-drawer-eyebrow">WORKDAY START</span>
                <h3>开始今天的任务</h3>
                <p>像值班员早上交接一样，先确认日期和执行内容，再让数字员工开始接单、外呼、汇总和汇报。</p>
              </div>
              <button type="button" className="de-schedule-close" onClick={dismissWorkdayGuide}>×</button>
            </div>

            <div className="de-workday-guide-steps" aria-label="开工引导步骤">
              {WORKDAY_GUIDE_STEPS.map((step, index) => (
                <div key={step.title} className="de-workday-guide-step">
                  <span>{index + 1}</span>
                  <strong>{step.title}</strong>
                  <p>{step.body}</p>
                </div>
              ))}
            </div>

            <div className="de-workday-guide-body">
              <section className="de-task-manager-column de-workday-guide-column">
                <div className="de-task-manager-section-head">
                  <div>
                    <strong>选择今天要执行的任务</strong>
                    <span>{selectedDuties.length} 项已选，{totalDuties.length} 项总任务，{pendingDuties.length} 项待选择</span>
                  </div>
                  <span className={`de-badge ${projectionSourceClass}`}>{projectionSourceLabel}</span>
                </div>
                <div className="de-workday-guide-duty-list">
                  {projectionLoading ? (
                    <div className="de-loading-skeleton" style={{ height: 220 }} />
                  ) : planItems.length === 0 ? (
                    <p className="de-empty-text">暂无任务，首页不再展示硬编码任务。请先在任务中心创建或同步。</p>
                  ) : (
                    planItems.map((planItem) => renderDutyChecklistCard(planItem, 'guide'))
                  )}
                </div>
              </section>

              <aside className="de-workday-guide-side">
                <div className="de-workday-guide-summary">
                  <span>日期</span>
                  <strong>{selectedDate}</strong>
                  <p>{workdaySummaryText}</p>
                </div>
                <div className="de-workday-guide-summary">
                  <span>确认后会发生什么</span>
                  <strong>右侧进入执行滚动</strong>
                  <p>首页会展示当前动作、下一步、操作状态和操作结果；需要人工决策时会在右侧停下来提示。</p>
                </div>
                {(actionError || selectionDirty || workdayProjection?.demo_reason) && (
                  <div className={`de-schedule-result ${actionError ? 'de-schedule-result--error' : 'de-schedule-result--success'}`}>
                    {actionError || (selectionDirty ? '已调整任务勾选，点击确认后生效。' : workdayProjection?.demo_reason)}
                  </div>
                )}
                <div className="de-workday-guide-actions">
                  <button type="button" className="de-btn-secondary de-btn-sm" onClick={dismissWorkdayGuide}>
                    稍后设置
                  </button>
                  <button
                    type="button"
                    className="de-btn-primary de-btn-sm"
                    disabled={actionBusy === 'confirm_workday' || projectionLoading}
                    onClick={() => { void confirmWorkday(); }}
                  >
                    {actionBusy === 'confirm_workday' ? '确认中...' : '确认并开始任务'}
                  </button>
                </div>
              </aside>
            </div>
          </div>
        </div>
      )}

      {taskManagerOpen && (
        <div className="de-task-manager-modal-overlay" role="presentation" onClick={() => setTaskManagerOpen(false)}>
          <div
            className="de-task-manager-modal"
            role="dialog"
            aria-modal="true"
            aria-label="任务设置"
            onClick={(event) => event.stopPropagation()}
          >
            <div className="de-task-manager-modal-head">
              <div>
                <span className="de-drawer-eyebrow">TASK MANAGER</span>
                <h3>任务设置</h3>
                <p>像员工早上确认工作一样，勾选今天要执行的内容，必要时进入详情或处理待决策事项。</p>
              </div>
              <button type="button" className="de-schedule-close" onClick={() => setTaskManagerOpen(false)}>×</button>
            </div>

            <div className="de-task-manager-modal-body">
              <section className="de-task-manager-column de-task-manager-column--duties">
                <div className="de-task-manager-section-head">
                  <div>
                    <strong>任务设置清单</strong>
                    <span>{selectedDuties.length} 项已选，{totalDuties.length} 项总任务，{pendingDuties.length} 项待选择</span>
                  </div>
                  <button
                    type="button"
                    className="de-btn-primary de-btn-sm"
                    disabled={actionBusy === 'confirm_workday' || projectionLoading}
                    onClick={() => { void confirmWorkday(); }}
                  >
                    {actionBusy === 'confirm_workday' ? '确认中...' : workday?.confirmed ? '重新任务执行' : '确认并开始任务'}
                  </button>
                </div>

                <div className="de-task-manager-duty-list">
                  {projectionLoading ? (
                    <div className="de-loading-skeleton" style={{ height: 180 }} />
                  ) : planItems.length === 0 ? (
                    <p className="de-empty-text">暂无任务，首页不会显示硬编码任务。可进入任务中心创建。</p>
                  ) : (
                    planItems.map((planItem) => renderDutyChecklistCard(planItem, 'manager'))
                  )}
                </div>
              </section>

              <aside className="de-task-manager-column de-task-manager-column--actions">
                <div className="de-task-manager-section-head">
                  <div>
                    <strong>待解决事项</strong>
                    <span>{pendingDecisions.length > 0 ? `${pendingDecisions.length} 项需要人处理` : '暂无阻塞事项'}</span>
                  </div>
                </div>
                <div className="de-task-manager-decision-list">
                  {(workdayProjection?.decisions ?? []).length === 0 ? (
                    <p className="de-empty-text">没有需要你确认的事项。</p>
                  ) : (
                    (workdayProjection?.decisions ?? []).map((decision) => {
                      const draft = approvalActionDrafts[decision.id] ?? EMPTY_APPROVAL_ACTION_DRAFT;
                      const actionBusyPrefix = `approval-action:${decision.id}:`;
                      const commentBusy = actionBusy === `${actionBusyPrefix}comment`;
                      const delegateBusy = actionBusy === `${actionBusyPrefix}delegate`;
                      const timeoutBusy = actionBusy === `${actionBusyPrefix}mark_timeout`;
                      const markRiskBusy = actionBusy === `${actionBusyPrefix}mark_risk`;
                      const clearRiskBusy = actionBusy === `${actionBusyPrefix}clear_risk`;
                      return (
                        <div key={decision.id} className="de-task-manager-decision-card">
                          <div className="de-log-entry-meta">
                            <strong>{decision.title}</strong>
                            <span>{decision.status_label}</span>
                          </div>
                          <p>{decision.scenario}</p>
                          <div className="de-approval-summary-grid">
                            <span className={`de-badge ${badgeClass(approvalRiskTone(decision.risk_level))}`}>
                              {approvalRiskLabel(decision.risk_level)}
                            </span>
                            <span className={`de-badge ${badgeClass(approvalSlaTone(decision.sla_status))}`}>
                              {approvalSlaLabel(decision.sla_status)}
                            </span>
                            <span>{decision.due_at ? `截止 ${formatBeijingDateTime(decision.due_at) || decision.due_at}` : '未设置截止'}</span>
                            <span>{decision.comment_count ? `评论 ${decision.comment_count} 条` : '暂无评论'}</span>
                            <span>{decision.delegate_to ? `转交 ${decision.delegate_to}` : '未转交'}</span>
                            <span>{decision.last_action ? `最近 ${approvalActionLabel(decision.last_action)} · ${decision.last_actor || '未知'}` : '暂无审批动作'}</span>
                          </div>
                          <div className="de-approval-action-fields">
                            <input
                              value={draft.comment}
                              placeholder="评论 / 风险原因"
                              onChange={(event) => updateApprovalActionDraft(decision.id, { comment: event.target.value })}
                            />
                            <input
                              value={draft.delegateTo}
                              placeholder="转交对象"
                              onChange={(event) => updateApprovalActionDraft(decision.id, { delegateTo: event.target.value })}
                            />
                            <input
                              type="datetime-local"
                              value={draft.dueAt}
                              onChange={(event) => updateApprovalActionDraft(decision.id, { dueAt: event.target.value })}
                            />
                          </div>
                          <div className="de-workbench-actions de-approval-governance-actions">
                            <button
                              type="button"
                              title="记录审批评论"
                              disabled={commentBusy}
                              onClick={() => { void submitApprovalAction(decision, 'comment'); }}
                            >
                              <MessageSquare size={13} />
                              <span>{commentBusy ? '记录中...' : '评论'}</span>
                            </button>
                            <button
                              type="button"
                              title="转交审批"
                              disabled={delegateBusy}
                              onClick={() => { void submitApprovalAction(decision, 'delegate'); }}
                            >
                              <UserRoundPlus size={13} />
                              <span>{delegateBusy ? '转交中...' : '转交'}</span>
                            </button>
                            <button
                              type="button"
                              title="标记 SLA 超时"
                              disabled={timeoutBusy}
                              onClick={() => { void submitApprovalAction(decision, 'mark_timeout'); }}
                            >
                              <TimerReset size={13} />
                              <span>{timeoutBusy ? '标记中...' : '超时'}</span>
                            </button>
                            <button
                              type="button"
                              title="标记审批风险"
                              disabled={markRiskBusy}
                              onClick={() => { void submitApprovalAction(decision, 'mark_risk'); }}
                            >
                              <ShieldAlert size={13} />
                              <span>{markRiskBusy ? '标记中...' : '风险'}</span>
                            </button>
                            <button
                              type="button"
                              title="清除审批风险"
                              disabled={clearRiskBusy}
                              onClick={() => { void submitApprovalAction(decision, 'clear_risk'); }}
                            >
                              <ShieldCheck size={13} />
                              <span>{clearRiskBusy ? '清除中...' : '清除'}</span>
                            </button>
                          </div>
                          <div className="de-decision-chain-note">
                            <span className="de-badge de-badge-success">本地记录</span>
                            <span>{isDecisionOpen(decision.status) ? '处理结果会写入 qimingclaw runtime event。' : '该事项已在本地状态中处理。'}</span>
                          </div>
                          <div className="de-workbench-actions">
                            {decision.actions.map((action) => (
                              <button
                                key={action.id}
                                type="button"
                                className={action.tone === 'primary' ? 'de-workbench-action-accent' : ''}
                                disabled={actionBusy === `${decision.id}:${action.id}` || !isDecisionOpen(decision.status)}
                                onClick={() => { void resolveDecision(decision, action.id); }}
                              >
                                {actionBusy === `${decision.id}:${action.id}` ? '处理中...' : action.label}
                              </button>
                            ))}
                            <button type="button" onClick={() => onNavigate({ tab: 'missions', date: selectedDate, missionId: decision.id })}>
                              查看上下文
                            </button>
                          </div>
                        </div>
                      );
                    })
                  )}
                </div>
              </aside>
            </div>
          </div>
        </div>
      )}

    </div>
  );
}
