import {
  AlertTriangle,
  Bot,
  CalendarClock,
  CheckCircle2,
  ClipboardCheck,
  ClipboardList,
  Clock3,
  FileText,
  Lightbulb,
  ListChecks,
  Loader2,
  MessageSquare,
  Route,
  Send,
  ShieldAlert,
  Wrench
} from "lucide-react";
import { AnimatePresence, motion } from "motion/react";
import { useEffect, useState } from "react";
import { cn } from "@/shared/ui/cn";
import {
  StatusBadge,
  StatusIcon as SemanticStatusIcon,
  type StatusTone
} from "@/shared/ui/status";
import { showMapNotice } from "@/features/map/core";
import {
  getRunningWorkflowDefinition,
  getRunningWorkflowState,
  getWorkflowStepStatus
} from "../data/running-workflows";
import type {
  ScheduledConditionAnalysisInsight,
  ScheduledConditionItem,
  ScheduledConditionKpi,
  ScheduledConditionRecord,
  ScheduledConditionRiskLevel,
  ScheduledWorkOrderItem
} from "../types";
import {
  formatDuration,
  formatTime,
  formatTimeRange,
  getStatusActivity,
  getStatusTone,
  getRiskLabel,
  getWorkOrderCurrentStage,
  getWorkOrderStageActivity,
  getWorkOrderStageTone,
  statusLabels
} from "./scheduled-condition-feed-utils";
import { getConditionReportRiskLevel } from "./condition-report-risk";

const RUNNING_WORKFLOW_TICK_MS = 1_000;
const NEUTRAL_SURFACE_CLASS_NAME = "surface-reading rounded-xl border border-slate-200/70";
const INSET_SURFACE_CLASS_NAME = "surface-control rounded-xl border border-slate-200/70";
const REPORT_META_TILE_CLASS_NAME = "surface-control rounded-lg border border-slate-200/70 px-2 py-1.5";

const riskTones = {
  normal: "success",
  attention: "warning",
  critical: "danger"
} satisfies Record<ScheduledConditionRiskLevel, StatusTone>;

type IncidentOperation = {
  target: string;
  elementType: string;
  action: string;
  command: string;
  verification: string;
};

type SubmittedIncidentWorkOrder = {
  code: string;
  submittedAt: number;
  notifiedTeams: string[];
  operations: IncidentOperation[];
};

type ExecutionStepStatus = "done" | "current" | "pending" | "confirmation";

type ExecutionBadgeTone = "active" | "confirmation" | "completed" | "pending";

type ExecutionStepMeta = {
  label: string;
  value: string;
};

type ExecutionStep = {
  id: string;
  title: string;
  description: string;
  status: ExecutionStepStatus;
  statusLabel?: string;
  meta?: ExecutionStepMeta[];
};

type ConditionDetailPanelProps = {
  condition: ScheduledConditionItem;
  onContinueConversation: () => void;
};

export function StatusPill({
  condition,
  className
}: {
  condition: ScheduledConditionItem;
  className?: string;
}) {
  const isWorkOrder = condition.kind === "work_order";
  const currentStage = isWorkOrder ? getWorkOrderCurrentStage(condition) : null;

  return (
    <StatusBadge
      tone={
        isWorkOrder
          ? getWorkOrderStageTone(currentStage?.id)
          : getStatusTone(condition.status)
      }
      activity={
        isWorkOrder
          ? getWorkOrderStageActivity(currentStage?.id)
          : getStatusActivity(condition.status)
      }
      className={className}
    >
      {isWorkOrder ? currentStage?.title ?? "工单" : statusLabels[condition.status]}
    </StatusBadge>
  );
}

export function ConditionDetailPanel({ condition, onContinueConversation }: ConditionDetailPanelProps) {
  const detailKey =
    condition.kind === "work_order"
      ? `${condition.id}-${getWorkOrderCurrentStage(condition)?.id ?? condition.status}`
      : condition.id;
  const content =
    condition.kind === "work_order" ? (
      <WorkOrderDetailPanel condition={condition} />
    ) : (
      <ConditionRecordDetailPanel condition={condition} onContinueConversation={onContinueConversation} />
    );

  return (
    <AnimatePresence initial={false} mode="wait">
      <motion.div
        key={detailKey}
        className="relative h-full min-h-0"
        initial={{ opacity: 0, y: 8 }}
        animate={{ opacity: 1, y: 0 }}
        exit={{ opacity: 0, y: -6 }}
        transition={{ duration: 0.22, ease: [0.22, 1, 0.36, 1] }}
      >
        {content}
      </motion.div>
    </AnimatePresence>
  );
}

