import React, { useState, useEffect } from 'react';
import { useNavigate } from 'react-router-dom';
import { useAuth } from '../../contexts/AuthContext';
import { textileApi, http } from '../../api';
import { usePlanStatusSync } from '../../hooks/usePlanStatusSync';
import { motion, AnimatePresence } from 'framer-motion';
import { ChevronDown, ChevronRight, ArrowLeft, Link2, Clipboard, Check, Loader2, X } from 'lucide-react';
import { ProcessFlow } from '../../components/ProcessFlow';
import { notifyStepCompleted, notifyPlanUpdated } from '../../utils/notifications';
import { simpleStatusMap as statusMap, PLAN_STATUS, STEP_STATUS } from '../../utils/constants';
import { extractParamsFromLink } from '../../utils/helpers';
import { STORAGE_KEYS } from '../../config/app';
import { useErrorHandler } from '../../hooks/useErrorHandler';
import type { ProductionPlan, PlanProcessStep, Company, Profile, YarnRatio } from '../../types';

// 纱线类型显示映射
const yarnTypeLabels: Record<string, string> = {
  warp: '经线',
  weft: '纬线',
  all: '全部'
};

interface PlanGroup {
  purchaserId: string;
  purchaserName: string;
  plans: (ProductionPlan & {
    processSteps: PlanProcessStep[];
    inventoryRecords: { time: string; quantity: number; rolls: number | null }[];
    yarnRatios?: YarnRatio[];
    image_url?: string | null;
    warp_weight?: number | null;
    weft_weight?: number | null;
    total_weight?: number | null;
    weight?: number | null;
  })[];
}

