// public/app.jsx
const { useState, useMemo, useEffect, useCallback, useRef, memo, createContext, useContext } = React;

const AppContext = createContext(null);
const DragContext = createContext(null);

// ==========================================
// 1. 自定义 Hooks (状态与逻辑控制)
// ==========================================

function useTaskHistory(initial) {
  const [history, setHistory] = useState({ past: [], present: initial, future: [] });

  const dispatch = useCallback((action) => {
     setHistory(curr => {
        const state = curr.present;
        let newPresent = state;

        if (action.type === 'SET_TASKS') newPresent = action.payload;
        else if (action.type === 'UPDATE_TASK') newPresent = state.map(t => t.id === action.id ? { ...t, [action.field]: action.value } : t);
        else if (action.type === 'TOGGLE_TASK') newPresent = state.map(t => t.id === action.id ? { ...t, isExpanded: !t.isExpanded } : t);
        else if (action.type === 'ADD_SIBLING') {
            const idx = state.findIndex(t => t.id === action.id);
            if (idx > -1) {
                const target = state[idx];
                const newTask = { id: Date.now(), parentId: target.parentId, name: '新任务', startDate: target.startDate || formatDate(new Date()), duration: 15, color: '#3b82f6', height: 20 };
                newPresent = [...state]; newPresent.splice(idx + 1, 0, newTask);
            }
        }
        else if (action.type === 'DELETE_TASK') {
            newPresent = state.filter(t => t.id !== action.id);
        }

        if (newPresent === curr.present) return curr;
        return { past: [...curr.past, curr.present].slice(-30), present: newPresent, future: [] };
     });
  }, []);

  return { tasks: history.present, dispatch, undo: () => {}, redo: () => {}, canUndo: false, canRedo: false };
}

function useVirtualizer(itemCount, rowHeight, scrollContainerRef) {
  const [range, setRange] = useState({ start: 0, end: 30 });
  return range;
}

function useTaskTree(tasks, showGroups, sfConfig) {
  return useMemo(() => {
    // 关键加固：防止 undefined 导致 reduce 报错
    const safeTasks = tasks || []; 

    const childrenMap = safeTasks.reduce((acc, t) => {
      const pId = t.parentId || 'root';
      (acc[pId] = acc[pId] || []).push(t);
      return acc;
    }, {});

    const buildTree = (parentId, prefix) => {
      const nodes = childrenMap[parentId] || [];
      let resultNodes = [], groupStart = null, groupEnd = null;

      nodes.forEach((node, index) => {
        const wbs = prefix ? `${prefix}.${index + 1}` : `${index + 1}`;
        const depth = prefix ? prefix.split('.').length : 0;
        const childrenResult = buildTree(node.id, wbs);
        const hasChildren = childrenResult.nodes.length > 0;
        
        let sDate = node.startDate ? parseDateLocal(node.startDate) : null;
        let eDate = null;
        let duration = hasChildren ? 0 : (Number(node.duration) || 0);
        
        if (hasChildren) {
          sDate = childrenResult.start; eDate = childrenResult.end;
          duration = (sDate && eDate) ? Math.max(calcDuration(sDate, eDate, sfConfig), 1) : 0;
        } else {
          eDate = duration > 0 ? calcEndDate(sDate, duration, sfConfig) : sDate;
        }

        resultNodes.push({
          ...node, wbs, depth, isGroup: hasChildren || node.parentId === null,
          computedStart: sDate && !isNaN(sDate) ? formatDate(sDate) : '',
          computedEnd: eDate && !isNaN(eDate) ? formatDate(eDate) : '',
          computedDuration: duration, naturalDuration: sDate && eDate ? naturalDiff(sDate, eDate) + 1 : 0,
          children: childrenResult.nodes
        });

        if (sDate && !isNaN(sDate) && (!groupStart || sDate < groupStart)) groupStart = sDate;
        if (eDate && !isNaN(eDate) && (!groupEnd || eDate > groupEnd)) groupEnd = eDate;
      });
      return { nodes: resultNodes, start: groupStart, end: groupEnd };
    };

    const tree = buildTree('root', '');
    const flatten = (nodes) => nodes.reduce((acc, n) => {
      acc.push(n);
      if (n.isExpanded !== false && n.children.length > 0) acc.push(...flatten(n.children));
      return acc;
    }, []);

    const visibleTasks = flatten(tree.nodes);
    return { visibleTasks, renderedTasks: visibleTasks.filter(task => showGroups || !task.isGroup) };
  }, [tasks, showGroups]);
}

function useTimelineData(visibleTasks, zoomLevel) {
  return useMemo(() => {
    let minDate = new Date();
    const validStarts = visibleTasks.map(t => parseDateLocal(t.computedStart)).filter(d => !isNaN(d));
    if (validStarts.length > 0) minDate = new Date(Math.min(...validStarts));
    
    const pixelsPerDay = (Number(zoomLevel) || 100) / 100 * 20;
    minDate.setDate(minDate.getDate() - 5);

    let columns = [];
    for (let i = 0; i < 100; i++) {
        let d = new Date(minDate); d.setDate(d.getDate() + i);
        columns.push({ start: d, width: pixelsPerDay, label: d.getDate() });
    }

    return { columns, minDate, pixelsPerDay, totalWidth: columns.length * pixelsPerDay, yearMonths: [] };
  }, [visibleTasks, zoomLevel]);
}