function ConditionRecordDetailPanel({
  condition,
  onContinueConversation
}: {
  condition: ScheduledConditionRecord;
  onContinueConversation: () => void;
}) {
  const insight = getConditionAnalysisInsight(condition);
  const [submittedWorkOrder, setSubmittedWorkOrder] = useState<SubmittedIncidentWorkOrder | null>(null);
  const header = getConditionDetailHeader(condition);
  const riskLevel = getConditionReportRiskLevel(condition.status, condition.riskLevel);
  const bodyKey = `${condition.id}-${condition.status}-${condition.riskLevel}`;

  function handleSubmitIncidentWorkOrder() {
    const nextWorkOrder = createSubmittedIncidentWorkOrder(condition);
    setSubmittedWorkOrder(nextWorkOrder);
    showMapNotice({
      id: `incident-work-order-${condition.id}`,
      tone: "success",
      title: "系统工单已提交",
      message: `${nextWorkOrder.code} 已通知 ${nextWorkOrder.notifiedTeams.join("、")}。`
    });
  }

  return (
    <DetailScroll>
      <DetailShell>
        <DetailHeader
          condition={condition}
          icon={header.icon}
          iconClassName={header.iconClassName}
          iconSpin={header.iconSpin}
        />
        <DetailDecisionBody>
          <AnimatePresence initial={false} mode="wait">
            <motion.div
              key={bodyKey}
              className="space-y-2.5"
              initial={{ opacity: 0, y: 10, scale: 0.992 }}
              animate={{ opacity: 1, y: 0, scale: 1 }}
              exit={{ opacity: 0, y: -8, scale: 0.996 }}
              transition={{ duration: 0.26, ease: [0.22, 1, 0.36, 1] }}
            >
              {condition.status === "running" ? (
                <RunningConditionBody condition={condition} />
              ) : (
                <>
                  <ConditionStatusReport condition={condition} riskLevel={riskLevel} />
                  {riskLevel === "critical" ? (
                    <>
                      <DecisionSummaryBlock
                        icon={ShieldAlert}
                        title="异常判断"
                        iconClassName="status-tone-danger text-[var(--status-foreground)]"
                        summary={insight.summary}
                        notes={insight.notes}
                      />
                      <SolutionOptionsList options={insight.solutionOptions ?? []} />
                      <IncidentWorkOrderPanel
                        condition={condition}
                        submittedWorkOrder={submittedWorkOrder}
                        onSubmitWorkOrder={handleSubmitIncidentWorkOrder}
                      />
                      <DecisionActionStrip
                        icon={Bot}
                        title="Agent 继续分析"
                        value={condition.recommendation ?? "建议打开 Agent 会话，结合异常证据继续判断处置优先级。"}
                        actionLabel="继续分析"
                        onAction={onContinueConversation}
                      />
                    </>
                  ) : riskLevel === "attention" ? (
                    <>
                      <DecisionSummaryBlock
                        icon={Lightbulb}
                        title="关注说明"
                        iconClassName="status-tone-warning text-[var(--status-foreground)]"
                        summary={insight.summary}
                        notes={insight.notes}
                      />
                      <EscalationCriteriaList items={insight.escalationCriteria ?? []} />
                      <DecisionActionStrip
                        icon={Bot}
                        title="复核建议"
                        value={condition.recommendation ?? "建议保留为关注项，下一轮工况继续复核同一测点趋势。"}
                        actionLabel="继续对话"
                        onAction={onContinueConversation}
                      />
                    </>
                  ) : (
                    <>
                      <EvidenceList items={condition.evidence ?? []} />
                      <DecisionActionStrip
                        icon={Bot}
                        title="Agent 建议"
                        value={condition.recommendation ?? "当前工况暂无新增处置建议，保持观察即可。"}
                        actionLabel="继续对话"
                        onAction={onContinueConversation}
                      />
                    </>
                  )}
                </>
              )}
            </motion.div>
          </AnimatePresence>
        </DetailDecisionBody>
      </DetailShell>
    </DetailScroll>
  );
}

function WorkOrderDetailPanel({ condition }: { condition: ScheduledWorkOrderItem }) {
  const currentStage = getWorkOrderCurrentStage(condition);

  return (
    <DetailScroll>
      <DetailShell>
        <DetailHeader
          condition={condition}
          icon={ClipboardList}
          iconClassName="bg-blue-50 text-blue-700"
        />
        <DetailDecisionBody>
          <WorkOrderLifecyclePanel condition={condition} />
          <WorkOrderReplyRequirements condition={condition} />
          <DecisionActionStrip
            icon={CalendarClock}
            title={currentStage ? `当前阶段：${currentStage.title}` : "工单流转"}
            value={condition.recommendation ?? "按派发、执行、复令三阶段跟踪现场处置闭环。"}
            actionLabel={currentStage?.id === "reply" ? "待复令" : "跟踪工单"}
            actionDisabled
            actionTitle="工单流程由调度和现场班组流转"
          />
        </DetailDecisionBody>
      </DetailShell>
    </DetailScroll>
  );
}

function RunningConditionBody({ condition }: { condition: ScheduledConditionRecord }) {
  const runningEvidence = (condition.evidence ?? []).slice(0, 2);
  const [nowMs, setNowMs] = useState(() => Date.now());

  useEffect(() => {
    setNowMs(Date.now());
    const interval = window.setInterval(() => {
      setNowMs(Date.now());
    }, RUNNING_WORKFLOW_TICK_MS);

    return () => window.clearInterval(interval);
  }, [condition.id]);

  return (
    <>
      <RunningWorkflowPanel condition={condition} nowMs={nowMs} />
      <RunningEvidencePreview items={runningEvidence} />
      <DecisionActionStrip
        icon={Bot}
        title="阶段判断"
        value={condition.recommendation ?? "等待本轮工况完成后再确认是否生成处置建议。"}
        actionLabel="等待完成"
        actionDisabled
        actionTitle="任务执行中，完成后可继续对话"
      />
    </>
  );
}

function getConditionDetailHeader(condition: ScheduledConditionRecord) {
  if (condition.status === "running") {
    return {
      icon: Loader2,
      iconClassName: "bg-blue-600 text-white",
      iconSpin: true
    };
  }

  return {
    icon: FileText,
    iconClassName: undefined,
    iconSpin: false
  };
}