export function TextilePlanOverview() {
  const navigate = useNavigate();
  const { auth } = useAuth();
  const handleError = useErrorHandler();

  // 使用计划状态同步检查 Hook，每5分钟自动检查并修复状态不一致
  usePlanStatusSync(auth.company?.id);
  const [groups, setGroups] = useState<PlanGroup[]>([]);
  const [expandedGroups, setExpandedGroups] = useState<Set<string>>(new Set());
  const [expandedPlan, setExpandedPlan] = useState<string | null>(null);
  const [loading, setLoading] = useState(true);
  const [confirming, setConfirming] = useState<string | null>(null);
  const [rejecting, setRejecting] = useState<string | null>(null);
  const [showRejectModal, setShowRejectModal] = useState(false);
  const [rejectStepId, setRejectStepId] = useState<string | null>(null);
  const [rejectReason, setRejectReason] = useState('');
  const [importLink, setImportLink] = useState('');
  const [operatorNames, setOperatorNames] = useState<Record<string, string>>({});
  const [rejectedPlans, setRejectedPlans] = useState<Set<string>>(new Set());

  useEffect(() => {
    if (!auth.company) return;
    fetchPlans();
  }, [auth.company]);

  const fetchPlans = async () => {
    const response = await textileApi.listPlans();
    const planData = response.data || [];

    if (planData.length === 0) {
      setGroups([]);
      setLoading(false);
      return;
    }

    const planIds = planData.map(p => p.id);

    const operatorIds = [...new Set(
      planData.flatMap(p => (p.process_steps || []).filter(s => s.operator_id).map(s => s.operator_id!))
    )];
    if (operatorIds.length > 0) {
      try {
        const { data: profilesData } = await http.get<any[]>('/common/profiles', { ids: operatorIds.join(',') });
        const names: Record<string, string> = {};
        (profilesData || []).forEach(p => { names[p.id] = p.username; });
        setOperatorNames(names);
      } catch {}
    }

    const purchaserIds = [...new Set(planData.map(p => p.purchaser_id))];
    const companyMap: Record<string, string> = {};
    planData.forEach(p => {
      if (p.purchaser_name) companyMap[p.purchaser_id] = p.purchaser_name;
    });

    const inventoryResults = await Promise.all(
      planIds.map(id => textileApi.listInventory(id).catch(() => [] as any[]))
    );
    const inventoryByPlan: Record<string, any[]> = {};
    planIds.forEach((id, idx) => { inventoryByPlan[id] = inventoryResults[idx] || []; });

    let yarnRatiosData: any[] = [];
    let productsData: any[] = [];
    try {
      const [yrRes, prRes] = await Promise.all([
        http.get<any[]>('/textile/yarn-ratios', { plan_ids: planIds.join(',') }),
        http.get<any[]>('/common/products', { company_ids: purchaserIds.join(',') })
      ]);
      yarnRatiosData = yrRes.data || [];
      productsData = prRes.data || [];
    } catch {}

    const grouped: Record<string, PlanGroup> = {};
    planData.forEach(plan => {
      const pid = plan.purchaser_id;
      if (!grouped[pid]) {
        grouped[pid] = {
          purchaserId: pid,
          purchaserName: companyMap[pid] || plan.purchaser_name || '未知布行',
          plans: []
        };
      }
      const processSteps = (plan.process_steps || [])
        .sort((a, b) => {
          const order = ['confirm', 'yarn_purchase', 'dyeing', 'machine_start', 'fabric_warehouse'];
          return order.indexOf(a.step_type) - order.indexOf(b.step_type);
        });
      const inventoryRecords = (inventoryByPlan[plan.id] || [])
        .map((r: any) => ({ time: r.created_at, quantity: r.quantity, rolls: r.rolls }));
      const yarnRatios = (yarnRatiosData)
        .filter(y => y.plan_id === plan.id)
        .map(y => ({
          id: y.id,
          plan_id: y.plan_id,
          yarn_name: y.yarn_name,
          ratio: y.ratio,
          amount_per_meter: y.amount_per_meter,
          total_amount: y.total_amount,
          yarn_type: y.yarn_type,
          created_at: y.created_at,
          company_id: y.company_id
        }));
      const product = productsData.find(p =>
        p.fabric_code === plan.fabric_code && p.company_id === plan.purchaser_id
      );
      grouped[pid].plans.push({
        ...plan,
        processSteps,
        inventoryRecords,
        yarnRatios,
        image_url: product?.image_url || null,
        warp_weight: product?.warp_weight || null,
        weft_weight: product?.weft_weight || null,
        total_weight: product?.total_weight || null,
        weight: product?.weight || null
      });
    });

    const groupList = Object.values(grouped);
    setGroups(groupList);
    if (groupList.length > 0) {
      setExpandedGroups(new Set([groupList[0].purchaserId]));
    }
    setLoading(false);
  };

  const toggleGroup = (id: string) => {
    setExpandedGroups(prev => {
      const next = new Set(prev);
      if (next.has(id)) next.delete(id);
      else next.add(id);
      return next;
    });
  };

  const handleImportFromLink = () => {
    if (!importLink.trim()) return;

    const { token, plan, type, shortCode } = extractParamsFromLink(importLink);

    if (shortCode) {
      navigate(`/import?s=${shortCode}`);
    } else if (token) {
      navigate(`/import?token=${token}`);
    } else if (plan && type) {
      navigate(`/import?plan=${plan}&type=${type}`);
    } else {
      handleError(new Error('无效的链接格式'), { userMessage: '请确保链接包含 token、s 或 plan 参数' });
    }
  };

  const handlePasteFromClipboard = async () => {
    try {
      const text = await navigator.clipboard.readText();
      if (text.includes('/import?') || text.includes('#/import?')) {
        setImportLink(text);
        const { token, plan, type, shortCode } = extractParamsFromLink(text);

        if (shortCode) {
          navigate(`/import?s=${shortCode}`);
        } else if (token) {
          navigate(`/import?token=${token}`);
        } else if (plan && type) {
          navigate(`/import?plan=${plan}&type=${type}`);
        } else {
          handleError(new Error('链接格式不正确'), { userMessage: '请检查链接是否完整' });
        }
      } else {
        handleError(new Error('无效链接'), { userMessage: '剪贴板中没有检测到有效的导入链接' });
      }
    } catch (err) {
      handleError(err, { userMessage: '无法读取剪贴板，请手动粘贴链接' });
    }
  };

  // 打开拒绝弹窗
  const handleOpenRejectModal = (stepId: string) => {
    setRejectStepId(stepId);
    setRejectReason('');
    setShowRejectModal(true);
  };

  // 关闭拒绝弹窗
  const handleCloseRejectModal = () => {
    setShowRejectModal(false);
    setRejectStepId(null);
    setRejectReason('');
  };

  // 处理拒绝计划
  const handleRejectStep = async () => {
    if (!rejectStepId || !rejectReason.trim()) {
      handleError(new Error('缺少拒绝原因'), { userMessage: '请输入拒绝原因' });
      return;
    }

    setRejecting(rejectStepId);

    try {
      const planId = groups.flatMap(g => g.plans).find(
        p => p.processSteps.some(s => s.id === rejectStepId)
      )?.id;

      if (!planId) {
        setRejecting(null);
        handleCloseRejectModal();
        return;
      }

      await textileApi.rejectStep(planId, rejectStepId, { reason: rejectReason.trim() });

      await notifyPlanUpdated(planId, PLAN_STATUS.REJECTED, auth.company!.id, auth.user!.id);

      setRejectedPlans(prev => new Set([...prev, planId]));

      const stored = localStorage.getItem(STORAGE_KEYS.textileRejectedPlans);
      const rejectedArray = stored ? JSON.parse(stored) : [];
      if (!rejectedArray.includes(planId)) {
        rejectedArray.push(planId);
        localStorage.setItem(STORAGE_KEYS.textileRejectedPlans, JSON.stringify(rejectedArray));
      }

      handleCloseRejectModal();
      setExpandedPlan(null);
    } catch (err) {
      handleError(err, { userMessage: '拒绝失败，请重试' });
    }
    setRejecting(null);
  };

  const handleConfirmStep = async (stepId: string, quantity?: number, rolls?: number) => {
    setConfirming(stepId);

    const plan = groups.flatMap(g => g.plans).find(
      p => p.processSteps.some(s => s.id === stepId)
    );
    const step = plan?.processSteps.find(s => s.id === stepId);
    const planId = plan?.id;

    if (!planId || !step) {
      setConfirming(null);
      return;
    }

    try {
      if (step.step_type === 'fabric_warehouse' && quantity && quantity > 0) {
        await textileApi.inbound(planId, {
          quantity,
          rolls: rolls || 0,
        });

        await textileApi.completeStep(planId, stepId, {
          operator_name: auth.user?.username
        });
      } else {
        await textileApi.completeStep(planId, stepId, {
          operator_name: auth.user?.username
        });
      }

      const stepNames: Record<string, string> = {
        confirm: '确认计划',
        yarn_purchase: '采纱',
        dyeing: '染纱',
        machine_start: '上机',
        fabric_warehouse: '坯布生产'
      };
      const stepName = stepNames[step.step_type || ''] || '生产节点';
      await notifyStepCompleted(
        planId,
        stepName,
        auth.company!.id,
        auth.user!.id,
        step.step_type === 'fabric_warehouse' ? { quantity, rolls } : undefined
      );

      await fetchPlans();
    } catch (err) {
      handleError(err, { userMessage: '确认失败，请重试' });
    }
    setConfirming(null);
  };

  // 将步骤转换为 ProcessFlow 需要的格式
  const formatProcessNodes = (steps: PlanProcessStep[]) => {
    return steps.map(step => ({
      id: step.id,
      name: step.step_type,
      status: step.status,
      timestamp: step.timestamp,
      stepType: step.step_type,
      operatorName: step.operator_id ? operatorNames[step.operator_id] : undefined
    }));
  };

  return (
    <div className="min-h-screen bg-gray-50 p-3 sm:p-4 md:p-6">
      <div className="max-w-6xl mx-auto">
        <div className="flex items-center gap-2 sm:gap-3 md:gap-4 mb-4 sm:mb-5 md:mb-6">
          <motion.button
            whileTap={{ scale: 0.95 }}
            onClick={() => navigate('/textile')}
            className="p-2 hover:bg-gray-200 rounded-full transition-colors will-change-transform"
          >
            <ArrowLeft className="w-5 h-5 sm:w-6 sm:h-6 text-gray-600" />
          </motion.button>
          <h1 className="text-lg sm:text-xl md:text-2xl font-bold text-gray-800">计划总览</h1>
        </div>

        {/* 导入链接区域 */}
        <motion.div
          initial={{ opacity: 0, y: 10 }}
          animate={{ opacity: 1, y: 0 }}
          transition={{ duration: 0.3 }}
          className="bg-white rounded-xl shadow-sm border border-gray-200 p-3 sm:p-4 mb-4 sm:mb-5 md:mb-6"
        >
          <div className="flex items-center justify-between mb-2 sm:mb-3">
            <h2 className="font-semibold text-gray-800 flex items-center gap-2 text-sm sm:text-base">
              <Link2 className="w-4 h-4 sm:w-5 sm:h-5 text-emerald-600" />
              导入关联计划
            </h2>
            <motion.button
              whileTap={{ scale: 0.97 }}
              onClick={handlePasteFromClipboard}
              className="flex items-center gap-1 px-2 sm:px-3 py-1 sm:py-1.5 text-xs sm:text-sm text-emerald-600 hover:bg-emerald-50 rounded-lg transition-colors will-change-transform"
            >
              <Clipboard className="w-3.5 h-3.5 sm:w-4 sm:h-4" />
              识别剪贴板
            </motion.button>
          </div>
          <div className="flex gap-2">
            <input
              type="text"
              value={importLink}
              onChange={(e) => setImportLink(e.target.value)}
              placeholder="粘贴采购商分享的链接..."
              className="flex-1 px-3 sm:px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-emerald-500 focus:border-emerald-500 text-xs sm:text-sm"
            />
            <motion.button
              whileTap={{ scale: 0.97 }}
              onClick={handleImportFromLink}
              disabled={!importLink.trim()}
              className="px-3 sm:px-4 py-2 bg-emerald-600 text-white rounded-lg hover:bg-emerald-700 disabled:opacity-50 disabled:cursor-not-allowed text-xs sm:text-sm font-medium will-change-transform"
            >
              导入
            </motion.button>
          </div>
        </motion.div>

        {loading ? (
          <div className="flex flex-col items-center justify-center py-12 sm:py-16">
            <motion.div
              animate={{ rotate: 360 }}
              transition={{ duration: 1, repeat: Infinity, ease: 'linear' }}
              className="w-6 h-6 sm:w-8 sm:h-8 border-2 border-emerald-500 border-t-transparent rounded-full mb-3"
            />
            <p className="text-gray-400 text-sm">加载中...</p>
          </div>
        ) : groups.length === 0 ? (
          <motion.div
            initial={{ opacity: 0, y: 10 }}
            animate={{ opacity: 1, y: 0 }}
            className="text-center py-12 sm:py-16 text-gray-400"
          >
            <p className="mb-2 text-sm sm:text-base">暂无关联计划</p>
            <p className="text-xs sm:text-sm text-gray-400">请使用上方输入框粘贴采购商分享的链接</p>
          </motion.div>
        ) : (
          <div className="space-y-3 sm:space-y-4">
            {groups.map((group, groupIndex) => (
              <motion.div
                key={group.purchaserId}
                initial={{ opacity: 0, y: 15 }}
                animate={{ opacity: 1, y: 0 }}
                transition={{ delay: groupIndex * 0.08, duration: 0.35 }}
                className="bg-white rounded-xl shadow-sm border border-gray-200 overflow-hidden"
              >
                <motion.div
                  onClick={() => toggleGroup(group.purchaserId)}
                  whileTap={{ scale: 0.995 }}
                  className="flex items-center justify-between p-3 sm:p-4 cursor-pointer hover:bg-gray-50 transition-colors"
                >
                  <div className="flex items-center gap-2 sm:gap-3">
                    <motion.button
                      animate={{ rotate: expandedGroups.has(group.purchaserId) ? 90 : 0 }}
                      transition={{ duration: 0.2 }}
                      className="p-1 rounded hover:bg-gray-200 will-change-transform"
                    >
                      <ChevronRight size={18} className="sm:w-5 sm:h-5" />
                    </motion.button>
                    <div>
                      <h3 className="font-semibold text-gray-800 text-sm sm:text-base">{group.purchaserName}</h3>
                      <span className="text-xs sm:text-sm text-gray-500">计划 ({group.plans.length})</span>
                    </div>
                  </div>
                </motion.div>
                <AnimatePresence>
                  {expandedGroups.has(group.purchaserId) && (
                    <motion.div
                      initial={{ height: 0, opacity: 0 }}
                      animate={{ height: 'auto', opacity: 1 }}
                      exit={{ height: 0, opacity: 0 }}
                      transition={{ duration: 0.3, ease: [0.25, 0.46, 0.45, 0.94] }}
                      className="border-t border-gray-100"
                    >
                      <div className="p-3 sm:p-4 space-y-3 sm:space-y-4">
                        {group.plans.map((plan, planIndex) => {
                          const progress = plan.target_quantity > 0
                            ? Math.round((plan.completed_quantity / plan.target_quantity) * 100)
                            : 0;
                          // 从 processSteps 中检测 rejected 状态
                          const isRejected = plan.processSteps.some(s => s.status === STEP_STATUS.REJECTED);
                          return (
                            <motion.div
                              key={plan.id}
                              initial={{ opacity: 0, y: 8 }}
                              animate={{ opacity: 1, y: 0 }}
                              transition={{ delay: Math.min(planIndex * 0.03, 0.3), duration: 0.25 }}
                              className={`border rounded-2xl overflow-hidden transition-all duration-200 ${isRejected ? 'border-gray-200 bg-gray-50' : 'border-gray-200 bg-white hover:border-emerald-200 hover:shadow-md'}`}
                            >
                              <div
                                onClick={() => !isRejected && setExpandedPlan(expandedPlan === plan.id ? null : plan.id)}
                                className={`p-4 sm:p-5 transition-colors ${isRejected ? 'cursor-default' : 'cursor-pointer hover:bg-gray-50/50'}`}
                              >
                                <div className="flex items-start justify-between gap-3">
                                  <div className="min-w-0 flex-1">
                                    <div className="flex items-center gap-2 mb-2">
                                      {isRejected ? (
                                        <span className="px-2.5 py-1 text-xs rounded-full bg-gray-400 text-white font-medium">
                                          已拒绝
                                        </span>
                                      ) : (
                                        <span className={`px-2.5 py-1 text-xs rounded-full font-medium ${statusMap[plan.status]?.color || 'bg-gray-100'}`}>
                                          {statusMap[plan.status]?.label || plan.status}
                                        </span>
                                      )}
                                      <span className="text-xs text-gray-400 font-mono">{plan.plan_code}</span>
                                    </div>
                                    <p className={`text-sm font-medium truncate ${isRejected ? 'text-gray-500' : 'text-gray-800'}`}>{plan.fabric_code}</p>
                                  </div>
                                  <div className={`text-right text-sm flex-shrink-0 ${isRejected ? 'text-gray-500' : 'text-gray-700'}`}>
                                    <p className="font-medium">{plan.target_quantity.toLocaleString()}<span className="text-xs text-gray-500 ml-1">米</span></p>
                                    <p className="text-xs text-emerald-600">已入 {plan.completed_quantity.toLocaleString()}米</p>
                                  </div>
                                </div>
                                <div className="mt-4">
                                  <div className="flex justify-between text-xs text-gray-500 mb-1.5">
                                    <span className="flex items-center gap-1">
                                      <svg className="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
                                        <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M13 10V3L4 14h7v7l9-11h-7z" />
                                      </svg>
                                      生产进度
                                    </span>
                                    <span className="font-medium text-emerald-600">{progress}%</span>
                                  </div>
                                  <div className="h-2 bg-gray-100 rounded-full overflow-hidden">
                                    <motion.div
                                      initial={{ width: 0 }}
                                      animate={{ width: `${progress}%` }}
                                      transition={{ duration: 0.6, delay: 0.1, ease: [0.25, 0.46, 0.45, 0.94] }}
                                      className="h-full bg-gradient-to-r from-emerald-500 to-green-500 rounded-full"
                                    />
                                  </div>
                                </div>
                              </div>
                              <AnimatePresence>
                                {expandedPlan === plan.id && (
                                  <motion.div
                                    initial={{ height: 0, opacity: 0 }}
                                    animate={{ height: 'auto', opacity: 1 }}
                                    exit={{ height: 0, opacity: 0 }}
                                    transition={{ duration: 0.25 }}
                                    className="border-t border-gray-100 p-3 sm:p-4 bg-gray-50"
                                  >
                                    {/* 产品图片和基本信息 */}
                                    <div className="flex items-start gap-3 mb-3">
                                      {plan.image_url ? (
                                        <img
                                          src={plan.image_url}
                                          alt="产品图片"
                                          className="w-16 h-16 sm:w-20 sm:h-20 rounded-lg object-cover border border-gray-200 flex-shrink-0"
                                        />
                                      ) : (
                                        <div className="w-16 h-16 sm:w-20 sm:h-20 rounded-lg bg-gray-100 flex items-center justify-center flex-shrink-0">
                                          <span className="text-gray-400 text-[10px] sm:text-xs">无图片</span>
                                        </div>
                                      )}
                                      <div className="flex-1 grid grid-cols-2 gap-x-2 gap-y-1 text-xs sm:text-sm">
                                        <div className="truncate">
                                          <span className="text-gray-400">编号:</span>
                                          <span className="ml-1 text-gray-700 font-medium">{plan.plan_code}</span>
                                        </div>
                                        <div className="truncate">
                                          <span className="text-gray-400">坯布:</span>
                                          <span className="ml-1 text-gray-700 font-medium">{plan.fabric_code}</span>
                                        </div>
                                        <div className="truncate">
                                          <span className="text-gray-400">计划:</span>
                                          <span className="ml-1 text-gray-700 font-medium">{plan.target_quantity.toLocaleString()}米</span>
                                        </div>
                                        <div className="truncate">
                                          <span className="text-gray-400">完成:</span>
                                          <span className="ml-1 text-gray-700 font-medium">{plan.completed_quantity.toLocaleString()}米</span>
                                        </div>
                                        <div className="truncate">
                                          <span className="text-gray-400">进度:</span>
                                          <span className="ml-1 text-emerald-600 font-medium">{progress}%</span>
                                        </div>
                                        <div className="truncate">
                                          <span className="text-gray-400">创建:</span>
                                          <span className="ml-1 text-gray-700">{new Date(plan.created_at).toLocaleDateString('zh-CN')}</span>
                                        </div>
                                        <div className="truncate">
                                          <span className="text-gray-400">开始:</span>
                                          <span className="ml-1 text-gray-700">{plan.start_time ? new Date(plan.start_time).toLocaleDateString('zh-CN') : '-'}</span>
                                        </div>
                                      </div>
                                    </div>

                                    {/* 备注信息 */}
                                    {plan.remark && (
                                      <div className="text-xs sm:text-sm bg-gray-50 p-2 rounded-lg mb-3">
                                        <span className="text-gray-400">备注:</span>
                                        <span className="ml-1 text-gray-700">{plan.remark}</span>
                                      </div>
                                    )}

                                    {/* 克重和采购价信息 */}
                                    <div className="grid grid-cols-2 sm:grid-cols-5 gap-2 text-xs sm:text-sm mb-3">
                                      <div className="truncate">
                                        <span className="text-gray-400">克重:</span>
                                        <span className="ml-1 text-gray-700 font-medium">{plan.weight || plan.total_weight || plan.yarn_usage_per_meter || '-'}g</span>
                                      </div>
                                      <div className="truncate">
                                        <span className="text-gray-400">经线:</span>
                                        <span className="ml-1 text-gray-700 font-medium">{plan.warp_weight || '-'}g</span>
                                      </div>
                                      <div className="truncate">
                                        <span className="text-gray-400">纬线:</span>
                                        <span className="ml-1 text-gray-700 font-medium">{plan.weft_weight || '-'}g</span>
                                      </div>
                                      <div className="truncate">
                                        <span className="text-gray-400">总克重:</span>
                                        <span className="ml-1 text-gray-700 font-medium">{plan.total_weight || '-'}g</span>
                                      </div>
                                      <div className="truncate">
                                        <span className="text-gray-400">采购价:</span>
                                        <span className="ml-1 text-gray-700 font-medium">¥{plan.production_price || 0}/米</span>
                                      </div>
                                    </div>

                                    {/* 纱线配比信息 */}
                                    {plan.yarnRatios && plan.yarnRatios.length > 0 && (
                                      <div className="border-t border-gray-200 pt-3 mb-4">
                                        <h5 className="text-sm font-medium text-gray-900 mb-2">纱线名称/占比</h5>
                                        <div className="flex flex-wrap gap-2">
                                          {plan.yarnRatios.map((yarn, index) => (
                                            <span key={index} className="inline-flex items-center px-2 py-1 bg-emerald-50 text-emerald-700 text-xs rounded-lg">
                                              {yarnTypeLabels[yarn.yarn_type || 'all']}/{yarn.yarn_name}:{Number(yarn.ratio).toFixed(0)}%
                                              {yarn.amount_per_meter && `(${yarn.amount_per_meter}g/m)`}
                                            </span>
                                          ))}
                                        </div>
                                        {plan.yarn_usage_per_meter && (
                                          <p className="text-xs text-gray-500 mt-2">
                                            每米纱用量: {plan.yarn_usage_per_meter}g/m
                                          </p>
                                        )}
                                      </div>
                                    )}

                                    {/* 生产流程 */}
                                    {plan.processSteps.length > 0 && (
                                      <div className="border-t border-gray-200 pt-3">
                                        <h5 className="font-medium mb-3 sm:mb-4 flex items-center gap-2 text-sm">
                                          <Check className="w-4 h-4 text-emerald-600" />
                                          生产记录
                                        </h5>
                                        <ProcessFlow
                                          nodes={formatProcessNodes(plan.processSteps)}
                                          onConfirm={(stepId, quantity, rolls) => handleConfirmStep(stepId, quantity, rolls)}
                                          onReject={handleOpenRejectModal}
                                          confirmLoading={confirming}
                                          showConfirmButton={true}
                                          planTargetQuantity={plan.target_quantity}
                                          planCompletedQuantity={plan.completed_quantity}
                                          isPlanLocked={plan.status === PLAN_STATUS.COMPLETED}
                                          lastInventoryTime={plan.inventoryRecords[0]?.time}
                                          inventoryRecords={plan.inventoryRecords}
                                          yarnRatios={plan.yarnRatios}
                                          companyId={auth.company?.id}
                                          planId={plan.id}
                                        />
                                      </div>
                                    )}
                                  </motion.div>
                                )}
                              </AnimatePresence>
                            </motion.div>
                          );
                        })}
                      </div>
                    </motion.div>
                  )}
                </AnimatePresence>
              </motion.div>
            ))}
          </div>
        )}
      </div>

      {/* 拒绝计划弹窗 */}
      <AnimatePresence>
        {showRejectModal && (
          <motion.div
            initial={{ opacity: 0 }}
            animate={{ opacity: 1 }}
            exit={{ opacity: 0 }}
            className="fixed inset-0 bg-black/50 flex items-center justify-center z-50 p-4"
          >
            <motion.div
              initial={{ scale: 0.95, opacity: 0, y: 20 }}
              animate={{ scale: 1, opacity: 1, y: 0 }}
              exit={{ scale: 0.95, opacity: 0, y: 20 }}
              transition={{ duration: 0.2, ease: [0.25, 0.46, 0.45, 0.94] }}
              className="bg-white rounded-xl p-6 w-full max-w-md shadow-xl"
            >
              <div className="flex items-center gap-3 mb-4">
                <div className="w-10 h-10 rounded-full bg-red-100 flex items-center justify-center">
                  <X className="w-6 h-6 text-red-600" />
                </div>
                <h3 className="text-lg font-semibold text-gray-800">拒绝计划</h3>
              </div>
              <p className="text-sm text-gray-600 mb-4">
                请填写拒绝原因，采购商将收到通知并可以重新调整计划。
              </p>
              <div className="mb-4">
                <label className="block text-sm font-medium text-gray-700 mb-2">
                  拒绝原因 <span className="text-red-500">*</span>
                </label>
                <textarea
                  value={rejectReason}
                  onChange={(e) => setRejectReason(e.target.value)}
                  placeholder="请输入拒绝原因，如：产能不足、价格不合适等..."
                  className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-red-500 focus:border-red-500 text-sm resize-none"
                  rows={4}
                />
              </div>
              <div className="flex gap-3">
                <motion.button
                  whileTap={{ scale: 0.98 }}
                  onClick={handleCloseRejectModal}
                  className="flex-1 py-2 border border-gray-300 rounded-lg text-gray-700 hover:bg-gray-50 text-sm font-medium transition-colors"
                >
                  取消
                </motion.button>
                <motion.button
                  whileTap={{ scale: 0.98 }}
                  onClick={handleRejectStep}
                  disabled={!rejectReason.trim() || rejecting === rejectStepId}
                  className="flex-1 py-2 bg-red-600 text-white rounded-lg hover:bg-red-700 disabled:opacity-50 text-sm font-medium transition-colors flex items-center justify-center gap-2"
                >
                  {rejecting === rejectStepId ? (
                    <Loader2 className="w-4 h-4 animate-spin" />
                  ) : (
                    <X className="w-4 h-4" />
                  )}
                  确认拒绝
                </motion.button>
              </div>
            </motion.div>
          </motion.div>
        )}
      </AnimatePresence>
    </div>
  );
}
