'use client';

/**
 * 작업자 화면 메인 컴포넌트 (기획서 기반 전면 개편)
 *
 * 구조:
 * - 상단: 페이지 제목
 * - 탭: 스크린/슬랫/절곡 (디폴트: 스크린)
 * - 상태 카드 4개 (할일/작업중/완료/긴급)
 * - 수주 정보 섹션 (읽기 전용)
 * - 작업 정보 섹션 (생산담당자 셀렉트 + 생산일자)
 * - 작업 목록 (WorkItemCard 나열)
 * - 하단 고정 버튼 (작업일지보기 / 중간검사하기)
 */

/** 품목명에서 길이(mm) 추출: "가이드레일(측면) 본체(철재) 2438mm" → 2438 */
function extractLengthFromName(name?: string | null): number {
  if (!name) return 0;
  const m = name.match(/(\d{3,5})\s*mm/i);
  return m ? parseInt(m[1], 10) : 0;
}

import { useState, useMemo, useCallback, useEffect, useRef } from 'react';
import dynamic from 'next/dynamic';
import { useSearchParams, useRouter, usePathname } from 'next/navigation';
import { useSidebarCollapsed } from '@/stores/menuStore';
import { ClipboardList, PlayCircle, CheckCircle2, AlertTriangle, ChevronDown, ChevronUp, List } from 'lucide-react';
import {
  Dialog,
  DialogContent,
  DialogHeader,
  DialogTitle,
  DialogFooter,
} from '@/components/ui/dialog';
import { ContentSkeleton } from '@/components/ui/skeleton';
import { Card, CardContent } from '@/components/ui/card';
import { Input } from '@/components/ui/input';
import { DatePicker } from '@/components/ui/date-picker';
import { Label } from '@/components/ui/label';
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from '@/components/ui/select';
import { Tabs, TabsList, TabsTrigger, TabsContent } from '@/components/ui/tabs';
import { Button } from '@/components/ui/button';
import { PageLayout } from '@/components/organisms/PageLayout';
import { cn } from '@/lib/utils';
import { toast } from 'sonner';
import { getMyWorkOrders, completeWorkOrder, saveItemInspection, getWorkOrderInspectionData, saveInspectionDocument, getInspectionTemplate, getStepProgress, toggleStepProgress, deleteMaterialInput, updateMaterialInput, getDepartments, getDepartmentUsers, updateWorkOrderInfo } from './actions';
import type { StepProgressItem, DepartmentOption, DepartmentUser } from './actions';
import type { InspectionTemplateData } from './types';
import { getProcessList } from '@/components/process-management/actions';
import type { InspectionSetting, InspectionScope, Process } from '@/types/process';
import type { WorkOrder } from '../ProductionDashboard/types';
import { BENDING_STEP_MAP, extractBendingTypeCode } from '../WorkOrders/types';
import { isNextRedirectError } from '@/lib/utils/redirect-error';
import type {
  WorkerStats,
  CompletionToastInfo,
  MaterialInput,
  ProcessTab,
  WorkItemData,
  WorkStepData,
  MaterialListItem,
} from './types';
import { PROCESS_TAB_LABELS } from './types';
import { WorkItemCard } from './WorkItemCard';
import { CompletionConfirmDialog } from './CompletionConfirmDialog';
import { CompletionToast } from './CompletionToast';
import type { InspectionProcessType, InspectionData } from './InspectionInputModal';

const InspectionInputModal = dynamic(
  () => import('./InspectionInputModal').then(mod => ({ default: mod.InspectionInputModal })),
);
const MaterialInputModal = dynamic(
  () => import('./MaterialInputModal').then(mod => ({ default: mod.MaterialInputModal })),
);
const WorkLogModal = dynamic(
  () => import('./WorkLogModal').then(mod => ({ default: mod.WorkLogModal })),
);
const IssueReportModal = dynamic(
  () => import('./IssueReportModal').then(mod => ({ default: mod.IssueReportModal })),
);
const WorkCompletionResultDialog = dynamic(
  () => import('./WorkCompletionResultDialog').then(mod => ({ default: mod.WorkCompletionResultDialog })),
);
const InspectionReportModal = dynamic(
  () => import('../WorkOrders/documents').then(mod => ({ default: mod.InspectionReportModal })),
);

interface SidebarOrder {
  id: string;
  siteName: string;
  date: string;
  quantity: number;
  shutterCount: number;
  priority: 'urgent' | 'priority' | 'normal';
  subType?: 'slat' | 'jointbar' | 'bending' | 'wip';
  bdCode?: string; // 재공품 BD- 코드 (예: BD-ST-24)
  status?: string; // 작업지시 상태 (waiting/in_progress/completed)
}

const WO_STATUS_BADGE: Record<string, { label: string; className: string }> = {
  completed: { label: '완료', className: 'bg-gray-500 text-white' },
  in_progress: { label: '진행중', className: 'bg-green-100 text-green-700' },
  waiting: { label: '대기', className: 'bg-yellow-100 text-yellow-700' },
  pending: { label: '대기', className: 'bg-gray-100 text-gray-600' },
};

const SUB_TYPE_TAGS: Record<string, { label: string; className: string }> = {
  slat: { label: '슬랫', className: 'bg-blue-100 text-blue-700' },
  jointbar: { label: '조인트바', className: 'bg-purple-100 text-purple-700' },
  bending: { label: '절곡', className: 'bg-amber-100 text-amber-700' },
  wip: { label: '재공품', className: 'bg-orange-100 text-orange-700' },
};

const PRIORITY_GROUPS = [
  { key: 'urgent' as const, label: '긴급', color: 'text-red-600' },
  { key: 'priority' as const, label: '우선', color: 'text-orange-600' },
  { key: 'normal' as const, label: '일반', color: 'text-gray-600' },
];

// 하드코딩된 공정별 단계 폴백
const PROCESS_STEPS: Record<string, { name: string; isMaterialInput: boolean; isInspection?: boolean }[]> = {
  screen: [
    { name: '자재투입', isMaterialInput: true },
    { name: '절단', isMaterialInput: false },
    { name: '미싱', isMaterialInput: false },
    { name: '중간검사', isMaterialInput: false, isInspection: true },
    { name: '포장완료', isMaterialInput: false },
  ],
  slat: [
    { name: '자재투입', isMaterialInput: true },
    { name: '포밍/절단', isMaterialInput: false },
    { name: '중간검사', isMaterialInput: false, isInspection: true },
    { name: '포장완료', isMaterialInput: false },
  ],
  bending: [
    { name: '자재투입', isMaterialInput: true },
    { name: '절단', isMaterialInput: false },
    { name: '절곡', isMaterialInput: false },
    { name: '중간검사', isMaterialInput: false, isInspection: true },
  ],
  bending_wip: [
    { name: '자재투입', isMaterialInput: true },
    { name: '절단', isMaterialInput: false },
    { name: '중간검사', isMaterialInput: false, isInspection: true },
  ],
};