function DetailScroll({ children }: { children: React.ReactNode }) {
  return (
    <section
      className={cn(
        NEUTRAL_SURFACE_CLASS_NAME,
        "scheduled-feed-detail-viewport absolute inset-0 overflow-hidden"
      )}
    >
      <div
        data-testid="scheduled-condition-detail-scroll"
        className="scheduled-feed-scroll absolute inset-x-0 inset-y-2 overflow-y-auto pb-4 pl-0.5 pr-2 pt-0.5"
      >
        {children}
      </div>
    </section>
  );
}

type DetailShellProps = {
  children: React.ReactNode;
};

function DetailShell({ children }: DetailShellProps) {
  return (
    <div className="overflow-hidden">{children}</div>
  );
}

type DetailHeaderProps = {
  condition: ScheduledConditionItem;
  icon: typeof FileText;
  iconClassName?: string;
  iconSpin?: boolean;
};

function DetailHeader({
  condition,
  icon: Icon,
  iconClassName,
  iconSpin = false
}: DetailHeaderProps) {
  return (
    <div className="px-3 py-3">
      <div className="grid gap-3 2xl:grid-cols-[minmax(0,1fr)_220px]">
        <div className="flex min-w-0 items-start gap-2.5">
          <span
            className={cn(
              "grid h-9 w-9 shrink-0 place-items-center bg-slate-100 text-slate-600",
              "rounded-lg",
              iconClassName
            )}
          >
            <Icon size={16} aria-hidden="true" className={iconSpin ? "animate-spin" : undefined} />
          </span>
          <div className="min-w-0 flex-1">
            <div className="flex flex-wrap items-center gap-2">
              <span className="font-mono text-xs font-semibold text-slate-500">{formatTime(condition.scheduledAt)}</span>
              {condition.kind === "work_order" || condition.status === "running" || condition.status === "pending" ? (
                <StatusPill condition={condition} />
              ) : null}
            </div>
            <h3 className="mt-1 text-base font-semibold leading-5 text-slate-950">{condition.title}</h3>
            {condition.detail ? <p className="mt-1.5 text-xs leading-5 text-slate-700">{condition.detail}</p> : null}
          </div>
        </div>

        <DetailMetricGrid condition={condition} />
      </div>
    </div>
  );
}

function DetailDecisionBody({ children }: { children: React.ReactNode }) {
  return (
    <div className="space-y-2.5 px-3 pb-3">
      {children}
    </div>
  );
}

function DecisionSummaryBlock({
  icon: Icon,
  title,
  iconClassName,
  summary,
  notes
}: {
  icon: typeof Bot;
  title: string;
  iconClassName: string;
  summary: string;
  notes: string[];
}) {
  return (
    <section className={cn(NEUTRAL_SURFACE_CLASS_NAME, "px-3 py-3")}>
      <SectionTitle icon={Icon} title={title} iconClassName={iconClassName} />
      <p className="mt-2 text-xs leading-5 text-slate-700">{summary}</p>
      <ul className="mt-2 grid gap-1.5">
        {notes.map((note) => (
          <li key={note} className="grid grid-cols-[7px_1fr] gap-2 text-xs leading-5 text-slate-700">
            <span className="mt-2 h-1.5 w-1.5 rounded-full bg-slate-300" aria-hidden="true" />
            <span>{note}</span>
          </li>
        ))}
      </ul>
    </section>
  );
}

function SolutionOptionsList({
  options
}: {
  options: NonNullable<ScheduledConditionAnalysisInsight["solutionOptions"]>;
}) {
  return (
    <section className={cn(NEUTRAL_SURFACE_CLASS_NAME, "px-3 py-3")}>
      <SectionEyebrow icon={Route} label="处置方案" />
      <div className={cn(INSET_SURFACE_CLASS_NAME, "mt-2 divide-y divide-slate-200/70 overflow-hidden")}>
        {options.map((option, index) => (
          <article key={option.id} className="px-2.5 py-2">
            <div className="flex items-center gap-2">
              <span className="surface-reading grid h-5 w-5 shrink-0 place-items-center rounded-lg border border-slate-200/70 text-xs font-semibold text-slate-600">
                {index + 1}
              </span>
              <h4 className="min-w-0 truncate text-xs font-semibold leading-4 text-slate-900">{option.title}</h4>
            </div>
            <dl className="mt-2 grid gap-1.5 text-xs leading-5">
              <div className="grid grid-cols-[56px_1fr] gap-2">
                <dt className="font-semibold text-slate-400">适用</dt>
                <dd className="text-slate-700">{option.scenario}</dd>
              </div>
              <div className="grid grid-cols-[56px_1fr] gap-2">
                <dt className="font-semibold text-slate-400">动作</dt>
                <dd className="text-slate-700">{option.action}</dd>
              </div>
              <div className="grid grid-cols-[56px_1fr] gap-2">
                <dt className="font-semibold text-slate-400">代价</dt>
                <dd className="text-slate-700">{option.tradeoff}</dd>
              </div>
            </dl>
          </article>
        ))}
      </div>
    </section>
  );
}