// ==========================================
// 2. UI 组件 (简约明亮设计)
// ==========================================

const HeaderBar = memo(({ appData, onSave }) => (
    <div className="bg-white px-4 py-3 shadow-sm border-b flex justify-between items-center shrink-0 z-50">
      <h1 className="text-xl font-black text-slate-800 flex items-center gap-2">
        <i className="fas fa-project-diagram text-indigo-600"></i> {appData.appName}
      </h1>
      <div className="flex gap-3">
        <button onClick={onSave} className="bg-emerald-600 hover:bg-emerald-700 text-white px-4 py-2 rounded-lg text-sm font-bold shadow-md transition-all active:scale-95">
          <i className="fas fa-cloud-upload-alt"></i> 同步到云端
        </button>
      </div>
    </div>
));

const TaskRow = memo(({ task }) => {
    const { timeline } = useContext(AppContext);
    const offsetPx = task.computedStart ? naturalDiff(timeline.minDate, parseDateLocal(task.computedStart)) * timeline.pixelsPerDay : 0;
    const barWidthPx = task.naturalDuration * timeline.pixelsPerDay;
    
    return (
      <div className="flex group border-b border-slate-50 hover:bg-slate-50/50" style={{ height: '40px' }}>
        <div className="flex sticky left-0 z-30 bg-white border-r shadow-sm items-center" style={{ width: '360px' }}>
          <div className="w-12 text-center text-[10px] font-mono text-slate-400">{task.wbs}</div>
          <div className="flex-1 px-2 text-xs font-medium truncate" style={{ paddingLeft: `${task.depth * 15 + 10}px` }}>
            {task.isGroup && <i className="fas fa-folder-open mr-2 text-indigo-400"></i>}
            {task.name}
          </div>
          <div className="w-12 text-center text-xs font-bold text-slate-600">{task.computedDuration}</div>
        </div>
        <div className="flex-1 relative overflow-hidden pointer-events-none">
          {task.computedStart && (
            <div className="absolute rounded shadow-sm flex items-center justify-center text-[9px] text-white font-bold" 
                 style={{ left: `${offsetPx}px`, width: `${barWidthPx}px`, height: '20px', top: '10px', backgroundColor: task.color || '#3b82f6' }}>
              {barWidthPx > 40 && task.computedDuration + 'd'}
            </div>
          )}
        </div>
      </div>
    );
});

function App() {
  const { tasks, dispatch } = useTaskHistory([]);
  const [appData, setAppData] = useState({ appName: '极速进度管理系统' });
  const scrollRef = useRef(null);

  // 👉 加载数据：携带 Token
  useEffect(() => {
    const token = localStorage.getItem('gantt_token');
    fetch('/api/project', {
        headers: { 'Authorization': `Bearer ${token}` }
    })
    .then(res => res.json())
    .then(data => {
        const payload = (data && data.tasks && data.tasks.length > 0) ? data.tasks : window.initialTasksData;
        dispatch({ type: 'SET_TASKS', payload });
    })
    .catch(() => dispatch({ type: 'SET_TASKS', payload: window.initialTasksData }));
  }, []);

  // 👉 保存数据：携带 Token
  const handleSave = () => {
    const token = localStorage.getItem('gantt_token');
    if (!token) return alert('请先进行模拟登录获取 Token！');
    
    fetch('/api/project', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` },
        body: JSON.stringify({ tasks })
    })
    .then(res => res.json())
    .then(data => alert(data.message))
    .catch(() => alert('网络连接错误'));
  };

  const { renderedTasks } = useTaskTree(tasks, true, {});
  const timeline = useTimelineData(renderedTasks, 100);

  const contextValue = useMemo(() => ({ timeline }), [timeline]);

  return (
    <AppContext.Provider value={contextValue}>
      <div className="h-screen w-full flex flex-col bg-slate-50 overflow-hidden font-sans">
        <HeaderBar appData={appData} onSave={handleSave} />
        <div className="flex-1 m-4 bg-white rounded-xl shadow-lg border border-slate-200 overflow-hidden flex flex-col">
          <div ref={scrollRef} className="flex-1 overflow-auto custom-scrollbar">
            <div className="w-max min-w-full">
               {/* 表头 */}
               <div className="sticky top-0 z-40 flex bg-slate-100 border-b-2 border-indigo-500 font-bold text-xs text-slate-600">
                  <div className="sticky left-0 bg-slate-100 z-50 flex items-center border-r" style={{ width: '360px' }}>
                    <div className="w-12 text-center">WBS</div>
                    <div className="flex-1 px-4 text-left">任务名称</div>
                    <div className="w-12 text-center">工期</div>
                  </div>
                  <div className="flex">
                    {timeline.columns.map((c, i) => <div key={i} className="border-r text-center" style={{ width: c.width }}>{c.label}</div>)}
                  </div>
               </div>
               {/* 列表 */}
               <div className="relative">
                 {renderedTasks.map(t => <TaskRow key={t.id} task={t} />)}
               </div>
            </div>
          </div>
        </div>
      </div>
    </AppContext.Provider>
  );
}

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App />);