export default function WorkerScreen() {
  // ===== 상태 관리 =====
  const sidebarCollapsed = useSidebarCollapsed();
  const searchParams = useSearchParams();
  const router = useRouter();
  const pathname = usePathname();
  const [workOrders, setWorkOrders] = useState<WorkOrder[]>([]);
  const [isLoading, setIsLoading] = useState(true);
  const [activeTab, setActiveTabState] = useState<string>(searchParams.get('tab') || '');

  // 탭 변경 시 URL query parameter 동기화 (새로고침 시 탭 유지)
  const setActiveTab = useCallback((tab: string) => {
    setActiveTabState(tab);
    const params = new URLSearchParams(searchParams.toString());
    params.set('tab', tab);
    router.replace(`${pathname}?${params.toString()}`, { scroll: false });
  }, [searchParams, router, pathname]);
  const [bendingSubMode, setBendingSubMode] = useState<'normal' | 'wip'>('normal');
  const [slatSubMode, setSlatSubMode] = useState<'normal' | 'jointbar'>('normal');

  // 작업 정보
  const [departmentId, setDepartmentId] = useState('');
  const [productionManagerId, setProductionManagerId] = useState('');
  const [productionDate, setProductionDate] = useState('');
  const [departmentList, setDepartmentList] = useState<DepartmentOption[]>([]);
  const [departmentUsers, setDepartmentUsers] = useState<DepartmentUser[]>([]);

  // 좌측 사이드바
  const [selectedSidebarOrderId, setSelectedSidebarOrderId] = useState<string>('');

  // 작업정보 변경 → API 저장 + workOrders state 동기화
  const saveWorkOrderField = useCallback((field: 'scheduled_date' | 'team_id' | 'assignee_id', value: string | number | null) => {
    const orderId = selectedSidebarOrderId;
    if (!orderId) return;
    updateWorkOrderInfo(orderId, { [field]: value });
    setWorkOrders(prev => prev.map(wo => {
      if (wo.id !== orderId) return wo;
      if (field === 'scheduled_date') return { ...wo, scheduledDate: value as string };
      if (field === 'team_id') return { ...wo, teamId: value as number };
      if (field === 'assignee_id') return { ...wo, assigneeId: value as number };
      return wo;
    }));
  }, [selectedSidebarOrderId]);
  const [isSidebarOpen, setIsSidebarOpen] = useState(false);

  // 공정별 step 완료 상태: { [itemId-stepName]: boolean }
  const [stepCompletionMap, setStepCompletionMap] = useState<Record<string, boolean>>({});

  // 작업지시별 단계 진행 캐시: { [workOrderId]: StepProgressItem[] }
  const [stepProgressMap, setStepProgressMap] = useState<Record<string, StepProgressItem[]>>({});

  // 데이터 로드 (작업목록 + 공정목록 + 부서목록 병렬)
  const loadData = useCallback(async () => {
    setIsLoading(true);
    try {
      const [workOrderResult, processResult, deptResult] = await Promise.all([
        getMyWorkOrders(),
        getProcessList({ size: 100 }),
        getDepartments(),
      ]);

      if (workOrderResult.success) {
        setWorkOrders(workOrderResult.data);
      } else {
        toast.error(workOrderResult.error || '작업 목록 조회에 실패했습니다.');
      }

      if (processResult.success && processResult.data?.items) {
        setProcessListCache(processResult.data.items);
      }

      if (deptResult.success) {
        setDepartmentList(deptResult.data);
      }
    } catch (error) {
      if (isNextRedirectError(error)) throw error;
      console.error('[WorkerScreen] loadData error:', error);
      toast.error('데이터 로드 중 오류가 발생했습니다.');
    } finally {
      setIsLoading(false);
    }
  }, []);

  useEffect(() => {
    loadData();
  }, [loadData]);

  // 부서 선택 시 해당 부서 사용자 목록 로드
  useEffect(() => {
    if (!departmentId) {
      setDepartmentUsers([]);
      setProductionManagerId('');
      return;
    }
    getDepartmentUsers(Number(departmentId)).then((res) => {
      if (res.success) {
        setDepartmentUsers(res.data);
      } else {
        setDepartmentUsers([]);
      }
      setProductionManagerId('');
    });
  }, [departmentId]);

  // PC에서 사이드바 sticky 동작을 위해 main의 overflow 임시 해제
  useEffect(() => {
    const mainEl = document.querySelector('main');
    if (!mainEl) return;
    const original = mainEl.style.overflow;
    mainEl.style.overflow = 'visible';
    return () => {
      mainEl.style.overflow = original;
    };
  }, []);

  // 모달/다이얼로그 상태
  const [selectedOrder, setSelectedOrder] = useState<WorkOrder | null>(null);
  const [isCompletionDialogOpen, setIsCompletionDialogOpen] = useState(false);
  const [isMaterialModalOpen, setIsMaterialModalOpen] = useState(false);
  const [selectedWorkOrderItemId, setSelectedWorkOrderItemId] = useState<number | undefined>();
  const [selectedWorkOrderItemIds, setSelectedWorkOrderItemIds] = useState<number[] | undefined>();
  const [selectedWorkOrderItemName, setSelectedWorkOrderItemName] = useState<string | undefined>();
  const [isWorkLogModalOpen, setIsWorkLogModalOpen] = useState(false);
  const [isInspectionModalOpen, setIsInspectionModalOpen] = useState(false);
  const [isIssueReportModalOpen, setIsIssueReportModalOpen] = useState(false);
  const [isInspectionInputModalOpen, setIsInspectionInputModalOpen] = useState(false);
  // 공정의 중간검사 설정
  const [currentInspectionSetting, setCurrentInspectionSetting] = useState<InspectionSetting | undefined>();
  // 공정의 검사 범위 설정
  const [currentInspectionScope, setCurrentInspectionScope] = useState<InspectionScope | undefined>();
  // 문서 템플릿 데이터 (document_template 기반 동적 검사용)
  const [inspectionTemplateData, setInspectionTemplateData] = useState<InspectionTemplateData | undefined>();
  const [inspectionDimensions, setInspectionDimensions] = useState<{ width?: number; height?: number }>({});
  // 검사 클릭 시 해당 step name 추적 (하드코딩 '중간검사' 제거용)
  const [inspectionStepName, setInspectionStepName] = useState<string>('');

  // 중간검사 체크 상태 관리: { [itemId]: boolean }
  const [inspectionCheckedMap, _setInspectionCheckedMap] = useState<Record<string, boolean>>({});

  // 체크된 검사 항목 수 계산
  const _checkedInspectionCount = useMemo(() => {
    return Object.values(inspectionCheckedMap).filter(Boolean).length;
  }, [inspectionCheckedMap]);

  // 중간검사 완료 데이터 관리
  const [inspectionDataMap, setInspectionDataMap] = useState<Map<string, InspectionData>>(new Map());

  // 전량완료 흐름 상태
  const [isCompletionFlow, setIsCompletionFlow] = useState(false);
  const [isCompletionResultOpen, setIsCompletionResultOpen] = useState(false);
  const [completionLotNo, setCompletionLotNo] = useState('');

  // 투입된 자재 관리 (orderId -> MaterialInput[])
  const [inputMaterialsMap, setInputMaterialsMap] = useState<Map<string, MaterialInput[]>>(
    new Map()
  );

  // 자재 수정 Dialog 상태
  const [editMaterialTarget, setEditMaterialTarget] = useState<{ itemId: string; material: MaterialListItem } | null>(null);
  const [editMaterialQty, setEditMaterialQty] = useState('');

  // 완료 토스트 상태
  const [toastInfo, _setToastInfo] = useState<CompletionToastInfo | null>(null);

  // 공정 목록 캐시
  const [processListCache, setProcessListCache] = useState<Process[]>([]);

  // 활성 공정 목록
  const activeProcesses = useMemo(() => {
    return processListCache.filter((p) => p.status === '사용중');
  }, [processListCache]);

  // 그룹별 탭 구성 (parent_id 기반 트리 구조)
  const groupedTabs = useMemo(() => {
    const groupMap = new Map<string, Process[]>();

    // 루트 공정 기준 그룹 구성
    activeProcesses.forEach((p) => {
      if (p.parentId) return; // 자식은 건너뜀

      const group = p.processName;
      if (!groupMap.has(group)) groupMap.set(group, []);
      groupMap.get(group)!.push(p);

      // 자식 공정 추가
      const children = activeProcesses.filter((c) => c.parentId === p.id);
      children.forEach((c) => groupMap.get(group)!.push(c));
    });

    return Array.from(groupMap.entries()).map(([group, processes]) => ({
      group,
      processes,
      defaultProcessId: processes[0].id,
    }));
  }, [activeProcesses]);

  // processTabs 호환 (기존 코드에서 참조)
  const processTabs = activeProcesses;

  // 선택된 그룹 내 하위 공정 필터
  const [subProcessId, setSubProcessId] = useState<string>('all');

  // 현재 탭의 그룹 정보
  const activeGroup = useMemo(() => {
    const process = processListCache.find((p) => p.id === activeTab);
    if (!process) return null;
    // 자식이면 부모 공정명, 루트면 자기 공정명
    const groupName = process.parentProcessName || process.processName;
    return groupedTabs.find((g) => g.group === groupName) || null;
  }, [activeTab, processListCache, groupedTabs]);

  // 공정 목록 로드 후 탭 선택 (URL 파라미터 우선, 없으면 첫 번째 그룹)
  useEffect(() => {
    if (groupedTabs.length === 0 && !isLoading) {
      if (!activeTab) setActiveTabState('screen');
      return;
    }
    if (groupedTabs.length === 0) return;

    // URL에 tab이 있고 유효한 탭이면 유지
    if (activeTab) {
      const isValid = groupedTabs.some((g) => g.defaultProcessId === activeTab);
      if (isValid) return;
    }
    // 없으면 첫 번째 그룹 선택
    setActiveTabState(groupedTabs[0].defaultProcessId);
  }, [groupedTabs, activeTab, isLoading]);

  // 선택된 공정의 ProcessTab 키 (mock 데이터 및 기존 로직 호환용)
  const activeProcessTabKey: ProcessTab = useMemo(() => {
    const process = processListCache.find((p) => p.id === activeTab);
    if (!process) return 'screen';
    const name = process.processName.toLowerCase();
    if (name.includes('스크린')) return 'screen';
    if (name.includes('슬랫')) return 'slat';
    if (name.includes('절곡')) return 'bending';
    return 'screen';
  }, [activeTab, processListCache]);

  // 선택된 공정의 작업일지/검사성적서 설정
  // subProcessId가 선택되어 있으면 자식 공정의 설정 사용
  const activeProcessSettings = useMemo(() => {
    const effectiveId = subProcessId !== 'all' ? subProcessId : activeTab;
    const process = processListCache.find((p) => p.id === effectiveId);
    // 자식 공정에 설정이 없으면 부모 공정 폴백
    const parentProcess = processListCache.find((p) => p.id === activeTab);
    return {
      needsWorkLog: process?.needsWorkLog ?? parentProcess?.needsWorkLog ?? false,
      hasDocumentTemplate: !!(process?.documentTemplateId ?? parentProcess?.documentTemplateId),
      workLogTemplateId: process?.workLogTemplateId ?? parentProcess?.workLogTemplateId,
      workLogTemplateName: process?.workLogTemplateName ?? parentProcess?.workLogTemplateName,
    };
  }, [activeTab, subProcessId, processListCache]);

  // activeTab 변경 시 해당 공정의 중간검사 설정 조회
  useEffect(() => {
    if (processListCache.length === 0 || !activeTab) return;

    const matchedProcess = processListCache.find((p) => p.id === activeTab);

    if (matchedProcess?.steps) {
      const inspectionStep = matchedProcess.steps.find(
        (step) => step.needsInspection && step.inspectionSetting
      );
      setCurrentInspectionSetting(inspectionStep?.inspectionSetting);
      setCurrentInspectionScope(inspectionStep?.inspectionScope);
    } else {
      setCurrentInspectionSetting(undefined);
      setCurrentInspectionScope(undefined);
    }
  }, [activeTab, processListCache]);

  // ===== 작업지시 선택 시 단계 진행 데이터 로드 =====
  useEffect(() => {
    if (!selectedSidebarOrderId) return;
    if (selectedSidebarOrderId.startsWith('order-')) return;

    const loadStepProgress = async () => {
      try {
        const result = await getStepProgress(selectedSidebarOrderId);
        if (result.success) {
          setStepProgressMap((prev) => ({ ...prev, [selectedSidebarOrderId]: result.data }));
        }
      } catch {
        // step progress 로드 실패 시 무시
      }
    };
    loadStepProgress();
   
  }, [selectedSidebarOrderId]);

  // ===== 탭별 필터링된 작업 (그룹 + 하위 공정 필터) =====
  const filteredWorkOrders = useMemo(() => {
    // 하위 공정이 특정되면 해당 공정만 필터
    if (subProcessId !== 'all') {
      const subProcess = processListCache.find((p) => p.id === subProcessId);
      if (subProcess) {
        const subName = subProcess.processName.toLowerCase();
        return workOrders.filter((order) => {
          const orderProcessName = (order.processName || '').toLowerCase();
          return orderProcessName.includes(subName) || subName.includes(orderProcessName);
        });
      }
    }

    // 그룹 내 모든 공정 매칭
    if (activeGroup) {
      const groupProcessNames = activeGroup.processes.map((p) => p.processName.toLowerCase());
      return workOrders.filter((order) => {
        const orderProcessName = (order.processName || '').toLowerCase();
        return groupProcessNames.some((gpn) =>
          orderProcessName.includes(gpn) || gpn.includes(orderProcessName)
        );
      });
    }

    // 폴백: 기존 방식
    const selectedProcess = processListCache.find((p) => p.id === activeTab);
    if (!selectedProcess) return workOrders;
    const selectedName = selectedProcess.processName.toLowerCase();
    return workOrders.filter((order) => {
      const orderProcessName = (order.processName || '').toLowerCase();
      return orderProcessName.includes(selectedName) || selectedName.includes(orderProcessName);
    });
  }, [workOrders, activeTab, activeGroup, subProcessId, processListCache]);

  // ===== API WorkOrders → SidebarOrder 변환 =====
  const apiSidebarOrders: SidebarOrder[] = useMemo(() => {
    return filteredWorkOrders.map((wo) => {
      const isWip = wo.projectName === '재고생산' || wo.salesOrderNo?.startsWith('STK');
      // 재공품: 첫 번째 item의 BD- 코드 추출
      const bdCode = isWip
        ? wo.nodeGroups?.flatMap(g => g.items).find(it => it.itemCode?.startsWith('BD-'))?.itemCode ?? undefined
        : undefined;
      return {
        id: wo.id,
        siteName: wo.projectName || wo.client || '-',
        date: wo.dueDate || (wo.createdAt ? wo.createdAt.slice(0, 10) : '-'),
        quantity: wo.quantity,
        shutterCount: wo.shutterCount || 0,
        priority: (wo.isUrgent ? 'urgent' : (wo.priority <= 3 ? 'priority' : 'normal')) as SidebarOrder['priority'],
        subType: isWip ? 'wip' as const : undefined,
        bdCode,
        status: wo.status,
      };
    });
  }, [filteredWorkOrders]);

  // ===== 탭 변경/데이터 로드 시 최상위 우선순위 작업 자동 선택 =====
  useEffect(() => {
    if (isLoading) return;

    const allOrders: SidebarOrder[] = [...apiSidebarOrders];

    // 현재 선택이 유효하면 자동 전환하지 않음 (데이터 새로고침 시 선택 유지)
    if (selectedSidebarOrderId && allOrders.some((o) => o.id === selectedSidebarOrderId)) {
      return;
    }

    // API 작업지시 우선 선택 (부서/담당자 연동을 위해)
    if (apiSidebarOrders.length > 0) {
      const firstApi = apiSidebarOrders[0];
      setSelectedSidebarOrderId(firstApi.id);
      if (activeProcessTabKey === 'slat') {
        setSlatSubMode(firstApi.subType === 'jointbar' ? 'jointbar' : 'normal');
      }
      if (activeProcessTabKey === 'bending') {
        setBendingSubMode(firstApi.subType === 'wip' ? 'wip' : 'normal');
      }
      return;
    }

    // API 작업지시 없으면 목업에서 우선순위 순서: urgent → priority → normal
    for (const group of PRIORITY_GROUPS) {
      const first = allOrders.find((o) => o.priority === group.key);
      if (first) {
        setSelectedSidebarOrderId(first.id);
        if (activeProcessTabKey === 'slat') {
          setSlatSubMode(first.subType === 'jointbar' ? 'jointbar' : 'normal');
        }
        if (activeProcessTabKey === 'bending') {
          setBendingSubMode(first.subType === 'wip' ? 'wip' : 'normal');
        }
        return;
      }
    }
  }, [isLoading, apiSidebarOrders, activeProcessTabKey, selectedSidebarOrderId]);

  // ===== 통계 계산 (탭별) =====
  const stats: WorkerStats = useMemo(() => {
    return {
      assigned: filteredWorkOrders.length,
      inProgress: filteredWorkOrders.filter((o) => o.status === 'inProgress').length,
      completed: 0,
      urgent: filteredWorkOrders.filter((o) => o.isUrgent).length,
    };
  }, [filteredWorkOrders]);

  // ===== 선택된 작업지시의 개소별 WorkItemData 변환 + 목업 =====

  // 현재 활성 공정의 단계 설정 (processListCache 기반)
  const activeProcessSteps = useMemo(() => {
    const process = processListCache.find((p) => p.id === activeTab);
    return process?.steps || [];
  }, [activeTab, processListCache]);

  const workItems: WorkItemData[] = useMemo(() => {
    const selectedOrder = filteredWorkOrders.find((wo) => wo.id === selectedSidebarOrderId);
    const stepsKey = (activeProcessTabKey === 'bending' && bendingSubMode === 'wip') ? 'bending_wip' : activeProcessTabKey;
    const hardcodedSteps = PROCESS_STEPS[stepsKey];

    // 공정관리 API에서 가져온 단계가 있으면 우선 사용, 없으면 하드코딩 폴백
    const useApiSteps = activeProcessSteps.length > 0;
    const stepsTemplate: { name: string; isMaterialInput: boolean; isInspection?: boolean }[] = useApiSteps
      ? activeProcessSteps
          .filter((ps) => ps.isActive)
          .sort((a, b) => a.order - b.order)
          .map((ps) => ({
            name: ps.stepName,
            isMaterialInput: ps.stepName.includes('자재투입'),
            isInspection: ps.needsInspection,
          }))
      : hardcodedSteps;

    // step에 API 설정 속성을 매칭하는 헬퍼
    const orderProgress = stepProgressMap[selectedSidebarOrderId || ''] || [];
    const enrichStep = (st: { name: string; isMaterialInput: boolean; isInspection?: boolean }, stepId: string, stepKey: string, apiItemId?: number) => {
      const matched = activeProcessSteps.find((ps) => ps.stepName === st.name);
      // stepProgress 매칭 (개소별: work_order_item_id로 필터)
      const spMatch = orderProgress.find((sp) =>
        sp.step_name === st.name &&
        (sp.work_order_item_id === null || sp.work_order_item_id === (apiItemId ?? null))
      );
      return {
        id: stepId,
        name: st.name,
        isMaterialInput: st.isMaterialInput,
        isInspection: matched ? matched.needsInspection : (st.isInspection || false),
        isCompleted: stepKey in stepCompletionMap ? stepCompletionMap[stepKey] : (spMatch?.is_completed || false),
        stepProgressId: spMatch?.id,
        needsInspection: matched?.needsInspection,
        connectionType: matched?.connectionType,
        connectionTarget: matched?.connectionTarget,
        completionType: matched?.completionType,
      };
    };

    const apiItems: WorkItemData[] = [];

    if (selectedOrder && selectedOrder.nodeGroups && selectedOrder.nodeGroups.length > 0) {
      // 개소별로 WorkItemData 생성
      selectedOrder.nodeGroups.forEach((group, index) => {
        const nodeKey = group.nodeId != null ? String(group.nodeId) : `unassigned-${index}`;
        const firstItem = group.items[0];
        const firstItemId = firstItem?.id as number | undefined;

        // 절곡 공정: BD 코드에 따라 필요한 단계만 필터링
        let itemStepsTemplate = stepsTemplate;
        if (activeProcessTabKey === 'bending') {
          const itemCodes = group.items.map((it) => it.itemCode).filter(Boolean) as string[];
          if (itemCodes.length > 0) {
            const neededKeys = new Set<string>();
            let hasNonBd = false;
            for (const code of itemCodes) {
              const typeCode = extractBendingTypeCode(code);
              if (typeCode && BENDING_STEP_MAP[typeCode]) {
                BENDING_STEP_MAP[typeCode].forEach((k) => neededKeys.add(k));
              } else {
                hasNonBd = true;
              }
            }
            if (!hasNonBd && neededKeys.size > 0) {
              // 단계명 매핑: guide_rail→가이드레일 제작, case→케이스 제작, bottom_finish→하단마감재 제작, inspection→검사/중간검사
              const stepNameMap: Record<string, string[]> = {
                guide_rail: ['가이드레일 제작', '가이드레일'],
                case: ['케이스 제작', '케이스'],
                bottom_finish: ['하단마감재 제작', '하단마감재'],
                inspection: ['검사', '중간검사'],
              };
              const allowedNames = new Set<string>();
              // 자재투입은 항상 포함
              allowedNames.add('자재투입');
              for (const key of neededKeys) {
                (stepNameMap[key] || []).forEach((n) => allowedNames.add(n));
              }
              itemStepsTemplate = stepsTemplate.filter((st) => allowedNames.has(st.name));
            }
          }
        }

        const steps: WorkStepData[] = itemStepsTemplate.map((st, si) => {
          const stepKey = `${selectedOrder.id}-${nodeKey}-${st.name}`;
          return enrichStep(st, `${selectedOrder.id}-${nodeKey}-step-${si}`, stepKey, firstItemId);
        });

        // 개소 내 아이템 이름 요약
        const itemNames = group.items.map((it) => it.itemName).filter(Boolean);
        const itemSummary = itemNames.length > 0 ? itemNames.join(', ') : '-';
        const opts = (firstItem?.options || {}) as Record<string, unknown>;

        // 개소별 투입 자재 매핑 (로컬 오버라이드 > API 초기 데이터)
        const itemMapKey = firstItem?.id ? `${selectedOrder.id}-item-${firstItem.id}` : '';
        const savedMats = inputMaterialsMap.get(itemMapKey) || inputMaterialsMap.get(selectedOrder.id);
        let materialInputsList: MaterialListItem[];
        if (savedMats) {
          materialInputsList = savedMats.map((m) => ({ id: m.id, lotNo: m.lotNo, itemName: m.materialName, quantity: m.inputQuantity, unit: m.unit }));
        } else {
          // API 초기 데이터에서 투입 이력 추출
          const apiMaterialInputs = group.items.flatMap((it) => it.materialInputs || []);
          materialInputsList = apiMaterialInputs.map((mi) => ({
            id: String(mi.id),
            lotNo: mi.lotNo || '',
            itemName: mi.materialName || '',
            quantity: mi.qty,
            unit: mi.unit,
          }));
        }

        // API 데이터에서 자재투입 이력이 있으면 자재투입 step 완료 처리
        if (materialInputsList.length > 0) {
          const matStep = steps.find((s) => s.isMaterialInput);
          if (matStep && !matStep.isCompleted) {
            matStep.isCompleted = true;
          }
        }

        // 개소 내 모든 item IDs 수집 (절곡 공정 등에서 복수 items)
        const allItemIds = group.items.map((it) => it.id as number).filter(Boolean);

        const workItem: WorkItemData = {
          id: `${selectedOrder.id}-node-${nodeKey}`,
          apiItemId: firstItem?.id as number | undefined,
          apiItemIds: allItemIds.length > 0 ? allItemIds : undefined,
          workOrderId: selectedOrder.id,
          itemNo: index + 1,
          itemCode: selectedOrder.orderNo || '-',
          itemName: selectedOrder.productCode !== '-' ? selectedOrder.productCode : itemSummary,
          floor: (opts.floor as string) || '-',
          code: (opts.code as string) || '-',
          width: (opts.bending_width as number) || (opts.width as number) || 0,
          height: (opts.height as number) || extractLengthFromName(firstItem?.itemName) || 0,
          quantity: group.totalQuantity,
          processType: activeProcessTabKey,
          steps,
          materialInputs: materialInputsList,
        };

        // 공정별 추가 정보 추출
        if (opts.cutting_info) {
          const ci = opts.cutting_info as { width: number; sheets: number };
          workItem.cuttingInfo = { width: ci.width, sheets: ci.sheets };
        }
        if (opts.slat_info) {
          const si = opts.slat_info as { length: number; slat_count: number; joint_bar: number; glass_qty: number };
          workItem.slatInfo = { length: si.length, slatCount: si.slat_count, jointBar: si.joint_bar, glassQty: si.glass_qty || 0 };
        }
        if (opts.bending_info) {
          const bi = opts.bending_info as {
            common: { kind: string; type: string; length_quantities: { length: number; quantity: number }[] };
            detail_parts: { part_name: string; material: string; barcy_info: string }[];
          };
          workItem.bendingInfo = {
            common: { kind: bi.common?.kind || '', type: bi.common?.type || '', lengthQuantities: bi.common?.length_quantities || [] },
            detailParts: (bi.detail_parts || []).map(dp => ({ partName: dp.part_name, material: dp.material, barcyInfo: dp.barcy_info })),
          };
        }
        // BD- 코드 추출 (재공품/절곡품 참조용)
        const bdItemCode = firstItem?.itemCode;
        if (bdItemCode?.startsWith('BD-')) {
          workItem.bdCode = bdItemCode;
        }
        if (opts.is_wip) {
          workItem.isWip = true;
          const wi = opts.wip_info as { specification: string; length_quantity: string } | undefined;
          if (wi) {
            workItem.wipInfo = { specification: wi.specification, lengthQuantity: wi.length_quantity };
          }
        }
        if (opts.is_joint_bar) {
          workItem.isJointBar = true;
          const jb = opts.slat_joint_bar_info as { specification: string; length: number; quantity: number } | undefined;
          if (jb) workItem.slatJointBarInfo = jb;
        }

        apiItems.push(workItem);
      });
    } else if (selectedOrder) {
      // nodeGroups가 없는 경우 폴백 (단일 항목)
      const steps: WorkStepData[] = stepsTemplate.map((st, si) => {
        const stepKey = `${selectedOrder.id}-${st.name}`;
        return enrichStep(st, `${selectedOrder.id}-step-${si}`, stepKey);
      });
      const fallbackMats = inputMaterialsMap.get(selectedOrder.id);
      const fallbackMaterialsList: MaterialListItem[] = fallbackMats
        ? fallbackMats.map((m) => ({ id: m.id, lotNo: m.lotNo, itemName: m.materialName, quantity: m.inputQuantity, unit: m.unit }))
        : [];
      apiItems.push({
        id: selectedOrder.id,
        workOrderId: selectedOrder.id,
        itemNo: 1,
        itemCode: selectedOrder.orderNo || '-',
        itemName: selectedOrder.productCode !== '-' ? selectedOrder.productCode : (selectedOrder.productName || '-'),
        floor: '-',
        code: '-',
        width: 0,
        height: 0,
        quantity: selectedOrder.quantity || 0,
        processType: activeProcessTabKey,
        steps,
        materialInputs: fallbackMaterialsList,
      });
    }

    return apiItems;
  }, [filteredWorkOrders, selectedSidebarOrderId, activeProcessTabKey, stepCompletionMap, bendingSubMode, slatSubMode, activeProcessSteps, inputMaterialsMap, stepProgressMap]);

  // ===== 검사 범위(scope) 기반 검사 단계 활성화/비활성화 =====
  // 수주 단위로 적용: API 아이템(실제 수주 개소)에만 scope 적용
  // 목업 아이템은 각각 독립 1개소이므로 항상 검사 버튼 유지
  const scopedWorkItems: WorkItemData[] = useMemo(() => {
    if (!currentInspectionScope || currentInspectionScope.type === 'all') {
      return workItems;
    }

    // 실제 수주 아이템만 분리 (목업 제외)
    const apiItems = workItems.filter((item) => !item.id.startsWith('mock-'));
    const apiCount = apiItems.length;
    if (apiCount === 0) return workItems;

    // 검사 단계를 아예 제거하는 헬퍼
    const removeInspectionSteps = (item: WorkItemData): WorkItemData => ({
      ...item,
      steps: item.steps.filter((step) => !step.isInspection && !step.needsInspection),
    });

    let realIdx = 0;

    if (currentInspectionScope.type === 'sampling') {
      const sampleSize = currentInspectionScope.sampleSize || 1;
      return workItems.map((item) => {
        // 목업은 독립 1개소 → 검사 유지
        if (item.id.startsWith('mock-')) return item;
        const isInSampleRange = realIdx >= apiCount - sampleSize;
        realIdx++;
        return isInSampleRange ? item : removeInspectionSteps(item);
      });
    }

    if (currentInspectionScope.type === 'group') {
      return workItems.map((item) => {
        if (item.id.startsWith('mock-')) return item;
        const isLast = realIdx === apiCount - 1;
        realIdx++;
        return isLast ? item : removeInspectionSteps(item);
      });
    }

    return workItems;
  }, [workItems, currentInspectionScope]);

  // ===== 작업지시 선택 시 기존 검사 데이터 로드 =====
  // workItems 선언 이후에 위치해야 workItems.length 참조 가능
  // workItems.length 의존성: selectedSidebarOrderId 변경 시점에 workItems가 아직 비어있을 수 있음
  // (filteredWorkOrders API 응답이 늦은 경우). workItems가 채워지면 재실행하여 매칭 보장.
  useEffect(() => {
    if (!selectedSidebarOrderId) return;
    // 목업 ID면 건너뛰기
    if (selectedSidebarOrderId.startsWith('order-')) return;
    // workItems가 아직 비어있으면 대기 (채워지면 재실행됨)
    if (workItems.length === 0) return;

    const loadInspectionData = async () => {
      try {
        const result = await getWorkOrderInspectionData(selectedSidebarOrderId);
        if (result.success && result.data?.items) {
          const completionUpdates: Record<string, boolean> = {};
          setInspectionDataMap((prev) => {
            const next = new Map(prev);

            // 절곡 공정: 수주 단위 검사 → 어떤 item이든 inspection_data 있으면 모든 개소가 공유
            const isBendingProcess = workItems.some(w => w.processType === 'bending');
            if (isBendingProcess) {
              const bendingItem = result.data!.items.find(i => i.inspection_data);
              if (bendingItem?.inspection_data) {
                for (const w of workItems) {
                  next.set(w.id, bendingItem.inspection_data as unknown as InspectionData);
                  const inspStep = w.steps.find((s) => s.isInspection || s.needsInspection);
                  if (inspStep) {
                    const stepKey = `${w.id.replace('-node-', '-')}-${inspStep.name}`;
                    completionUpdates[stepKey] = true;
                  }
                }
              }
            } else {
              // 기존: item별 개별 매칭
              for (const apiItem of result.data!.items) {
                if (!apiItem.inspection_data) continue;
                // workItems에서 apiItemId가 일치하는 항목 찾기
                const match = workItems.find((w) => w.apiItemId === apiItem.item_id);
                if (match) {
                  next.set(match.id, apiItem.inspection_data as unknown as InspectionData);
                  // 검사 step 완료 처리 (실제 step name 사용)
                  const inspStep = match.steps.find((s) => s.isInspection || s.needsInspection);
                  if (inspStep) {
                    const stepKey = `${match.id.replace('-node-', '-')}-${inspStep.name}`;
                    completionUpdates[stepKey] = true;
                  }
                }
              }
            }

            return next;
          });
          // stepCompletionMap 일괄 업데이트
          if (Object.keys(completionUpdates).length > 0) {
            setStepCompletionMap((prev) => ({ ...prev, ...completionUpdates }));
          }
        }
      } catch {
        // 검사 데이터 로드 실패는 무시 (새 작업일 수 있음)
      }
    };
    loadInspectionData();
   
  }, [selectedSidebarOrderId, workItems.length]);

  // ===== 작업지시 변경 시 작업 정보 자동 세팅 =====
  // selectedSidebarOrderId 변경 시 workOrders state에서 저장된 값을 로드
  useEffect(() => {
    if (!selectedSidebarOrderId) {
      setDepartmentId('');
      setProductionManagerId('');
      setProductionDate('');
      return;
    }
    const apiOrder = workOrders.find((wo) => wo.id === selectedSidebarOrderId);
    if (!apiOrder) return;

    // 부서 세팅: 1순위 work_orders.team_id → 2순위 process.department(부서명 매칭)
    if (apiOrder.teamId) {
      setDepartmentId(String(apiOrder.teamId));
    } else if (apiOrder.processDepartment && departmentList.length > 0) {
      const matched = departmentList.find((d) => d.name === apiOrder.processDepartment);
      setDepartmentId(matched ? String(matched.id) : '');
    } else {
      setDepartmentId('');
    }
    // 생산담당자 세팅
    setProductionManagerId(apiOrder.assigneeId ? String(apiOrder.assigneeId) : '');
    // 생산일자 세팅
    setProductionDate(apiOrder.scheduledDate || '');
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [selectedSidebarOrderId]);

  // ===== 수주 정보 (사이드바 선택 항목 기반) =====
  const orderInfo = useMemo(() => {
    // 1. 선택된 API 작업지시에서 찾기
    const apiOrder = filteredWorkOrders.find((wo) => wo.id === selectedSidebarOrderId);
    if (apiOrder) {
      return {
        orderDate: apiOrder.createdAt ? new Date(apiOrder.createdAt).toLocaleDateString('ko-KR') : '-',
        salesOrderNo: apiOrder.salesOrderNo || '-',
        siteName: apiOrder.projectName || '-',
        client: apiOrder.client || '-',
        salesManager: apiOrder.salesManager || '-',
        managerPhone: apiOrder.managerPhone || '-',
        shippingDate: apiOrder.dueDate ? new Date(apiOrder.dueDate).toLocaleDateString('ko-KR') : '-',
        status: apiOrder.status || '-',
      };
    }

    // 2. 폴백: 첫 번째 작업
    const first = filteredWorkOrders[0];
    if (!first) return null;
    return {
      orderDate: first.createdAt ? new Date(first.createdAt).toLocaleDateString('ko-KR') : '-',
      salesOrderNo: first.salesOrderNo || '-',
      siteName: first.projectName || '-',
      client: first.client || '-',
      salesManager: first.salesManager || '-',
      managerPhone: first.managerPhone || '-',
      shippingDate: first.dueDate ? new Date(first.dueDate).toLocaleDateString('ko-KR') : '-',
      status: first.status || '-',
    };
  }, [filteredWorkOrders, selectedSidebarOrderId, activeProcessTabKey]);

  // ===== 핸들러 =====

  // 중간검사 버튼 클릭 핸들러 - 템플릿 로드 후 모달 열기
  const handleInspectionClick = useCallback(async (itemId: string, stepName?: string) => {
    // 해당 아이템 찾기
    const item = workItems.find((w) => w.id === itemId);
    if (item) {
      // 클릭된 검사 step name 저장 (stepName 미전달 시 item.steps에서 검사 step 탐색)
      const resolvedStepName = stepName
        || item.steps.find((s) => s.isInspection || s.needsInspection)?.name
        || '';
      setInspectionStepName(resolvedStepName);

      // 합성 WorkOrder 생성
      const syntheticOrder: WorkOrder = {
        id: item.id,
        orderNo: item.itemCode,
        productCode: item.itemCode,
        productName: item.itemName,
        processCode: item.processType,
        processName: PROCESS_TAB_LABELS[item.processType],
        client: '-',
        projectName: '-',
        assignees: [],
        quantity: item.quantity,
        shutterCount: 0,
        dueDate: '',
        priority: 5,
        status: 'waiting',
        isUrgent: false,
        isDelayed: false,
        createdAt: '',
      };
      setSelectedOrder(syntheticOrder);
      setInspectionDimensions({ width: item.width, height: item.height });

      // 실제 API 아이템인 경우 검사 템플릿 로딩 시도
      if (item.workOrderId && !item.id.startsWith('mock-')) {
        try {
          const tplResult = await getInspectionTemplate(item.workOrderId);
          if (tplResult.success && tplResult.data?.has_template) {
            setInspectionTemplateData(tplResult.data);
          } else {
            setInspectionTemplateData(undefined);
          }
        } catch {
          setInspectionTemplateData(undefined);
        }
      } else {
        setInspectionTemplateData(undefined);
      }

      setIsInspectionInputModalOpen(true);
    }
  }, [workItems]);

  // pill 클릭 핸들러
  const handleStepClick = useCallback(
    async (itemId: string, step: WorkStepData) => {
      if (step.isMaterialInput) {
        // 자재투입 → 자재 투입 모달 열기 (개소별)
        const order = workOrders.find((o) => o.id === itemId || itemId.startsWith(`${o.id}-node-`));
        const workItem = workItems.find((item) => item.id === itemId);
        if (order) {
          setSelectedOrder(order);
          // 개소별 API 호출을 위한 apiItemId(s) 설정
          setSelectedWorkOrderItemId(workItem?.apiItemId);
          setSelectedWorkOrderItemIds(workItem?.apiItemIds);
          setSelectedWorkOrderItemName(workItem ? `${workItem.itemName} (${workItem.code})` : undefined);
          setIsMaterialModalOpen(true);
        } else {
          // 목업 아이템인 경우 합성 WorkOrder 생성
          const mockItem = workItems.find((item) => item.id === itemId);
          if (mockItem) {
            const syntheticOrder: WorkOrder = {
              id: mockItem.id,
              orderNo: mockItem.itemCode,
              productCode: mockItem.itemCode,
              productName: mockItem.itemName,
              processCode: mockItem.processType,
              processName: PROCESS_TAB_LABELS[mockItem.processType],
              client: '-',
              projectName: '-',
              assignees: [],
              quantity: mockItem.quantity,
              shutterCount: 0,
              dueDate: '',
              priority: 5,
              status: 'waiting',
              isUrgent: false,
              isDelayed: false,
              createdAt: '',
            };
            setSelectedOrder(syntheticOrder);
            setIsMaterialModalOpen(true);
          }
        }
      } else if (step.connectionType === '팝업' && step.connectionTarget === '중간검사') {
        // 연결정보: 팝업 + 중간검사 → 중간검사 모달 열기
        handleInspectionClick(itemId, step.name);
      } else if (step.needsInspection || step.isInspection) {
        // 검사 단계 (processListCache 설정 또는 하드코딩 폴백) → 중간검사 모달 열기
        handleInspectionClick(itemId, step.name);
      } else if (step.stepProgressId) {
        // stepProgressId가 있으면 서버 토글 API 호출 (모든 일반 step 포함)
        const workItem = workItems.find((item) => item.id === itemId);
        const orderId = workItem?.workOrderId;
        if (orderId) {
          // enrichStep의 stepKey와 동일한 형식 사용 (-node- 제거)
          const stepKey = `${itemId.replace('-node-', '-')}-${step.name}`;
          try {
            const result = await toggleStepProgress(orderId, step.stepProgressId);
            if (result.success && result.data) {
              setStepCompletionMap((prev) => ({
                ...prev,
                [stepKey]: result.data!.is_completed,
              }));
              toast.success(result.data.is_completed ? `${step.name} 완료` : `${step.name} 완료 취소`);

              // 단계 완료 시 생산일자가 비어있으면 오늘로 자동 저장
              if (result.data.is_completed && !productionDate) {
                const today = new Date().toISOString().slice(0, 10);
                setProductionDate(today);
                saveWorkOrderField('scheduled_date', today);
              }

              // 모든 단계 완료 시 작업지시 자동 완료 → 생산일자 저장 + 목록 새로고침
              if (result.data.work_order_status_changed) {
                toast.success('모든 공정 단계 완료 — 작업지시가 자동 완료되었습니다.');
                const today = new Date().toISOString().slice(0, 10);
                setProductionDate(today);
                saveWorkOrderField('scheduled_date', today);
                try {
                  const refreshResult = await getMyWorkOrders();
                  if (refreshResult.success) setWorkOrders(refreshResult.data);
                } catch { /* refresh failed */ }
              }
            } else {
              toast.error(result.error || '단계 완료 처리에 실패했습니다.');
            }
          } catch {
            toast.error('단계 완료 처리 중 오류가 발생했습니다.');
          }
        }
      } else {
        // stepProgressId 없는 경우 → 로컬 토글 (폴백)
        const stepKey = `${itemId.replace('-node-', '-')}-${step.name}`;
        setStepCompletionMap((prev) => ({
          ...prev,
          [stepKey]: !prev[stepKey],
        }));
      }
    },
    [workOrders, workItems, handleInspectionClick]
  );

  // 자재 수정 핸들러 - Dialog 열기
  const handleEditMaterial = useCallback(
    (itemId: string, material: MaterialListItem) => {
      setEditMaterialTarget({ itemId, material });
      setEditMaterialQty(String(material.quantity));
    },
    []
  );

  // 자재 수정 확정
  const handleEditMaterialConfirm = useCallback(async () => {
    if (!editMaterialTarget) return;
    const { itemId, material } = editMaterialTarget;
    const newQty = parseFloat(editMaterialQty);
    if (isNaN(newQty) || newQty <= 0) {
      toast.error('올바른 수량을 입력해주세요.');
      return;
    }

    const workItem = workItems.find((w) => w.id === itemId);
    const orderId = workItem?.workOrderId;
    if (!orderId) return;

    const result = await updateMaterialInput(orderId, parseInt(material.id), newQty);
    if (result.success) {
      toast.success('투입 수량이 수정되었습니다.');
      setEditMaterialTarget(null);
      // 데이터 새로고침
      try {
        const refreshResult = await getMyWorkOrders();
        if (refreshResult.success) setWorkOrders(refreshResult.data);
      } catch { /* refresh failed silently */ }
    } else {
      toast.error(result.error || '수정에 실패했습니다.');
    }
  }, [editMaterialTarget, editMaterialQty, workItems]);

  // 자재 삭제 핸들러
  const handleDeleteMaterial = useCallback(
    async (itemId: string, materialId: string) => {
      const workItem = workItems.find((w) => w.id === itemId);
      const orderId = workItem?.workOrderId;
      if (!orderId) return;

      const result = await deleteMaterialInput(orderId, parseInt(materialId));
      if (result.success) {
        toast.success('자재 투입이 삭제되었습니다.');

        // 해당 개소에 더이상 투입 이력이 없으면 자재투입 step 완료 해제
        const nodeMatch = itemId.match(/-node-(.+)$/);
        if (nodeMatch) {
          const stepKey = `${orderId}-${nodeMatch[1]}-자재투입`;
          // 현재 해당 노드의 materialInputs에서 삭제 대상 제외 후 남은 것 확인
          const currentInputs = workItem.materialInputs?.filter((m) => m.id !== materialId);
          if (!currentInputs || currentInputs.length === 0) {
            setStepCompletionMap((prev) => {
              const next = { ...prev };
              delete next[stepKey];
              return next;
            });
          }
        }

        // 데이터 새로고침
        try {
          const refreshResult = await getMyWorkOrders();
          if (refreshResult.success) {
            setWorkOrders(refreshResult.data);
            // 로컬 오버라이드 모두 제거 (API 데이터가 최신)
            setInputMaterialsMap(new Map());
          }
        } catch { /* refresh failed silently */ }
      } else {
        toast.error(result.error || '삭제에 실패했습니다.');
      }
    },
    [workItems]
  );

  // 자재 저장 핸들러
  const handleSaveMaterials = useCallback(async (orderId: string, materials: MaterialInput[]) => {
    // 개소별 키: workOrderItemId가 있으면 개소별, 없으면 orderId 기준
    const mapKey = selectedWorkOrderItemId ? `${orderId}-item-${selectedWorkOrderItemId}` : orderId;
    setInputMaterialsMap((prev) => {
      const next = new Map(prev);
      next.set(mapKey, materials);
      return next;
    });

    // 자재투입 step 완료로 마킹 - workItem의 id 기반으로 stepKey 생성
    // workItems에서 해당 개소를 찾아 정확한 stepKey 사용
    const matchedItem = workItems.find((item) =>
      selectedWorkOrderItemId
        ? item.apiItemId === selectedWorkOrderItemId
        : item.workOrderId === orderId || item.id === orderId
    );
    if (matchedItem) {
      // workItems의 step 생성 시 stepKey = `${orderId}-${nodeKey}-자재투입` 형식
      // matchedItem.id에서 nodeKey 추출: `${orderId}-node-${nodeKey}`
      const nodeMatch = matchedItem.id.match(/-node-(.+)$/);
      const stepKey = nodeMatch
        ? `${orderId}-${nodeMatch[1]}-자재투입`
        : `${orderId}-자재투입`;
      setStepCompletionMap((prev) => ({
        ...prev,
        [stepKey]: true,
      }));
    }

    // 로컬 오버라이드로 즉시 반영 (전체 새로고침 없이 현재 선택 수주 유지)
  }, [selectedWorkOrderItemId, workItems]);

  // 완료 확인 → MaterialInputModal 열기
  const handleCompletionConfirm = useCallback(() => {
    setIsCompletionFlow(true);
    setIsMaterialModalOpen(true);
  }, []);

  // MaterialInputModal 완료 후 → API 완료 처리 → 결과 팝업
  const handleWorkCompletion = useCallback(async () => {
    if (!selectedOrder) return;
    setIsCompletionFlow(false);

    try {
      const materials = inputMaterialsMap.get(selectedOrder.id);
      const result = await completeWorkOrder(
        selectedOrder.id,
        materials?.map((m) => ({
          materialId: parseInt(m.id),
          quantity: m.inputQuantity,
          lotNo: m.lotNo,
        }))
      );

      if (result.success) {
        // 백엔드에서 받은 실제 LOT 번호로 결과 팝업 표시
        setCompletionLotNo(result.lotNo || '');
        setIsCompletionResultOpen(true);
        setInputMaterialsMap((prev) => {
          const next = new Map(prev);
          next.delete(selectedOrder.id);
          return next;
        });
        setWorkOrders((prev) => prev.filter((o) => o.id !== selectedOrder.id));
      } else {
        toast.error(result.error || '작업 완료 처리에 실패했습니다.');
      }
    } catch (error) {
      if (isNextRedirectError(error)) throw error;
      console.error('[WorkerScreen] handleWorkCompletion error:', error);
      toast.error('작업 완료 중 오류가 발생했습니다.');
    }
  }, [selectedOrder, inputMaterialsMap]);

  // 완료 결과 팝업 확인 → 상태 정리
  const handleCompletionResultConfirm = useCallback(() => {
    setSelectedOrder(null);
    setCompletionLotNo('');
  }, []);

  // 하단 버튼용 합성 WorkOrder (사이드바 선택 우선, 없으면 첫 번째, 그래도 없으면 목업 폴백)
  const getTargetOrder = useCallback((): WorkOrder | null => {
    // 사이드바에서 선택된 작업지시 우선
    const selected = selectedSidebarOrderId
      ? filteredWorkOrders.find((wo) => wo.id === selectedSidebarOrderId)
      : null;
    if (selected) return selected;

    // 선택 없으면 첫 번째 작업지시
    const apiTarget = filteredWorkOrders[0];
    if (apiTarget) return apiTarget;

    // 목업 아이템으로 폴백
    const mockItem = workItems[0];
    if (!mockItem) return null;
    return {
      id: mockItem.id,
      orderNo: mockItem.itemCode,
      productCode: mockItem.itemCode,
      productName: mockItem.itemName,
      processCode: mockItem.processType,
      processName: PROCESS_TAB_LABELS[mockItem.processType],
      client: '-',
      projectName: '-',
      assignees: [],
      quantity: mockItem.quantity,
      shutterCount: 0,
      dueDate: '',
      priority: 5,
      status: 'waiting',
      isUrgent: false,
      isDelayed: false,
      createdAt: '',
    };
  }, [filteredWorkOrders, workItems, selectedSidebarOrderId]);

  // 현재 공정에 맞는 중간검사 타입 결정
  const getInspectionProcessType = useCallback((): InspectionProcessType => {
    if (activeProcessTabKey === 'bending' && bendingSubMode === 'wip') {
      return 'bending_wip';
    }
    if (activeProcessTabKey === 'slat' && slatSubMode === 'jointbar') {
      return 'slat_jointbar';
    }
    return activeProcessTabKey as InspectionProcessType;
  }, [activeProcessTabKey, bendingSubMode, slatSubMode]);

  // 하단 버튼 핸들러
  const handleWorkLog = useCallback(() => {
    const target = getTargetOrder();
    if (target) {
      setSelectedOrder(target);
      setIsWorkLogModalOpen(true);
    } else {
      toast.error('표시할 작업이 없습니다.');
    }
  }, [getTargetOrder]);

  const handleInspection = useCallback(() => {
    const target = getTargetOrder();
    if (target) {
      setSelectedOrder(target);
      setIsInspectionModalOpen(true);
    } else {
      toast.error('표시할 작업이 없습니다.');
    }
  }, [getTargetOrder]);

  // 검사 완료 핸들러 (API 저장 + 메모리 업데이트 + 공정 단계 완료 처리)
  const handleInspectionComplete = useCallback(async (data: InspectionData) => {
    if (!selectedOrder) return;

    // stepCompletionMap 키 생성 헬퍼 (enrichStep 형식 일치: -node- 제거 + 실제 step name)
    const buildStepKey = (stepName: string) =>
      `${selectedOrder.id.replace('-node-', '-')}-${stepName}`;

    // 메모리에 즉시 반영
    // 절곡: 수주 단위 검사 → 모든 개소가 동일한 검사 데이터 공유
    const inspProcessType = getInspectionProcessType();
    const isBendingInsp = inspProcessType === 'bending' || inspProcessType === 'bending_wip';
    setInspectionDataMap((prev) => {
      const next = new Map(prev);
      if (isBendingInsp) {
        for (const w of workItems) {
          next.set(w.id, data);
        }
      } else {
        next.set(selectedOrder.id, data);
      }
      return next;
    });

    // 실제 API item인 경우 서버에 저장
    const targetItem = workItems.find((w) => w.id === selectedOrder.id);
    if (targetItem?.apiItemId && targetItem?.workOrderId) {
      try {
        // 1. 기존: work_order_items.options에 저장
        const result = await saveItemInspection(
          targetItem.workOrderId,
          targetItem.apiItemId,
          getInspectionProcessType(),
          data as unknown as Record<string, unknown>
        );
        if (result.success) {
          toast.success('검사가 저장되었습니다.');
        } else {
          toast.error(result.error || '검사 데이터 저장에 실패했습니다.');
        }

        // 2. Document 동기화: 백엔드가 원본(work_order_items)에서 전체 수집하여 document_data 갱신
        try {
          await saveInspectionDocument(targetItem.workOrderId, {});
        } catch {
          // Document 동기화 실패는 무시 (template 미연결 시 404 가능)
        }

        // 3. 검사 단계 자동 완료 처리 (inspectionStepName 우선, 없으면 steps에서 탐색)
        const stepName = inspectionStepName
          || targetItem.steps.find((s) => (s.completionType === 'inspection_complete') || s.needsInspection || s.isInspection)?.name
          || '';
        const inspectionStep = stepName
          ? targetItem.steps.find((s) => s.name === stepName)
          : undefined;

        if (inspectionStep?.stepProgressId) {
          // 서버에 단계 완료 토글
          try {
            const toggleResult = await toggleStepProgress(targetItem.workOrderId, inspectionStep.stepProgressId);
            if (toggleResult.success) {
              setStepCompletionMap((prev) => ({ ...prev, [buildStepKey(stepName)]: true }));
              if (toggleResult.data?.work_order_status_changed) {
                toast.success('모든 공정 단계 완료 — 작업지시가 자동 완료되었습니다.');
              }
            }
          } catch {
            // 단계 완료 실패 시 로컬만 업데이트
            setStepCompletionMap((prev) => ({ ...prev, [buildStepKey(stepName)]: true }));
          }
        } else if (stepName) {
          // stepProgressId 없으면 로컬만 완료 처리
          setStepCompletionMap((prev) => ({ ...prev, [buildStepKey(stepName)]: true }));
        }
        // 4. 생산일자 자동 저장 (검사 완료 시점 = 생산일자)
        {
          const today = new Date().toISOString().slice(0, 10);
          setProductionDate(today);
          saveWorkOrderField('scheduled_date', today);
        }

        // 5. 작업 목록 리프레시 (상태 변경 반영 → 사이드바 대기/완료 탭 갱신)
        const refreshResult = await getMyWorkOrders();
        if (refreshResult.success) setWorkOrders(refreshResult.data);
      } catch {
        toast.error('검사 데이터 저장 중 오류가 발생했습니다.');
      }
    } else if (inspectionStepName) {
    }
  }, [selectedOrder, workItems, getInspectionProcessType, inspectionStepName]);

  // ===== 재공품 감지 =====
  const hasWipItems = useMemo(() => {
    if (activeProcessTabKey !== 'bending') return false;
    // 1. workItems에서 isWip 체크
    if (workItems.some(item => item.isWip)) return true;
    // 2. Fallback: 선택된 작업지시의 프로젝트명/수주번호로 WIP 판별
    const selectedWo = filteredWorkOrders.find(wo => wo.id === selectedSidebarOrderId);
    return !!(selectedWo && (selectedWo.projectName === '재고생산' || selectedWo.salesOrderNo?.startsWith('STK')));
  }, [activeProcessTabKey, workItems, filteredWorkOrders, selectedSidebarOrderId]);

  // ===== 조인트바 감지 =====
  const hasJointBarItems = useMemo(() => {
    return activeProcessTabKey === 'slat' && slatSubMode === 'jointbar';
  }, [activeProcessTabKey, slatSubMode]);

  // 재공품 통합 문서 (작업일지 + 중간검사) 핸들러
  const _handleWipInspection = useCallback(() => {
    const target = getTargetOrder();
    if (target) {
      setSelectedOrder(target);
      setIsInspectionModalOpen(true);
    } else {
      toast.error('표시할 작업이 없습니다.');
    }
  }, [getTargetOrder]);

  return (
    <PageLayout>
      <div className="pb-20 overflow-x-hidden">
        {/* 완료 토스트 */}
        {toastInfo && <CompletionToast info={toastInfo} />}

        {/* 헤더 */}
        <div className="flex items-center gap-3 mb-6">
          <div className="flex h-10 w-10 items-center justify-center rounded-lg bg-primary/10">
            <ClipboardList className="h-5 w-5 text-primary" />
          </div>
          <div>
            <h1 className="text-2xl font-bold">작업자 화면</h1>
            <p className="text-sm text-muted-foreground">작업을 관리합니다</p>
          </div>
        </div>

        {/* 공정별 탭 (공정관리 API 기반 동적 생성) */}
        {isLoading ? (
          <ContentSkeleton type="list" rows={1} />
        ) : (
        <Tabs
          value={activeTab}
          onValueChange={(v) => setActiveTab(v)}
        >
          <div className="overflow-x-auto -mx-3 px-3 md:mx-0 md:px-0">
            <TabsList className="w-max">
              {groupedTabs.length > 0 ? (
                groupedTabs.map((g) => (
                  <TabsTrigger
                    key={g.defaultProcessId}
                    value={g.defaultProcessId}
                    className="px-6"
                    onClick={() => { setSubProcessId('all'); }}
                  >
                    {g.group}
                  </TabsTrigger>
                ))
              ) : (
                (['screen', 'slat', 'bending'] as ProcessTab[]).map((tab) => (
                  <TabsTrigger key={tab} value={tab} className="px-6">
                    {PROCESS_TAB_LABELS[tab]}
                  </TabsTrigger>
                ))
              )}
            </TabsList>
          </div>

          {/* 하위 공정 필터 제거 — 항상 '전체' 선택 상태로 동작 */}

          {(groupedTabs.length > 0
            ? groupedTabs.map((g) => g.defaultProcessId)
            : ['screen', 'slat', 'bending']
          ).map((tabValue) => (
            <TabsContent key={tabValue} value={tabValue} className="mt-4">
              {/* 모바일: 사이드바 토글 */}
              <div className="md:hidden mb-4">
                <button
                  type="button"
                  onClick={() => setIsSidebarOpen(!isSidebarOpen)}
                  className="w-full flex items-center justify-between px-4 py-3 bg-gray-50 rounded-lg border"
                >
                  <div className="flex items-center gap-2">
                    <List className="h-4 w-4" />
                    <span className="text-sm font-medium">수주 목록</span>
                  </div>
                  {isSidebarOpen ? <ChevronUp className="h-4 w-4" /> : <ChevronDown className="h-4 w-4" />}
                </button>
                {isSidebarOpen && (
                  <div className="mt-2 p-3 border rounded-lg bg-white max-h-[300px] overflow-y-auto">
                    <SidebarContent
                      tab={activeProcessTabKey}
                      selectedOrderId={selectedSidebarOrderId}
                      apiOrders={apiSidebarOrders}
                      onSelectOrder={(id, subType) => {
                        setSelectedSidebarOrderId(id);
                        if (subType === 'slat' || subType === 'jointbar') setSlatSubMode(subType === 'jointbar' ? 'jointbar' : 'normal');
                        if (subType === 'bending' || subType === 'wip') setBendingSubMode(subType === 'wip' ? 'wip' : 'normal');
                        setIsSidebarOpen(false);
                      }}
                    />
                  </div>
                )}
              </div>

              {/* 2-패널 레이아웃 */}
              <div className="flex gap-6">
                {/* 좌측 사이드바 - 데스크탑만 (스크롤 따라다님) */}
                <aside className="hidden md:block w-[250px] shrink-0 self-start sticky top-[6.5rem]">
                  <Card className="max-h-[calc(100vh-7.5rem)] overflow-y-auto">
                    <CardContent className="p-4">
                      <SidebarContent
                        tab={activeProcessTabKey}
                        selectedOrderId={selectedSidebarOrderId}
                        apiOrders={apiSidebarOrders}
                        onSelectOrder={(id, subType) => {
                          setSelectedSidebarOrderId(id);
                          if (subType === 'slat' || subType === 'jointbar') setSlatSubMode(subType === 'jointbar' ? 'jointbar' : 'normal');
                          if (subType === 'bending' || subType === 'wip') setBendingSubMode(subType === 'wip' ? 'wip' : 'normal');
                        }}
                      />
                    </CardContent>
                  </Card>
                </aside>

                {/* 우측 메인 패널 */}
                <div className="flex-1 min-w-0 space-y-6">
                  {/* 상태 카드 */}
                  <div className="grid grid-cols-2 md:grid-cols-4 gap-3">
                    <StatCard
                      title="할일"
                      value={stats.assigned}
                      icon={<ClipboardList className="h-4 w-4" />}
                      variant="default"
                    />
                    <StatCard
                      title="작업중"
                      value={stats.inProgress}
                      icon={<PlayCircle className="h-4 w-4" />}
                      variant="blue"
                    />
                    <StatCard
                      title="완료"
                      value={stats.completed}
                      icon={<CheckCircle2 className="h-4 w-4" />}
                      variant="green"
                    />
                    <StatCard
                      title="긴급"
                      value={stats.urgent}
                      icon={<AlertTriangle className="h-4 w-4" />}
                      variant="red"
                    />
                  </div>

                  {/* 수주 정보 */}
                  <Card>
                    <CardContent className="p-4">
                      <div className="flex items-center justify-between mb-3">
                        <h3 className="text-sm font-semibold text-gray-900">수주 정보</h3>
                        {orderInfo?.status && WO_STATUS_BADGE[orderInfo.status] && (
                          <span className={`px-2 py-0.5 rounded text-xs font-semibold ${WO_STATUS_BADGE[orderInfo.status].className}`}>
                            {WO_STATUS_BADGE[orderInfo.status].label}
                          </span>
                        )}
                      </div>
                      <div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-4 gap-x-6 gap-y-3">
                        <InfoField label="수주일" value={orderInfo?.orderDate} />
                        <InfoField label="수주로트" value={orderInfo?.salesOrderNo} />
                        <InfoField label="현장명" value={orderInfo?.siteName} />
                        <InfoField label="수주처" value={orderInfo?.client} />
                        <InfoField label="수주 담당자" value={orderInfo?.salesManager} />
                        <InfoField label="담당자 연락처" value={orderInfo?.managerPhone} />
                        <InfoField label="출고예정일" value={orderInfo?.shippingDate} />
                      </div>
                    </CardContent>
                  </Card>

                  {/* 작업 정보 - API 연동 */}
                  <Card>
                    <CardContent className="p-4">
                      <h3 className="text-sm font-semibold text-gray-900 mb-3">작업 정보</h3>
                      <div className="grid grid-cols-1 sm:grid-cols-3 gap-4">
                        <div className="space-y-1.5">
                          <Label className="text-sm text-gray-600">부서</Label>
                          <Select
                            key={`dept-${departmentId}`}
                            value={departmentId}
                            onValueChange={(v) => {
                              setDepartmentId(v);
                              if (v) saveWorkOrderField('team_id', Number(v));
                            }}
                          >
                            <SelectTrigger>
                              <SelectValue placeholder="선택" />
                            </SelectTrigger>
                            <SelectContent>
                              {departmentList.map((dept) => (
                                <SelectItem key={dept.id} value={String(dept.id)}>
                                  {dept.name}
                                </SelectItem>
                              ))}
                            </SelectContent>
                          </Select>
                        </div>
                        <div className="space-y-1.5">
                          <Label className="text-sm text-gray-600">생산 담당자</Label>
                          <Select
                            key={`manager-${departmentId}-${productionManagerId}`}
                            value={productionManagerId}
                            onValueChange={(v) => {
                              setProductionManagerId(v);
                              if (v) saveWorkOrderField('assignee_id', Number(v));
                            }}
                            disabled={!departmentId}
                          >
                            <SelectTrigger>
                              <SelectValue placeholder={departmentId ? '선택' : '부서를 먼저 선택'} />
                            </SelectTrigger>
                            <SelectContent>
                              {departmentUsers.map((user) => (
                                <SelectItem key={user.id} value={String(user.id)}>
                                  {user.name}
                                </SelectItem>
                              ))}
                            </SelectContent>
                          </Select>
                        </div>
                        <div className="space-y-1.5">
                          <Label className="text-sm text-gray-600">생산일자</Label>
                          <DatePicker
                            value={productionDate}
                            onChange={(date) => {
                              setProductionDate(date);
                              if (date) saveWorkOrderField('scheduled_date', date);
                            }}
                          />
                        </div>
                      </div>
                    </CardContent>
                  </Card>

                  {/* 작업 목록 */}
                  <div>
                    <h3 className="text-sm font-semibold text-gray-900 mb-3">작업 목록</h3>
                    {isLoading ? (
                      <ContentSkeleton type="cards" rows={4} />
                    ) : workItems.length === 0 ? (
                      <Card>
                        <CardContent className="py-12 text-center text-muted-foreground">
                          해당 공정에 배정된 작업이 없습니다.
                        </CardContent>
                      </Card>
                    ) : (
                      <div className="space-y-4">
                        {scopedWorkItems.map((item) => (
                          <div key={item.id}>
                              <WorkItemCard
                                item={item}
                                onStepClick={handleStepClick}
                                onEditMaterial={handleEditMaterial}
                                onDeleteMaterial={handleDeleteMaterial}
                                onInspectionClick={handleInspectionClick}
                              />
                          </div>
                        ))}
                      </div>
                    )}
                  </div>
                </div>
              </div>
            </TabsContent>
          ))}
        </Tabs>
        )}
      </div>

      {/* 하단 고정 버튼 */}
      {(hasWipItems || activeProcessSettings.needsWorkLog || activeProcessSettings.hasDocumentTemplate) && (
        <div className={`fixed bottom-4 left-4 right-4 px-4 py-3 bg-background/95 backdrop-blur rounded-xl border shadow-lg z-50 transition-all duration-300 md:bottom-6 md:px-6 md:right-[24px] ${sidebarCollapsed ? 'md:left-[120px]' : 'md:left-[280px]'}`}>
          <div className="flex gap-2 md:gap-3">
            {(hasWipItems || activeProcessSettings.needsWorkLog) && (
              <Button
                variant="outline"
                onClick={handleWorkLog}
                className="flex-1 py-5 md:py-6 text-sm md:text-base font-medium"
              >
                작업일지 보기
              </Button>
            )}
            {(hasWipItems || activeProcessSettings.hasDocumentTemplate) && (
              <Button
                onClick={handleInspection}
                className="flex-1 py-5 md:py-6 text-sm md:text-base font-medium bg-gray-900 hover:bg-gray-800"
              >
                검사성적서 보기
              </Button>
            )}
          </div>
        </div>
      )}

      {/* 모달/다이얼로그 */}
      <CompletionConfirmDialog
        open={isCompletionDialogOpen}
        onOpenChange={setIsCompletionDialogOpen}
        order={selectedOrder}
        onConfirm={handleCompletionConfirm}
      />

      <MaterialInputModal
        open={isMaterialModalOpen}
        onOpenChange={(open) => {
          setIsMaterialModalOpen(open);
          if (!open) {
            setSelectedWorkOrderItemId(undefined);
            setSelectedWorkOrderItemIds(undefined);
            setSelectedWorkOrderItemName(undefined);
          }
        }}
        order={selectedOrder}
        workOrderItemId={selectedWorkOrderItemId}
        workOrderItemIds={selectedWorkOrderItemIds}
        workOrderItemName={selectedWorkOrderItemName}
        isCompletionFlow={isCompletionFlow}
        onComplete={handleWorkCompletion}
        onSaveMaterials={handleSaveMaterials}
        savedMaterials={selectedOrder ? inputMaterialsMap.get(selectedOrder.id) : undefined}
      />

      <WorkLogModal
        open={isWorkLogModalOpen}
        onOpenChange={setIsWorkLogModalOpen}
        workOrderId={selectedOrder?.id || null}
        processType={activeProcessTabKey}
        workLogTemplateId={activeProcessSettings.workLogTemplateId}
        workLogTemplateName={activeProcessSettings.workLogTemplateName}
      />

      <InspectionReportModal
        open={isInspectionModalOpen}
        onOpenChange={setIsInspectionModalOpen}
        workOrderId={selectedOrder?.id || null}
        processType={hasWipItems ? 'bending_wip' : activeProcessTabKey}
        readOnly={true}
        isJointBar={hasJointBarItems}
        inspectionData={selectedOrder ? inspectionDataMap.get(selectedOrder.id) : undefined}
        workItems={workItems}
        inspectionDataMap={inspectionDataMap}
        inspectionSetting={currentInspectionSetting}
      />

      <IssueReportModal
        open={isIssueReportModalOpen}
        onOpenChange={setIsIssueReportModalOpen}
        order={selectedOrder}
      />

      <WorkCompletionResultDialog
        open={isCompletionResultOpen}
        onOpenChange={setIsCompletionResultOpen}
        lotNo={completionLotNo}
        onConfirm={handleCompletionResultConfirm}
      />

      {/* 자재 투입 수량 수정 Dialog */}
      <Dialog open={!!editMaterialTarget} onOpenChange={(open) => { if (!open) setEditMaterialTarget(null); }}>
        <DialogContent className="!max-w-sm">
          <DialogHeader>
            <DialogTitle>투입 수량 수정</DialogTitle>
          </DialogHeader>
          <div className="space-y-3 py-2">
            <p className="text-sm text-gray-600">{editMaterialTarget?.material.itemName}</p>
            <Input
              type="number"
              inputMode="numeric"
              value={editMaterialQty}
              onChange={(e) => setEditMaterialQty(e.target.value)}
              placeholder="수량 입력"
              min={1}
              autoFocus
              onKeyDown={(e) => { if (e.key === 'Enter') handleEditMaterialConfirm(); }}
            />
          </div>
          <DialogFooter className="gap-2">
            <Button variant="outline" onClick={() => setEditMaterialTarget(null)}>취소</Button>
            <Button onClick={handleEditMaterialConfirm}>수정</Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>

      <InspectionInputModal
        open={isInspectionInputModalOpen}
        onOpenChange={setIsInspectionInputModalOpen}
        processType={getInspectionProcessType()}
        productName={selectedOrder?.productCode && selectedOrder.productCode !== '-' ? selectedOrder.productCode : (selectedOrder?.productName || workItems[0]?.itemName || '')}
        specification={workItems[0]?.slatJointBarInfo?.specification || workItems[0]?.wipInfo?.specification || ''}
        initialData={selectedOrder ? inspectionDataMap.get(selectedOrder.id) : undefined}
        onComplete={handleInspectionComplete}
        templateData={inspectionTemplateData}
        workItemDimensions={inspectionDimensions}
        workOrderId={workItems.find(w => w.id === selectedOrder?.id)?.workOrderId}
      />
    </PageLayout>
  );
}

// ===== 사이드바 컨텐츠 =====
interface SidebarContentProps {
  tab: ProcessTab;
  selectedOrderId: string;
  apiOrders: SidebarOrder[];
  onSelectOrder: (id: string, subType?: SidebarOrder['subType']) => void;
}

function SidebarContent({
  tab,
  selectedOrderId,
  onSelectOrder,
  apiOrders,
}: SidebarContentProps) {
  const [sidebarTab, setSidebarTab] = useState<'orders' | 'wip'>('orders');
  const [showCompleted, setShowCompleted] = useState(false);
  const [searchTerm, setSearchTerm] = useState('');

  // 수주목록 / 재공품 분리
  const regularOrders = useMemo(() =>
    apiOrders.filter((o) => o.subType !== 'wip'),
  [apiOrders]);
  const wipOrders = useMemo(() =>
    apiOrders.filter((o) => o.subType === 'wip'),
  [apiOrders]);

  // 완료/미완료 필터링
  const pendingRegular = useMemo(() => regularOrders.filter(o => o.status !== 'completed'), [regularOrders]);
  const completedRegular = useMemo(() => regularOrders.filter(o => o.status === 'completed'), [regularOrders]);
  const pendingWip = useMemo(() => wipOrders.filter(o => o.status !== 'completed'), [wipOrders]);
  const completedWip = useMemo(() => wipOrders.filter(o => o.status === 'completed'), [wipOrders]);

  // 검색 필터링
  const displayOrders = useMemo(() => {
    const baseOrders = sidebarTab === 'orders'
      ? (showCompleted ? completedRegular : pendingRegular)
      : (showCompleted ? completedWip : pendingWip);
    if (!searchTerm.trim()) return baseOrders;
    const q = searchTerm.toLowerCase();
    return baseOrders.filter((o) =>
      o.siteName.toLowerCase().includes(q) || o.date.includes(q)
    );
  }, [sidebarTab, showCompleted, pendingRegular, completedRegular, pendingWip, completedWip, searchTerm]);

  const renderOrders = (orders: SidebarOrder[]) => (
    <>
      {PRIORITY_GROUPS.map((group) => {
        const groupOrders = orders.filter((o) => o.priority === group.key);
        if (groupOrders.length === 0) return null;
        return (
          <div key={group.key}>
            <p className={`text-xs font-semibold mb-1.5 ${group.color}`}>{group.label}</p>
            <div className="space-y-1.5">
              {groupOrders.map((order) => {
                const tag = order.subType ? SUB_TYPE_TAGS[order.subType] : null;
                return (
                  <button
                    key={order.id}
                    type="button"
                    onClick={() => onSelectOrder(order.id, order.subType)}
                    className={cn(
                      'w-full text-left p-2.5 rounded-lg border transition-colors text-xs',
                      selectedOrderId === order.id
                        ? 'border-primary bg-primary/5 ring-1 ring-primary/20'
                        : 'border-gray-200 hover:border-gray-300 hover:bg-gray-50'
                    )}
                  >
                    <div className="flex items-center justify-between">
                      <p className={cn("font-medium", order.status === 'completed' ? 'text-gray-400 line-through' : 'text-gray-900')}>{order.siteName}</p>
                      <div className="flex items-center gap-1">
                        {order.status && WO_STATUS_BADGE[order.status] && (
                          <span className={`px-1.5 py-0.5 rounded text-[10px] font-semibold ${WO_STATUS_BADGE[order.status].className}`}>
                            {WO_STATUS_BADGE[order.status].label}
                          </span>
                        )}
                        {tag && (
                          <span className={`px-1.5 py-0.5 rounded text-[10px] font-semibold ${tag.className}`}>
                            {tag.label}
                          </span>
                        )}
                      </div>
                    </div>
                    {order.bdCode && (
                      <p className="text-[10px] text-blue-600 font-mono mt-0.5">{order.bdCode}</p>
                    )}
                    <div className="flex items-center justify-between mt-1 text-gray-500">
                      <span>{order.date}</span>
                      <span>{order.shutterCount}개소</span>
                    </div>
                  </button>
                );
              })}
            </div>
          </div>
        );
      })}
    </>
  );

  return (
    <div className="space-y-3">
      {/* 탭: 수주목록 / 재공품 */}
      <div className="flex border-b">
        <button
          type="button"
          onClick={() => { setSidebarTab('orders'); setShowCompleted(false); setSearchTerm(''); }}
          className={cn(
            'flex-1 text-sm font-medium py-2 border-b-2 transition-colors',
            sidebarTab === 'orders'
              ? 'border-primary text-primary'
              : 'border-transparent text-gray-500 hover:text-gray-700'
          )}
        >
          수주목록 ({pendingRegular.length})
        </button>
        <button
          type="button"
          onClick={() => { setSidebarTab('wip'); setShowCompleted(false); setSearchTerm(''); }}
          className={cn(
            'flex-1 text-sm font-medium py-2 border-b-2 transition-colors',
            sidebarTab === 'wip'
              ? 'border-primary text-primary'
              : 'border-transparent text-gray-500 hover:text-gray-700'
          )}
        >
          재공품 ({pendingWip.length})
        </button>
      </div>

      {/* 대기/완료 토글 */}
      <div className="flex gap-1 px-1">
        <button
          type="button"
          onClick={() => setShowCompleted(false)}
          className={cn(
            'flex-1 text-xs font-medium py-1.5 rounded-md transition-colors',
            !showCompleted ? 'bg-blue-600 text-white' : 'bg-gray-100 text-gray-500 hover:bg-gray-200'
          )}
        >
          대기 ({sidebarTab === 'orders' ? pendingRegular.length : pendingWip.length})
        </button>
        <button
          type="button"
          onClick={() => setShowCompleted(true)}
          className={cn(
            'flex-1 text-xs font-medium py-1.5 rounded-md transition-colors',
            showCompleted ? 'bg-gray-600 text-white' : 'bg-gray-100 text-gray-500 hover:bg-gray-200'
          )}
        >
          완료 ({sidebarTab === 'orders' ? completedRegular.length : completedWip.length})
        </button>
      </div>

      {/* 검색 */}
      <Input
        placeholder="현장명 검색..."
        value={searchTerm}
        onChange={(e) => setSearchTerm(e.target.value)}
        className="h-8 text-xs"
      />

      {displayOrders.length > 0 ? (
        renderOrders(displayOrders)
      ) : (
        <p className="text-xs text-gray-400 text-center py-4">
          {searchTerm ? '검색 결과가 없습니다.' : '데이터가 없습니다.'}
        </p>
      )}
    </div>
  );
}

// ===== 하위 컴포넌트 =====

interface StatCardProps {
  title: string;
  value: number;
  icon: React.ReactNode;
  variant: 'default' | 'blue' | 'green' | 'red';
}

function StatCard({ title, value, icon, variant }: StatCardProps) {
  const variantClasses = {
    default: 'bg-gray-50 text-gray-700',
    blue: 'bg-blue-50 text-blue-700',
    green: 'bg-green-50 text-green-700',
    red: 'bg-red-50 text-red-700',
  };

  return (
    <Card className={variantClasses[variant]}>
      <CardContent className="p-4">
        <div className="flex items-center justify-between">
          <span className="text-sm font-medium">{title}</span>
          {icon}
        </div>
        <p className="text-2xl font-bold mt-2">{value}</p>
      </CardContent>
    </Card>
  );
}

interface InfoFieldProps {
  label: string;
  value?: string;
}

function InfoField({ label, value }: InfoFieldProps) {
  return (
    <div>
      <p className="text-xs text-gray-500">{label}</p>
      <p className="text-sm font-medium text-gray-900 mt-0.5">{value || '-'}</p>
    </div>
  );
}