function IncidentWorkOrderPanel({
  condition,
  submittedWorkOrder,
  onSubmitWorkOrder
}: {
  condition: ScheduledConditionItem;
  submittedWorkOrder: SubmittedIncidentWorkOrder | null;
  onSubmitWorkOrder: () => void;
}) {
  const operations = submittedWorkOrder?.operations ?? createIncidentOperations(condition);
  const submitted = Boolean(submittedWorkOrder);
  const steps: ExecutionStep[] = [
    { id: "analysis", title: "事件分析", status: "done", description: "汇总异常证据、影响分区和风险等级。" },
    { id: "solution", title: "形成方案", status: "done", description: "生成阀门、泵站和现场复核操作清单。" },
    { id: "confirm", title: "人工确认", status: submitted ? "done" : "confirmation", description: "调度员确认影响范围和操作边界。" },
    { id: "submit", title: "提交工单", status: submitted ? "done" : "pending", description: "写入系统工单并通知执行岗位。" }
  ];

  return (
    <TaskExecutionPanel
      icon={ClipboardCheck}
      title="任务执行"
      badge={submitted ? "已提交" : "待人工确认"}
      badgeTone={submitted ? "completed" : "confirmation"}
      summary={
        submitted
          ? `${submittedWorkOrder?.code} 已进入系统工单流转，并通知相关班组执行管网要素操作。`
          : "异常分析形成处置方案后，由调度员确认并提交系统工单，通知现场或调度岗位操作阀门、泵站和相关测点。"
      }
      meta={
        submittedWorkOrder
          ? [
              { label: "系统工单", value: submittedWorkOrder.code },
              { label: "通知对象", value: submittedWorkOrder.notifiedTeams.join("、") }
            ]
          : [
              { label: "来源", value: condition.title },
              { label: "状态", value: "待人工确认" },
              { label: "风险等级", value: getRiskLabel(condition.riskLevel) }
            ]
      }
      steps={steps}
    >
        <IncidentOperationList operations={operations} submitted={submitted} />
        <button
          type="button"
          disabled={submitted}
          aria-disabled={submitted}
          onClick={onSubmitWorkOrder}
          className={cn(
            "mt-1 flex min-h-9 w-full items-center justify-center gap-1.5 px-3 text-xs font-semibold leading-4 transition-colors",
            "rounded-xl",
            submitted
              ? "status-tone-success cursor-not-allowed bg-[var(--status-soft)] text-[var(--status-foreground)]"
              : "bg-blue-600 text-white hover:bg-blue-700"
          )}
        >
          {submitted ? <CheckCircle2 size={14} aria-hidden="true" /> : <Send size={14} aria-hidden="true" />}
          <span>{submitted ? "工单已提交" : "人工确认并提交工单"}</span>
        </button>
    </TaskExecutionPanel>
  );
}

function IncidentOperationList({
  operations,
  submitted
}: {
  operations: IncidentOperation[];
  submitted: boolean;
}) {
  return (
    <div className={cn(INSET_SURFACE_CLASS_NAME, "divide-y divide-slate-200/70 overflow-hidden")}>
      {operations.map((operation) => (
        <article key={`${operation.target}-${operation.action}`} className="px-2.5 py-2">
          <div className="flex flex-wrap items-center justify-between gap-2">
            <SectionEyebrow icon={Wrench} label={operation.action} />
            <StatusBadge tone={submitted ? "success" : "neutral"}>
              {submitted ? "已通知" : operation.elementType}
            </StatusBadge>
          </div>
          <dl className="mt-1.5 grid gap-1 text-xs leading-5">
            <div className="grid grid-cols-[56px_1fr] gap-2">
              <dt className="font-semibold text-slate-400">对象</dt>
              <dd className="text-slate-700">{operation.target}</dd>
            </div>
            <div className="grid grid-cols-[56px_1fr] gap-2">
              <dt className="font-semibold text-slate-400">指令</dt>
              <dd className="text-slate-700">{operation.command}</dd>
            </div>
            <div className="grid grid-cols-[56px_1fr] gap-2">
              <dt className="font-semibold text-slate-400">复核</dt>
              <dd className="text-slate-700">{operation.verification}</dd>
            </div>
          </dl>
        </article>
      ))}
    </div>
  );
}

function EscalationCriteriaList({ items }: { items: string[] }) {
  return (
    <section className={cn(NEUTRAL_SURFACE_CLASS_NAME, "px-3 py-3")}>
      <SectionEyebrow icon={AlertTriangle} label="升级条件" />
      <ol className={cn(INSET_SURFACE_CLASS_NAME, "mt-2 divide-y divide-slate-200/70 overflow-hidden")}>
        {items.map((item, index) => (
          <li key={item} className="grid grid-cols-[18px_1fr] gap-2 px-2 py-1.5 text-xs leading-5 text-slate-700">
            <span className="surface-reading mt-0.5 grid h-[18px] w-[18px] place-items-center rounded-lg border border-slate-200/70 text-xs font-semibold text-slate-600">
              {index + 1}
            </span>
            <span>{item}</span>
          </li>
        ))}
      </ol>
    </section>
  );
}

function ConditionStatusReport({
  condition,
  riskLevel
}: {
  condition: ScheduledConditionRecord;
  riskLevel: ScheduledConditionRiskLevel;
}) {
  if (!condition.report && !condition.kpis?.length) {
    return null;
  }

  const report = condition.report;
  const kpis = condition.kpis ?? [];
  const statusTime = formatTimeRange(condition.scheduledAt, condition.durationMinutes);

  return (
    <section className={cn(NEUTRAL_SURFACE_CLASS_NAME, "overflow-hidden")}>
      <div className="border-b border-slate-200/70 px-3 py-3">
        <div className="flex flex-wrap items-center justify-between gap-2">
          <SectionTitle icon={FileText} title="完成状态报告" />
          <LifecyclePill />
        </div>
        <h4 className="mt-2 min-w-0 text-sm font-semibold leading-5 text-slate-950">{report?.title ?? condition.title}</h4>
        {report?.conclusion ? (
          <div className="mt-1.5 flex min-w-0 flex-wrap items-start gap-2">
            <p className="min-w-[12rem] flex-1 text-xs leading-5 text-slate-700">{report.conclusion}</p>
            <RiskBadge riskLevel={riskLevel} />
          </div>
        ) : null}
        <div className="mt-2 flex items-center gap-1.5 text-xs leading-5 text-slate-500">
          <Clock3 size={13} aria-hidden="true" />
          <span>报告时段</span>
          <span className="font-mono font-semibold tabular-nums text-slate-700">{statusTime}</span>
        </div>
      </div>

      {kpis.length > 0 ? (
        <div className="px-3 py-3">
          <SectionEyebrow icon={ListChecks} label="关键指标" />
          <div className="mt-2 grid gap-2 sm:grid-cols-2">
            {kpis.map((kpi) => (
              <KpiTile key={kpi.id} kpi={kpi} />
            ))}
          </div>
        </div>
      ) : null}

      {report?.sections?.length ? (
        <div className="grid gap-2 border-t border-slate-200/70 px-3 py-3">
          {report.sections.map((section) => (
            <ReportSection key={section.title} title={section.title} items={section.items} />
          ))}
        </div>
      ) : null}
    </section>
  );
}

function LifecyclePill() {
  return (
    <StatusBadge tone="success" icon={<CheckCircle2 size={12} />}>
      完成
    </StatusBadge>
  );
}

function RiskBadge({ riskLevel }: { riskLevel: ScheduledConditionRiskLevel }) {
  const Icon = riskLevel === "critical" ? ShieldAlert : riskLevel === "attention" ? AlertTriangle : CheckCircle2;
  const label = getRiskLabel(riskLevel);

  return (
    <StatusBadge
      tone={riskTones[riskLevel]}
      icon={<Icon size={12} />}
      aria-label={`风险等级：${label}`}
    >
      {label}
    </StatusBadge>
  );
}

function ReportMetaTile({ label, value }: { label: string; value: string }) {
  return (
    <div className={REPORT_META_TILE_CLASS_NAME}>
      <div className="text-xs font-semibold text-slate-400">{label}</div>
      <div className="mt-0.5 truncate text-xs font-semibold text-slate-700" title={value}>
        {value}
      </div>
    </div>
  );
}

function ReportSection({
  title,
  items
}: {
  title: string;
  items: string[];
}) {
  return (
    <section className={cn(INSET_SURFACE_CLASS_NAME, "px-2.5 py-2")}>
      <div className="text-xs font-semibold text-slate-500">{title}</div>
      <ul className="mt-1.5 grid gap-1">
        {items.map((item) => (
          <li key={item} className="grid grid-cols-[7px_1fr] gap-2 text-xs leading-5 text-slate-700">
            <span className="mt-2 h-1.5 w-1.5 rounded-full bg-slate-300" aria-hidden="true" />
            <span>{item}</span>
          </li>
        ))}
      </ul>
    </section>
  );
}

function KpiTile({ kpi }: { kpi: ScheduledConditionKpi }) {
  return (
    <div className="surface-reading min-w-0 rounded-xl border border-slate-200/70 px-2.5 py-2">
      <div className="flex items-start justify-between gap-2">
        <div className="min-w-0">
          <div className="truncate text-xs font-semibold text-slate-500" title={kpi.label}>
            {kpi.label}
          </div>
          <div className="mt-1 flex items-baseline gap-1">
            <span className="font-mono text-lg font-semibold leading-5 text-slate-900">{kpi.value}</span>
            {kpi.unit ? <span className="text-xs font-semibold text-slate-500">{kpi.unit}</span> : null}
          </div>
        </div>
        <StatusBadge tone={riskTones[kpi.status]}>
          {getRiskLabel(kpi.status)}
        </StatusBadge>
      </div>
      <p className="mt-1.5 text-xs leading-4 text-slate-600">{kpi.description}</p>
      {kpi.threshold || kpi.baseline ? (
        <div className="mt-1.5 space-y-0.5 text-xs leading-4 text-slate-500">
          {kpi.threshold ? <div>阈值：{kpi.threshold}</div> : null}
          {kpi.baseline ? <div>基线：{kpi.baseline}</div> : null}
        </div>
      ) : null}
    </div>
  );
}

function DecisionActionStrip({
  icon: Icon,
  title,
  value,
  actionLabel,
  actionDisabled = false,
  actionTitle,
  onAction
}: {
  icon: typeof Bot;
  title: string;
  value: string;
  actionLabel: string;
  actionDisabled?: boolean;
  actionTitle?: string;
  onAction?: () => void;
}) {
  return (
    <div className={cn(NEUTRAL_SURFACE_CLASS_NAME, "flex flex-col gap-2 px-3 py-3 min-[1500px]:flex-row min-[1500px]:items-center")}>
      <div className="min-w-0 flex-1">
        <SectionEyebrow icon={Icon} label={title} />
        <p className="mt-1 text-xs leading-5 text-slate-700">{value}</p>
      </div>
      <button
        type="button"
        disabled={actionDisabled}
        aria-disabled={actionDisabled}
        title={actionTitle}
        onClick={onAction}
        className={cn(
          "flex min-h-9 shrink-0 items-center justify-center gap-1.5 px-3 text-xs font-semibold leading-4 transition-colors min-[1500px]:w-[104px]",
          "rounded-xl",
          actionDisabled
            ? "surface-control cursor-not-allowed border border-slate-200/70 text-slate-500 opacity-80"
            : "bg-blue-600 text-white hover:bg-blue-700"
        )}
      >
        <MessageSquare size={14} aria-hidden="true" />
        <span>{actionLabel}</span>
      </button>
    </div>
  );
}

function SectionEyebrow({
  icon: Icon,
  label
}: {
  icon?: typeof Bot;
  label: string;
}) {
  return (
    <div className="flex items-center gap-1.5 text-xs font-semibold text-slate-500">
      {Icon ? <Icon size={13} aria-hidden="true" /> : null}
      <span>{label}</span>
    </div>
  );
}

function getTaskExecutionBadgeTone(tone: ExecutionBadgeTone): StatusTone {
  if (tone === "completed") {
    return "success";
  }

  if (tone === "confirmation") {
    return "warning";
  }

  if (tone === "active") {
    return "info";
  }

  return "neutral";
}

function getTaskExecutionStepTone(status: ExecutionStepStatus): StatusTone {
  if (status === "done") {
    return "success";
  }

  if (status === "current") {
    return "info";
  }

  if (status === "confirmation") {
    return "warning";
  }

  return "neutral";
}

function getTaskExecutionStepStatusLabel(status: ExecutionStepStatus) {
  if (status === "done") {
    return "已完成";
  }

  if (status === "current") {
    return "当前";
  }

  if (status === "confirmation") {
    return "待人工确认";
  }

  return "待处理";
}

function DetailMetricGrid({ condition }: { condition: ScheduledConditionItem }) {
  const durationLabel = condition.status === "running" ? "状态" : "耗时";
  const durationValue = condition.status === "running" ? "实时执行" : formatDuration(condition.durationMinutes, condition.status);
  const metrics =
    condition.kind === "condition"
      ? [
          { label: "模型", value: condition.modelName ?? "未记录" },
          { label: "会话", value: condition.sessionId ?? "未记录" },
          { label: durationLabel, value: durationValue, className: "col-span-2" }
        ]
      : [
          { label: "类型", value: "预约工单" },
          { label: "窗口", value: formatTimeRange(condition.scheduledAt, condition.durationMinutes) },
          { label: "风险", value: getRiskLabel(condition.riskLevel) },
          { label: durationLabel, value: durationValue }
        ];

  return (
    <div className="grid min-w-0 grid-cols-2 gap-1.5">
      {metrics.map((metric) => (
        <div key={metric.label} className={metric.className}>
          <ReportMetaTile label={metric.label} value={metric.value} />
        </div>
      ))}
    </div>
  );
}

function RunningWorkflowPanel({
  condition,
  nowMs
}: {
  condition: ScheduledConditionRecord;
  nowMs: number;
}) {
  const workflow = getRunningWorkflowDefinition(condition);
  const workflowState = getRunningWorkflowState(condition, workflow, nowMs);
  const currentStepIndex = workflowState.currentStepIndex;
  const currentStep = workflow.steps[currentStepIndex] ?? workflow.steps[0];
  const nextStep = workflow.steps[currentStepIndex + 1];
  const steps: ExecutionStep[] = workflow.steps.map((step, index) => ({
    id: step.id,
    title: step.title,
    description: step.detail,
    status: getWorkflowStepStatus(condition, index, currentStepIndex)
  }));

  return (
    <TaskExecutionPanel
      title={workflow.title}
      badge="执行中"
      badgeTone="active"
      summary={`${currentStep.title}：${currentStep.detail}`}
      meta={[
        { label: "任务对象", value: condition.title },
        { label: "当前进度", value: `${workflowState.progress}%` },
        { label: "下一步", value: nextStep?.title ?? workflow.reportLabel }
      ]}
      steps={steps}
    />
  );
}

function SectionTitle({
  icon: Icon,
  title,
  iconClassName
}: {
  icon: typeof Bot;
  title: string;
  iconClassName?: string;
}) {
  return (
    <div className="flex items-center gap-1.5 text-xs font-semibold">
      <Icon size={13} aria-hidden="true" className={iconClassName} />
      <span>{title}</span>
    </div>
  );
}

function DetailSectionCard({
  children,
  className
}: {
  children: React.ReactNode;
  className?: string;
}) {
  return (
    <div className={cn("surface-reading rounded-xl border border-slate-200/70 px-2.5 py-2.5 text-slate-500", className)}>
      {children}
    </div>
  );
}

function TaskExecutionPanel({
  icon: Icon,
  title,
  badge,
  summary,
  meta,
  steps,
  badgeTone = "pending",
  children
}: {
  icon?: typeof Bot;
  title: string;
  badge: string;
  summary?: string;
  meta?: ExecutionStepMeta[];
  steps: ExecutionStep[];
  badgeTone?: ExecutionBadgeTone;
  children?: React.ReactNode;
}) {
  return (
    <section className={cn(NEUTRAL_SURFACE_CLASS_NAME, "overflow-hidden")}>
      <div className="border-b border-slate-200/70 px-3 py-3">
        <div className="flex flex-wrap items-center justify-between gap-2">
          {Icon ? (
            <SectionTitle icon={Icon} title={title} />
          ) : (
            <span className="text-xs font-semibold">{title}</span>
          )}
          <StatusBadge
            tone={getTaskExecutionBadgeTone(badgeTone)}
            activity={badgeTone === "active" ? "live" : "static"}
          >
            {badge}
          </StatusBadge>
        </div>
        {summary ? <p className="mt-2 text-xs leading-5 text-slate-700">{summary}</p> : null}
        {meta?.length ? (
          <div className="mt-2 grid gap-1.5 sm:grid-cols-3">
            {meta.map((item) => (
              <ReportMetaTile key={`${item.label}-${item.value}`} label={item.label} value={item.value} />
            ))}
          </div>
        ) : null}
      </div>

      <ol className="grid gap-2 px-3 py-3">
        {steps.map((step, index) => (
          <TaskExecutionStepRow
            key={step.id}
            step={step}
            isLast={index === steps.length - 1}
          />
        ))}
      </ol>
      {children ? <div className="grid gap-2 border-t border-slate-200/70 px-3 py-3">{children}</div> : null}
    </section>
  );
}

function TaskExecutionStepRow({
  step,
  isLast
}: {
  step: ExecutionStep;
  isLast: boolean;
}) {
  return (
    <li className="grid grid-cols-[28px_1fr] gap-2">
      <span className="relative flex justify-center">
        {!isLast ? (
          <span className="absolute bottom-[-0.65rem] top-7 w-px bg-slate-200" aria-hidden="true" />
        ) : null}
        <SemanticStatusIcon
          tone={getTaskExecutionStepTone(step.status)}
          activity={step.status === "current" ? "loading" : "static"}
          shape="circle"
          size="md"
          className="relative z-10 ring-4 ring-white"
        >
          {step.status === "done" ? (
            <CheckCircle2 size={14} />
          ) : step.status === "current" ? (
            <Loader2 size={14} />
          ) : step.status === "confirmation" ? (
            <AlertTriangle size={14} />
          ) : (
            <Clock3 size={14} />
          )}
        </SemanticStatusIcon>
      </span>
      <span
        className="surface-reading min-w-0 rounded-xl border border-slate-200/70 px-2.5 py-2"
      >
        <span className="flex min-w-0 flex-wrap items-center justify-between gap-2">
          <span className="text-xs font-semibold text-slate-900">{step.title}</span>
          <StatusBadge tone={getTaskExecutionStepTone(step.status)}>
            {step.statusLabel ?? getTaskExecutionStepStatusLabel(step.status)}
          </StatusBadge>
        </span>
        {step.meta?.length ? (
          <span className="mt-1 grid gap-1 text-xs leading-4 text-slate-500 sm:grid-cols-[68px_1fr]">
            {step.meta.map((item) => (
              <span key={`${item.label}-${item.value}`} className="contents">
                <span className="font-semibold text-slate-400">{item.label}</span>
                <span className={item.label === "时间" ? "font-mono text-slate-700" : "text-slate-700"}>{item.value}</span>
              </span>
            ))}
          </span>
        ) : null}
        <span className="mt-1.5 block text-xs leading-5 text-slate-700">{step.description}</span>
      </span>
    </li>
  );
}

function WorkOrderLifecyclePanel({ condition }: { condition: ScheduledWorkOrderItem }) {
  const duration = formatDuration(condition.durationMinutes, condition.status);
  const currentStage = getWorkOrderCurrentStage(condition);
  const steps = condition.stages.map((stage) => {
    const awaitingReply = stage.id === "reply" && stage.status === "current";

    return {
      id: stage.id,
      title: stage.title,
      status: awaitingReply ? ("confirmation" as const) : stage.status,
      statusLabel: awaitingReply ? "待复令" : undefined,
      description: stage.description,
      meta: [
        { label: "责任人", value: stage.owner },
        { label: "时间", value: stage.timeLabel }
      ]
    };
  });

  return (
    <TaskExecutionPanel
      icon={ClipboardList}
      title="任务执行"
      badge={currentStage ? currentStage.title : condition.code}
      badgeTone={currentStage?.id === "reply" ? "confirmation" : currentStage?.id === "execution" ? "active" : "pending"}
      summary={condition.detail ?? condition.summary}
      meta={[
        { label: "来源", value: condition.source },
        { label: "位置", value: condition.location },
        { label: "派发人", value: condition.dispatcher },
        { label: "执行班组", value: condition.assignee },
        { label: "优先级", value: condition.priority === "urgent" ? "紧急" : "普通" },
        { label: "预计耗时", value: duration }
      ]}
      steps={steps}
    />
  );
}

function WorkOrderReplyRequirements({ condition }: { condition: ScheduledWorkOrderItem }) {
  return (
    <DetailSectionCard>
      <SectionTitle icon={ListChecks} title="复令要求" />
      <div className="mt-2 grid grid-cols-[72px_1fr] gap-2 text-xs leading-5">
        <span className="font-semibold text-slate-400">执行窗口</span>
        <span className="font-mono font-semibold text-slate-800">{formatTimeRange(condition.scheduledAt, condition.durationMinutes)}</span>
        <span className="font-semibold text-slate-400">复令时限</span>
        <span className="text-slate-700">执行完成后 {condition.replyWindowMinutes} 分钟内</span>
      </div>
      <ul className="mt-2 space-y-1.5">
        {condition.replyRequirements.map((item, index) => (
          <li key={item} className="grid grid-cols-[18px_1fr] gap-2 text-xs leading-5 text-slate-700">
            <span className="surface-reading mt-0.5 grid h-[18px] w-[18px] place-items-center rounded-lg border border-blue-100 text-xs font-semibold text-blue-700">
              {index + 1}
            </span>
            <span>{item}</span>
          </li>
        ))}
      </ul>
    </DetailSectionCard>
  );
}

function RunningEvidencePreview({ items }: { items: string[] }) {
  return (
    <DetailSectionCard>
      <SectionTitle icon={ListChecks} title="采集中证据" />
      <ol className="space-y-1.5">
        {items.length > 0 ? (
          items.map((item, index) => (
            <li key={item} className="grid grid-cols-[18px_1fr_auto] items-start gap-2 text-xs leading-5 text-slate-700">
              <span className="surface-reading mt-0.5 grid h-[18px] w-[18px] place-items-center rounded-lg border border-blue-100 text-xs font-semibold text-blue-700">
                {index + 1}
              </span>
              <span className="line-clamp-1">{item}</span>
              <span className="mt-0.5 rounded-full bg-blue-50 px-1.5 py-0.5 text-xs font-semibold leading-4 text-blue-700">采集中</span>
            </li>
          ))
        ) : (
          <li className="text-xs leading-5 text-slate-500">正在等待首批证据返回。</li>
        )}
      </ol>
    </DetailSectionCard>
  );
}

function EvidenceList({ items }: { items: string[] }) {
  return (
    <DetailSectionCard>
      <SectionTitle icon={ListChecks} title="关键证据" />
      <ol className="space-y-1.5">
        {items.length > 0 ? (
          items.map((item, index) => (
            <li key={item} className="grid grid-cols-[18px_1fr] gap-2 text-xs leading-5 text-slate-700">
              <span className="surface-reading mt-0.5 grid h-[18px] w-[18px] place-items-center rounded-lg border border-blue-100 text-xs font-semibold text-blue-700">
                {index + 1}
              </span>
              <span>{item}</span>
            </li>
          ))
        ) : (
          <li className="text-xs leading-5 text-slate-500">暂无关键证据记录。</li>
        )}
      </ol>
    </DetailSectionCard>
  );
}

function createSubmittedIncidentWorkOrder(condition: ScheduledConditionItem): SubmittedIncidentWorkOrder {
  const operations = createIncidentOperations(condition);
  const submittedAt = Date.now();
  const codeSeed = `${condition.id}-${submittedAt}`.replace(/[^a-zA-Z0-9]/g, "").slice(-8).toUpperCase();

  return {
    code: `INC-WO-${codeSeed}`,
    submittedAt,
    notifiedTeams: ["调度执行岗", "现场抢修班组", "模型复核岗"],
    operations
  };
}

function createIncidentOperations(condition: ScheduledConditionItem): IncidentOperation[] {
  const baseVerification =
    condition.status === "error" ? "执行后 5 分钟内复核压力、流量和影响用户反馈。" : "下一轮工况继续跟踪偏差是否回落。";

  if (condition.title.includes("智能调度")) {
    return [
      {
        target: "华山路沿线阀门组 VG-11",
        elementType: "阀门",
        action: "阀门开度调整",
        command: "按方案将边界阀门预置到 45% 开度，执行前确认上下游压力。",
        verification: "确认高区末端压力不低于 0.22MPa。"
      },
      {
        target: "北辰二级泵站 P-02",
        elementType: "泵站",
        action: "泵站出水复核",
        command: "保持当前泵组组合，复核出水压力和频率波动。",
        verification: baseVerification
      }
    ];
  }

  if (condition.title.includes("SCADA")) {
    return [
      {
        target: "SCADA 异常测点组",
        elementType: "测点",
        action: "异常测点隔离",
        command: "调度计算暂不采用异常测点，使用相邻测点插补边界。",
        verification: "数据维护岗确认通信链路恢复后再解除隔离。"
      },
      {
        target: "异常 DMA 现场巡检点",
        elementType: "巡检点",
        action: "现场复核",
        command: "通知巡检班组核对压力表、流量计和阀井状态。",
        verification: baseVerification
      }
    ];
  }

  return [
    {
      target: "疑似影响区上下游阀门",
      elementType: "阀门",
      action: "阀门边界确认",
      command: "核对阀门当前开度，暂不执行大范围关断，保留应急隔离方案。",
      verification: "确认影响区压力恢复趋势和用户侧反馈。"
    },
    {
      target: "关联泵站与分区边界",
      elementType: "泵站/边界",
      action: "调度边界复核",
      command: "使用最新泵站出水、阀门开度和 SCADA 流量刷新模拟边界。",
      verification: baseVerification
    }
  ];
}

function getConditionAnalysisInsight(condition: ScheduledConditionItem): ScheduledConditionAnalysisInsight {
  if (condition.kind === "condition" && condition.analysisInsight) {
    return condition.analysisInsight;
  }

  if (condition.status === "error") {
    return {
      summary: "Agent 判断这条工况未完整闭环，需要先确认异常来源，再决定是否进入调度处置。",
      notes: [
        "优先核对遥测源新鲜度和关键测点完整率。",
        "结合历史基线复核压力/流量偏差是否持续。",
        "处置前应先确认影响范围，避免误触发联动动作。"
      ],
      solutionOptions: [
        {
          id: "fallback-source",
          title: "数据源复核",
          scenario: "遥测源超时或数据完整率不足。",
          action: "重试关键测点并标记缺失源。",
          tradeoff: "判断更稳妥，但会延后处置。"
        },
        {
          id: "fallback-model",
          title: "模型比对",
          scenario: "压力或流量偏差集中在局部分区。",
          action: "对比基线工况并圈定疑似影响范围。",
          tradeoff: "响应更快，但依赖模型边界条件质量。"
        },
        {
          id: "fallback-manual",
          title: "人工复核",
          scenario: "异常持续或伴随用户侧反馈。",
          action: "交由调度员确认阀门、泵站和巡检动作。",
          tradeoff: "闭环完整，但会占用人工资源。"
        }
      ]
    };
  }

  return {
    summary: "Agent 将这条工况标记为关注项，当前偏差不足以触发自动处置。",
    notes: [
      "保留当前证据，下一轮继续比对同一测点趋势。",
      "重点观察偏差是否扩大，避免单点噪声误判。",
      "需要时可在 Agent 面板追问偏差来源。"
    ],
    escalationCriteria: [
      "连续两轮工况仍高于关注阈值。",
      "关键测点完整率继续下降。",
      "同一分区出现用户投诉、低压或水质联动线索。"
    ]
  };
}
