"use client";

import { useEffect, useState, useCallback } from "react";
import { aiAgentApi } from "@/lib/api/aiAgent";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Dialog, DialogContent, DialogHeader, DialogTitle } from "@/components/ui/dialog";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
import { Label } from "@/components/ui/label";
import { Badge } from "@/components/ui/badge";
import { Network, Plus, Pencil, Trash2, Loader2, Bot, Database, Globe, FileText, Cpu, Bug, X, Zap, ListOrdered, Shuffle, GripVertical, ArrowDown, Check, Split } from "lucide-react";
import { toast } from "sonner";
import { DndContext, closestCenter, PointerSensor, useSensor, useSensors, type DragEndEvent } from "@dnd-kit/core";
import { SortableContext, verticalListSortingStrategy, useSortable } from "@dnd-kit/sortable";
import { CSS } from "@dnd-kit/utilities";
import { safeArray } from "@/lib/utils";

const CONNECTOR_ICONS: Record<string, any> = { database: Database, rest_api: Globe, file: FileText, plc: Cpu, crawler: Bug };
const CONNECTOR_COLORS: Record<string, string> = { database: "bg-blue-100 text-blue-700 dark:bg-blue-900/30 dark:text-blue-400", rest_api: "bg-green-100 text-green-700 dark:bg-green-900/30 dark:text-green-400", file: "bg-amber-100 text-amber-700 dark:bg-amber-900/30 dark:text-amber-400", plc: "bg-purple-100 text-purple-700 dark:bg-purple-900/30 dark:text-purple-400", crawler: "bg-rose-100 text-rose-700 dark:bg-rose-900/30 dark:text-rose-400" };
const EXEC_MODES = [
  { value: "parallel", label: "병렬", desc: "모두 동시 실행", icon: Zap, color: "text-amber-500" },
  { value: "sequential", label: "순차", desc: "1→2→3 순서대로", icon: ListOrdered, color: "text-blue-500" },
  { value: "mixed", label: "혼합", desc: "같은 순서=병렬", icon: Shuffle, color: "text-violet-500" },
];

export default function WorkspacePage() {
  const [groups, setGroups] = useState<any[]>([]);
  const [agents, setAgents] = useState<any[]>([]);
  const [connectors, setConnectors] = useState<any[]>([]);
  const [loading, setLoading] = useState(true);
  const [groupModalOpen, setGroupModalOpen] = useState(false);
  const [editingGroup, setEditingGroup] = useState<any>(null);
  const [groupForm, setGroupForm] = useState({ name: "", description: "", execution_mode: "parallel" });
  const [memberModalOpen, setMemberModalOpen] = useState(false);
  const [activeGroupId, setActiveGroupId] = useState<number | null>(null);
  const [selectedAgents, setSelectedAgents] = useState<Array<{
    agent_id: number; role_name: string; connectors: any[];
  }>>([]);
  const [detailGroup, setDetailGroup] = useState<any>(null);
  const [saving, setSaving] = useState(false);

  const loadData = useCallback(async () => {
    setLoading(true);
    try {
      const [groupRes, agentRes, connRes] = await Promise.all([
        aiAgentApi.listGroups(),
        aiAgentApi.list({ company_code: "*" } as any),
        aiAgentApi.getAvailableConnectors(),
      ]);
      setGroups(groupRes.data || []);
      setAgents(agentRes.data || []);
      setConnectors(connRes.data || []);
    } catch { toast.error("데이터 로드 실패"); }
    setLoading(false);
  }, []);

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

  const loadGroupDetail = async (id: number) => {
    try {
      const res = await aiAgentApi.getGroup(id);
      setDetailGroup(res.data);
    } catch { toast.error("그룹 상세 로드 실패"); }
  };

  const handleSaveGroup = async () => {
    if (!groupForm.name) { toast.error("그룹 이름을 입력하세요."); return; }
    setSaving(true);
    try {
      if (editingGroup) {
        await aiAgentApi.updateGroup(editingGroup.id, groupForm);
        toast.success("그룹이 수정되었습니다.");
        if (detailGroup?.id === editingGroup.id) loadGroupDetail(editingGroup.id);
      } else {
        await aiAgentApi.createGroup(groupForm);
        toast.success("그룹이 생성되었습니다.");
      }
      setGroupModalOpen(false);
      loadData();
    } catch (e: any) { toast.error(e.response?.data?.message || "저장 실패"); }
    setSaving(false);
  };

  const handleDeleteGroup = async (id: number) => {
    if (!confirm("그룹을 삭제하시겠습니까?")) return;
    try {
      await aiAgentApi.deleteGroup(id);
      toast.success("삭제 완료");
      loadData();
      if (detailGroup?.id === id) setDetailGroup(null);
    }
    catch { toast.error("삭제 실패"); }
  };

  const openAddMembers = (groupId: number) => {
    setActiveGroupId(groupId);
    setSelectedAgents([]);
    setMemberModalOpen(true);
  };

  const toggleAgentSelection = (agentId: number, agentName: string) => {
    setSelectedAgents((prev) => {
      const exists = prev.find((a) => a.agent_id === agentId);
      if (exists) return prev.filter((a) => a.agent_id !== agentId);
      return [...prev, { agent_id: agentId, role_name: agentName, connectors: [] }];
    });
  };

  const updateSelectedAgentRole = (agentId: number, role: string) => {
    setSelectedAgents((prev) => prev.map((a) => a.agent_id === agentId ? { ...a, role_name: role } : a));
  };

  const addConnectorToAgent = (agentId: number, conn: any) => {
    setSelectedAgents((prev) => prev.map((a) =>
      a.agent_id === agentId
        ? { ...a, connectors: [...a.connectors, { type: conn.type, connection_id: conn.connection_id, name: conn.name }] }
        : a
    ));
  };

  const removeConnectorFromAgent = (agentId: number, connIdx: number) => {
    setSelectedAgents((prev) => prev.map((a) =>
      a.agent_id === agentId
        ? { ...a, connectors: a.connectors.filter((_, i) => i !== connIdx) }
        : a
    ));
  };

  const handleSaveMembers = async () => {
    if (selectedAgents.length === 0) { toast.error("에이전트를 선택하세요"); return; }
    if (selectedAgents.some((a) => !a.role_name)) { toast.error("모든 에이전트의 역할을 입력하세요"); return; }
    setSaving(true);
    try {
      const baseOrder = (detailGroup?.members?.length || 0) + 1;
      for (let i = 0; i < selectedAgents.length; i++) {
        const agent = selectedAgents[i];
        await aiAgentApi.addGroupMember(activeGroupId!, {
          agent_id: agent.agent_id,
          role_name: agent.role_name,
          connectors: agent.connectors,
          execution_order: baseOrder + i,
        });
      }
      toast.success(`${selectedAgents.length}개 에이전트가 추가되었습니다.`);
      setMemberModalOpen(false);
      loadGroupDetail(activeGroupId!);
    } catch (e: any) { toast.error(e.response?.data?.message || "추가 실패"); }
    setSaving(false);
  };

  const handleRemoveMember = async (memberId: number) => {
    if (!confirm("멤버를 제거하시겠습니까?")) return;
    try { await aiAgentApi.removeGroupMember(memberId); toast.success("제거 완료"); loadGroupDetail(detailGroup.id); }
    catch { toast.error("제거 실패"); }
  };

  const handleChangeExecMode = async (mode: string) => {
    if (!detailGroup) return;
    try {
      await aiAgentApi.updateGroup(detailGroup.id, { execution_mode: mode });
      setDetailGroup({ ...detailGroup, execution_mode: mode });
      toast.success(`실행 모드: ${EXEC_MODES.find((m) => m.value === mode)?.label}`);
    } catch { toast.error("변경 실패"); }
  };

  const sensors = useSensors(useSensor(PointerSensor, { activationConstraint: { distance: 5 } }));

  const handleDragEnd = async (event: DragEndEvent) => {
    const { active, over } = event;
    if (!over || active.id === over.id || !detailGroup?.members) return;

    const members = [...detailGroup.members].sort((a: any, b: any) => a.execution_order - b.execution_order);
    const oldIndex = members.findIndex((m: any) => String(m.id) === String(active.id));
    const newIndex = members.findIndex((m: any) => String(m.id) === String(over.id));
    if (oldIndex === -1 || newIndex === -1) return;

    const [moved] = members.splice(oldIndex, 1);
    members.splice(newIndex, 0, moved);

    const updatedMembers = members.map((m: any, i: number) => ({ ...m, execution_order: i + 1 }));
    setDetailGroup({ ...detailGroup, members: updatedMembers });

    try {
      await Promise.all(updatedMembers.map((m: any) =>
        aiAgentApi.updateGroupMember(m.id, { execution_order: m.execution_order })
      ));
    } catch {
      toast.error("순서 변경 실패");
      loadGroupDetail(detailGroup.id);
    }
  };

  const handleAddMemberConnector = async (memberId: number, conn: any) => {
    const member = detailGroup?.members?.find((m: any) => m.id === memberId);
    if (!member) return;
    const newConnectors = [...(member.connectors || []), { type: conn.type, connection_id: conn.connection_id, name: conn.name }];
    try {
      await aiAgentApi.updateGroupMember(memberId, { connectors: newConnectors });
      setDetailGroup((prev: any) => ({
        ...prev,
        members: prev.members.map((m: any) => m.id === memberId ? { ...m, connectors: newConnectors } : m),
      }));
      toast.success(`${conn.name} 연결됨`);
    } catch { toast.error("커넥터 연결 실패"); }
  };

  const handleRemoveMemberConnector = async (memberId: number, connIdx: number) => {
    const member = detailGroup?.members?.find((m: any) => m.id === memberId);
    if (!member) return;
    const newConnectors = (member.connectors || []).filter((_: any, i: number) => i !== connIdx);
    try {
      await aiAgentApi.updateGroupMember(memberId, { connectors: newConnectors });
      setDetailGroup((prev: any) => ({
        ...prev,
        members: prev.members.map((m: any) => m.id === memberId ? { ...m, connectors: newConnectors } : m),
      }));
    } catch { toast.error("커넥터 제거 실패"); }
  };

  const renormalizeOrders = (members: any[]) => {
    const sorted = [...members].sort((a: any, b: any) => a.execution_order - b.execution_order);
    const orderMap = new Map<number, number>();
    let nextOrder = 1;
    for (const m of sorted) {
      if (!orderMap.has(m.execution_order)) {
        orderMap.set(m.execution_order, nextOrder++);
      }
    }
    return sorted.map((m: any) => ({ ...m, execution_order: orderMap.get(m.execution_order)! }));
  };

  const persistOrders = async (newMembers: any[]) => {
    if (!detailGroup) return;
    setDetailGroup({ ...detailGroup, members: newMembers });
    try {
      await Promise.all(newMembers.map((m: any) =>
        aiAgentApi.updateGroupMember(m.id, { execution_order: m.execution_order })
      ));
    } catch {
      toast.error("순서 변경 실패");
      loadGroupDetail(detailGroup.id);
    }
  };

  const handleMergeSteps = async (orderA: number, orderB: number) => {
    if (!detailGroup?.members) return;
    const updated = detailGroup.members.map((m: any) =>
      m.execution_order === orderB ? { ...m, execution_order: orderA } : m
    );
    const renormalized = renormalizeOrders(updated);
    await persistOrders(renormalized);
    toast.success("병렬로 합쳐졌습니다");
  };

  const handleSplitMember = async (memberId: number) => {
    if (!detailGroup?.members) return;
    const target = detailGroup.members.find((m: any) => m.id === memberId);
    if (!target) return;
    const currentOrder = target.execution_order;
    const sameStepCount = detailGroup.members.filter((m: any) => m.execution_order === currentOrder).length;
    if (sameStepCount <= 1) return;
    const updated = detailGroup.members.map((m: any) => {
      if (m.id === memberId) return { ...m, execution_order: currentOrder + 1 };
      if (m.execution_order > currentOrder) return { ...m, execution_order: m.execution_order + 1 };
      return m;
    });
    const renormalized = renormalizeOrders(updated);
    await persistOrders(renormalized);
    toast.success("분리되었습니다");
  };

  const activeAgents = agents.filter((a) => a.status === "active");

  return (
    <div className="h-full overflow-y-auto bg-background">
      <div className="space-y-4 p-4 sm:p-5">
        <div className="flex items-center justify-between border-b pb-3">
          <div>
            <h1 className="text-lg font-bold tracking-tight">에이전트 오케스트레이션</h1>
            <p className="mt-0.5 text-xs text-muted-foreground">에이전트 그룹을 구성하고 실행 파이프라인을 설계합니다</p>
          </div>
          <Button onClick={() => { setEditingGroup(null); setGroupForm({ name: "", description: "", execution_mode: "parallel" }); setGroupModalOpen(true); }} size="sm" className="h-8 gap-1 text-xs">
            <Plus className="h-3.5 w-3.5" />그룹 만들기
          </Button>
        </div>
      </div>

      <div className="flex flex-1 overflow-hidden" style={{ height: "calc(100% - 100px)" }}>
        {/* 왼쪽: 그룹 목록 */}
        <div className="w-64 shrink-0 overflow-auto border-r p-3 space-y-1.5">
          {loading ? (
            <div className="flex items-center justify-center py-12"><Loader2 className="h-5 w-5 animate-spin" /></div>
          ) : groups.length === 0 ? (
            <div className="flex flex-col items-center justify-center py-12 text-muted-foreground">
              <Network className="mb-2 h-5 w-5" />
              <p className="text-xs">그룹이 없습니다</p>
            </div>
          ) : (
            groups.map((g) => (
              <div
                key={g.id}
                className={`cursor-pointer rounded-lg border p-2.5 transition-colors hover:bg-accent/50 ${detailGroup?.id === g.id ? "border-primary bg-primary/5" : ""}`}
                onClick={() => loadGroupDetail(g.id)}
              >
                <div className="flex items-center justify-between">
                  <div>
                    <p className="text-xs font-semibold">{g.name}</p>
                    <p className="text-[10px] text-muted-foreground">{g.member_count || 0}개 에이전트</p>
                  </div>
                  <Badge variant={g.status === "active" ? "default" : "secondary"} className="h-4 text-[9px]">{g.status}</Badge>
                </div>
              </div>
            ))
          )}
        </div>

        {/* 오른쪽: 그룹 상세 */}
        <div className="flex-1 overflow-auto p-4 sm:p-5">
          {!detailGroup ? (
            <div className="flex flex-col items-center justify-center h-full text-muted-foreground">
              <Network className="mb-3 h-8 w-8 opacity-20" />
              <p className="text-xs">왼쪽에서 그룹을 선택하세요</p>
            </div>
          ) : (
            <div className="space-y-4">
              <div className="flex flex-wrap items-center justify-between gap-y-2">
                <div className="flex flex-wrap items-center gap-x-3 gap-y-1.5">
                  <h2 className="text-base font-bold">{detailGroup.name}</h2>
                  <div className="flex shrink-0 rounded-md border p-0.5">
                    {EXEC_MODES.map((mode) => (
                      <button
                        key={mode.value}
                        className={`flex shrink-0 items-center gap-1 whitespace-nowrap rounded px-2 py-0.5 text-[10px] font-medium transition-colors ${
                          detailGroup.execution_mode === mode.value ? "bg-primary/10 text-primary" : "text-muted-foreground hover:text-foreground"
                        }`}
                        onClick={() => handleChangeExecMode(mode.value)}
                      >
                        <mode.icon className="h-3 w-3" />
                        {mode.label}
                      </button>
                    ))}
                  </div>
                </div>
                <div className="flex shrink-0 gap-1.5">
                  <Button size="sm" className="h-7 gap-1 text-xs" onClick={() => openAddMembers(detailGroup.id)}>
                    <Plus className="h-3 w-3" />에이전트 추가
                  </Button>
                  <Button size="sm" variant="outline" className="h-7 gap-1 text-xs" onClick={() => { setEditingGroup(detailGroup); setGroupForm({ name: detailGroup.name, description: detailGroup.description || "", execution_mode: detailGroup.execution_mode || "parallel" }); setGroupModalOpen(true); }}>
                    <Pencil className="h-3 w-3" />수정
                  </Button>
                  <Button size="sm" variant="destructive" className="h-7 gap-1 text-xs" onClick={() => handleDeleteGroup(detailGroup.id)}>
                    <Trash2 className="h-3 w-3" />삭제
                  </Button>
                </div>
              </div>

              {detailGroup.description && <p className="text-xs text-muted-foreground">{detailGroup.description}</p>}

              {(!detailGroup.members || detailGroup.members.length === 0) ? (
                <div className="rounded-lg border-2 border-dashed p-10 text-center">
                  <Bot className="mx-auto mb-2 h-6 w-6 text-muted-foreground/30" />
                  <p className="text-xs text-muted-foreground">에이전트를 추가하여 파이프라인을 구성하세요</p>
                </div>
              ) : (() => {
                const mode = detailGroup.execution_mode;
                const members = detailGroup.members || [];

                if (mode === "parallel") {
                  return (
                    <div>
                      <div className="mb-2 flex items-center gap-1.5">
                        <Zap className="h-3.5 w-3.5 text-amber-500" />
                        <span className="text-[11px] font-semibold text-muted-foreground">모든 에이전트 동시 실행</span>
                      </div>
                      <div className="grid grid-cols-1 gap-2 sm:grid-cols-2 lg:grid-cols-3">
                        {members.map((member: any) => (
                          <MemberCard key={member.id} member={member} connectors={connectors} onRemove={() => handleRemoveMember(member.id)} onAddConnector={(conn) => handleAddMemberConnector(member.id, conn)} onRemoveConnector={(ci) => handleRemoveMemberConnector(member.id, ci)} />
                        ))}
                      </div>
                    </div>
                  );
                }

                if (mode === "sequential") {
                  const sorted = [...members].sort((a: any, b: any) => a.execution_order - b.execution_order);
                  return (
                    <DndContext sensors={sensors} collisionDetection={closestCenter} onDragEnd={handleDragEnd}>
                      <SortableContext items={sorted.map((m: any) => String(m.id))} strategy={verticalListSortingStrategy}>
                        <div className="space-y-1">
                          {sorted.map((member: any, idx: number) => (
                            <div key={member.id}>
                              <SortableMemberCard member={member} index={idx} connectors={connectors} onRemove={() => handleRemoveMember(member.id)} onAddConnector={(conn) => handleAddMemberConnector(member.id, conn)} onRemoveConnector={(ci) => handleRemoveMemberConnector(member.id, ci)} />
                              {idx < sorted.length - 1 && (
                                <div className="flex justify-center py-1"><ArrowDown className="h-4 w-4 text-primary/30" /></div>
                              )}
                            </div>
                          ))}
                        </div>
                      </SortableContext>
                    </DndContext>
                  );
                }

                const allSorted = [...members].sort((a: any, b: any) => a.execution_order - b.execution_order);
                const orderGroups = new Map<number, any[]>();
                for (const m of allSorted) {
                  const order = m.execution_order;
                  if (!orderGroups.has(order)) orderGroups.set(order, []);
                  orderGroups.get(order)!.push(m);
                }
                const sortedOrders = [...orderGroups.keys()].sort((a, b) => a - b);

                return (
                  <DndContext sensors={sensors} collisionDetection={closestCenter} onDragEnd={handleDragEnd}>
                    <SortableContext items={allSorted.map((m: any) => String(m.id))} strategy={verticalListSortingStrategy}>
                      <div className="space-y-1">
                        {sortedOrders.map((order, orderIdx) => {
                          const membersInOrder = orderGroups.get(order)!;
                          const isParallel = membersInOrder.length > 1;
                          return (
                            <div key={order}>
                              <div className={`mb-1.5 flex items-center gap-1.5 rounded px-1.5 py-1 ${isParallel ? "border border-amber-200 bg-amber-50 dark:border-amber-900/40 dark:bg-amber-950/20" : ""}`}>
                                <span className="flex h-5 w-5 items-center justify-center rounded-full bg-primary text-[10px] font-bold text-primary-foreground">{orderIdx + 1}</span>
                                <span className="text-[10px] text-muted-foreground">Step {orderIdx + 1}</span>
                                {isParallel && (
                                  <span className="flex items-center gap-0.5 text-[10px] font-semibold text-amber-600 dark:text-amber-500">
                                    <Zap className="h-3 w-3" />
                                    병렬 실행
                                  </span>
                                )}
                              </div>
                              <div className={isParallel ? "grid grid-cols-2 gap-2 lg:grid-cols-3" : ""}>
                                {membersInOrder.map((member: any, idx: number) => (
                                  <SortableMemberCard
                                    key={member.id}
                                    member={member}
                                    index={idx}
                                    connectors={connectors}
                                    onRemove={() => handleRemoveMember(member.id)}
                                    onAddConnector={(conn) => handleAddMemberConnector(member.id, conn)}
                                    onRemoveConnector={(ci) => handleRemoveMemberConnector(member.id, ci)}
                                    onSplit={isParallel ? () => handleSplitMember(member.id) : undefined}
                                  />
                                ))}
                              </div>
                              {orderIdx < sortedOrders.length - 1 && (
                                <div className="flex flex-col items-center gap-1 py-1.5">
                                  <ArrowDown className="h-3.5 w-3.5 text-primary/30" />
                                  <button
                                    onClick={() => handleMergeSteps(order, sortedOrders[orderIdx + 1])}
                                    className="flex items-center gap-1 rounded-full border border-dashed border-amber-300 bg-amber-50/50 px-2 py-0.5 text-[10px] text-amber-700 transition-colors hover:border-amber-500 hover:bg-amber-100 dark:border-amber-800 dark:bg-amber-950/20 dark:text-amber-400 dark:hover:bg-amber-900/30"
                                    title="이 두 스텝을 같은 단계(병렬)로 합치기"
                                  >
                                    <Zap className="h-3 w-3" />
                                    병렬로 합치기
                                  </button>
                                </div>
                              )}
                            </div>
                          );
                        })}
                      </div>
                    </SortableContext>
                  </DndContext>
                );
              })()}
            </div>
          )}
        </div>
      </div>

      {/* 그룹 생성/수정 모달 */}
      <Dialog open={groupModalOpen} onOpenChange={setGroupModalOpen}>
        <DialogContent className="max-w-sm">
          <DialogHeader><DialogTitle className="text-sm">{editingGroup ? "그룹 수정" : "그룹 만들기"}</DialogTitle></DialogHeader>
          <div className="space-y-3 pt-1">
            <div>
              <Label className="text-[11px]">그룹 이름</Label>
              <Input value={groupForm.name} onChange={(e) => setGroupForm({ ...groupForm, name: e.target.value })} placeholder="예: PLM 분석 에이전트" className="mt-1 h-8 text-xs" />
            </div>
            <div>
              <Label className="text-[11px]">설명</Label>
              <Input value={groupForm.description} onChange={(e) => setGroupForm({ ...groupForm, description: e.target.value })} placeholder="그룹 목적" className="mt-1 h-8 text-xs" />
            </div>
            <div>
              <Label className="text-[11px] mb-1.5 block">실행 모드</Label>
              <div className="grid grid-cols-3 gap-1.5">
                {EXEC_MODES.map((mode) => (
                  <button
                    key={mode.value}
                    type="button"
                    onClick={() => setGroupForm({ ...groupForm, execution_mode: mode.value })}
                    className={`flex flex-col items-center gap-1 rounded-lg border-2 p-2 transition-all ${
                      groupForm.execution_mode === mode.value ? "border-primary bg-primary/5" : "border-border hover:border-primary/30"
                    }`}
                  >
                    <mode.icon className={`h-4 w-4 ${groupForm.execution_mode === mode.value ? "text-primary" : "text-muted-foreground"}`} />
                    <span className="text-[10px] font-semibold">{mode.label}</span>
                    <span className="text-[9px] text-muted-foreground">{mode.desc}</span>
                  </button>
                ))}
              </div>
            </div>
            <div className="flex justify-end gap-2">
              <Button variant="outline" size="sm" className="h-7 text-xs" onClick={() => setGroupModalOpen(false)}>취소</Button>
              <Button size="sm" className="h-7 text-xs" onClick={handleSaveGroup} disabled={saving}>
                {saving && <Loader2 className="mr-1 h-3 w-3 animate-spin" />}{editingGroup ? "수정" : "만들기"}
              </Button>
            </div>
          </div>
        </DialogContent>
      </Dialog>

      {/* 다중 에이전트 추가 모달 */}
      <Dialog open={memberModalOpen} onOpenChange={setMemberModalOpen}>
        <DialogContent className="max-w-2xl max-h-[85vh] overflow-y-auto">
          <DialogHeader><DialogTitle className="text-sm">에이전트 추가 ({selectedAgents.length}개 선택)</DialogTitle></DialogHeader>
          <div className="space-y-4 pt-1">
            <div>
              <Label className="text-[11px] mb-1.5 block">에이전트 선택 (여러 개 가능)</Label>
              <div className="grid grid-cols-1 gap-1.5 sm:grid-cols-2 max-h-48 overflow-auto rounded-lg border p-2">
                {activeAgents.map((a) => {
                  const isSelected = selectedAgents.some((s) => s.agent_id === a.id);
                  return (
                    <button
                      key={a.id}
                      className={`flex items-center gap-2 rounded-md border p-2 text-left transition-all ${isSelected ? "border-primary bg-primary/5" : "hover:bg-accent"}`}
                      onClick={() => toggleAgentSelection(a.id, a.name)}
                    >
                      <div className={`flex h-4 w-4 items-center justify-center rounded border ${isSelected ? "bg-primary border-primary text-primary-foreground" : "border-muted-foreground/30"}`}>
                        {isSelected && <Check className="h-3 w-3" />}
                      </div>
                      <div className="min-w-0 flex-1">
                        <p className="truncate text-xs font-medium">{a.name}</p>
                        <p className="truncate text-[10px] text-muted-foreground font-mono">{a.model}</p>
                      </div>
                    </button>
                  );
                })}
              </div>
            </div>

            {selectedAgents.length > 0 && (
              <div className="space-y-3">
                <Label className="text-[11px]">에이전트별 역할 설정</Label>
                {selectedAgents.map((sa, idx) => {
                  const agentInfo = agents.find((a) => a.id === sa.agent_id);
                  return (
                    <div key={sa.agent_id} className="rounded-lg border bg-card p-3 space-y-2">
                      <div className="flex items-center justify-between">
                        <div className="flex items-center gap-2">
                          <span className="flex h-5 w-5 items-center justify-center rounded-full bg-primary text-[10px] font-bold text-primary-foreground">{idx + 1}</span>
                          <Bot className="h-3.5 w-3.5 text-primary" />
                          <span className="text-xs font-semibold">{agentInfo?.name || "에이전트"}</span>
                          <span className="text-[9px] font-mono text-muted-foreground">{agentInfo?.model}</span>
                        </div>
                        <Button variant="ghost" size="sm" className="h-5 w-5 p-0 text-destructive" onClick={() => toggleAgentSelection(sa.agent_id, "")}>
                          <X className="h-3 w-3" />
                        </Button>
                      </div>

                      <Input
                        value={sa.role_name}
                        onChange={(e) => updateSelectedAgentRole(sa.agent_id, e.target.value)}
                        placeholder="이 그룹에서의 역할 (예: 매출 데이터 분석)"
                        className="h-7 text-xs"
                      />

                      <div className="flex flex-wrap gap-1">
                        {sa.connectors.map((conn, ci) => {
                          const Icon = CONNECTOR_ICONS[conn.type] || Database;
                          const color = CONNECTOR_COLORS[conn.type] || "bg-gray-100 text-gray-700";
                          return (
                            <span key={ci} className={`flex items-center gap-0.5 rounded-full px-2 py-0.5 text-[9px] font-medium ${color}`}>
                              <Icon className="h-2.5 w-2.5" />{conn.name}
                              <button onClick={() => removeConnectorFromAgent(sa.agent_id, ci)} className="ml-0.5 hover:text-destructive"><X className="h-2.5 w-2.5" /></button>
                            </span>
                          );
                        })}
                        <Select onValueChange={(v) => {
                          const conn = connectors.find((c) => `${c.type}-${c.connection_id}` === v);
                          if (conn) addConnectorToAgent(sa.agent_id, conn);
                        }}>
                          <SelectTrigger className="h-5 w-auto border-dashed px-1.5 text-[9px]">
                            <Plus className="h-2.5 w-2.5 mr-0.5" />커넥터
                          </SelectTrigger>
                          <SelectContent>
                            {connectors.map((conn) => {
                              const Icon = CONNECTOR_ICONS[conn.type] || Database;
                              return (
                                <SelectItem key={`${conn.type}-${conn.connection_id}`} value={`${conn.type}-${conn.connection_id}`} className="text-xs">
                                  <div className="flex items-center gap-1.5">
                                    <Icon className="h-3 w-3" />
                                    {conn.name}
                                    <span className="text-[10px] text-muted-foreground">{conn.type}</span>
                                  </div>
                                </SelectItem>
                              );
                            })}
                          </SelectContent>
                        </Select>
                      </div>
                    </div>
                  );
                })}
              </div>
            )}

            <div className="flex justify-end gap-2 pt-2 border-t">
              <Button variant="outline" size="sm" className="h-7 text-xs" onClick={() => setMemberModalOpen(false)}>취소</Button>
              <Button size="sm" className="h-7 text-xs" onClick={handleSaveMembers} disabled={saving || selectedAgents.length === 0}>
                {saving && <Loader2 className="mr-1 h-3 w-3 animate-spin" />}
                {selectedAgents.length}개 에이전트 추가
              </Button>
            </div>
          </div>
        </DialogContent>
      </Dialog>
    </div>
  );
}

interface MemberCardProps {
  member: any;
  connectors: any[];
  onRemove: () => void;
  onAddConnector: (conn: any) => void;
  onRemoveConnector: (idx: number) => void;
  onSplit?: () => void;
}

function MemberCard({ member, connectors, onRemove, onAddConnector, onRemoveConnector, onSplit }: MemberCardProps) {
  return (
    <div className="rounded-lg border bg-card p-3 transition-all hover:shadow-sm">
      <MemberCardContent member={member} connectors={connectors} onRemove={onRemove} onAddConnector={onAddConnector} onRemoveConnector={onRemoveConnector} onSplit={onSplit} />
    </div>
  );
}

function SortableMemberCard({ member, index, connectors, onRemove, onAddConnector, onRemoveConnector, onSplit }: MemberCardProps & { index: number }) {
  const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({ id: String(member.id) });
  const style = {
    transform: CSS.Transform.toString(transform),
    transition,
    opacity: isDragging ? 0.5 : 1,
    zIndex: isDragging ? 50 : "auto" as any,
  };

  return (
    <div ref={setNodeRef} style={style} className={`rounded-lg border bg-card p-3 transition-all ${isDragging ? "shadow-lg ring-2 ring-primary/30" : "hover:shadow-sm"}`}>
      <div className="flex items-start gap-2">
        <button {...attributes} {...listeners} className="mt-0.5 flex h-5 w-5 shrink-0 cursor-grab items-center justify-center rounded text-muted-foreground hover:bg-accent active:cursor-grabbing">
          <GripVertical className="h-3.5 w-3.5" />
        </button>
        <div className="min-w-0 flex-1">
          <MemberCardContent member={member} connectors={connectors} onRemove={onRemove} onAddConnector={onAddConnector} onRemoveConnector={onRemoveConnector} onSplit={onSplit} />
        </div>
      </div>
    </div>
  );
}

const CONNECTOR_TYPE_OPTIONS = [
  { type: "database", label: "데이터베이스", icon: Database, color: "text-blue-500" },
  { type: "rest_api", label: "REST API", icon: Globe, color: "text-green-500" },
  { type: "plc", label: "장비 (PLC)", icon: Cpu, color: "text-purple-500" },
  { type: "crawler", label: "크롤링", icon: Bug, color: "text-rose-500" },
  { type: "file", label: "파일", icon: FileText, color: "text-amber-500" },
];

function MemberCardContent({ member, connectors, onRemove, onAddConnector, onRemoveConnector, onSplit }: MemberCardProps) {
  const [pickerOpen, setPickerOpen] = useState(false);
  const [selectedType, setSelectedType] = useState<string | null>(null);
  const memberConnectors = safeArray<any>(member.connectors);

  const filteredConnectors = selectedType
    ? connectors.filter((c) => c.type === selectedType)
    : [];

  return (
    <div>
      <div className="flex items-start justify-between gap-1">
        <div className="min-w-0 flex-1">
          <div className="flex flex-wrap items-center gap-1 min-w-0">
            <Bot className="h-3.5 w-3.5 text-primary shrink-0" />
            <span className="text-xs font-semibold truncate min-w-0 max-w-full" title={member.role_name}>{member.role_name}</span>
            <Badge variant="outline" className="h-4 text-[9px] shrink-0 max-w-[140px] truncate inline-block whitespace-nowrap" title={member.agent_name}>{member.agent_name || "에이전트"}</Badge>
          </div>
          <p className="mt-0.5 ml-5 text-[10px] text-muted-foreground font-mono truncate" title={member.agent_model}>{member.agent_model}</p>
        </div>
        <div className="flex shrink-0 items-center gap-0.5">
          {onSplit && (
            <button
              className="flex h-5 w-5 items-center justify-center rounded text-amber-600 hover:bg-amber-50 dark:text-amber-500 dark:hover:bg-amber-950/30"
              onClick={onSplit}
              title="이 에이전트를 다음 스텝으로 분리"
            >
              <Split className="h-3 w-3" />
            </button>
          )}
          <button className="flex h-5 w-5 items-center justify-center rounded text-destructive hover:bg-destructive/10" onClick={onRemove}>
            <Trash2 className="h-3 w-3" />
          </button>
        </div>
      </div>

      <div className="mt-2 ml-5 flex flex-wrap items-center gap-1">
        {memberConnectors.map((conn: any, ci: number) => {
          const Icon = CONNECTOR_ICONS[conn.type] || Database;
          const color = CONNECTOR_COLORS[conn.type] || "bg-gray-100 text-gray-700";
          return (
            <span key={ci} className={`flex items-center gap-0.5 rounded-full px-1.5 py-0.5 text-[9px] font-medium ${color}`}>
              <Icon className="h-2.5 w-2.5" />{conn.name}
              <button onClick={() => onRemoveConnector(ci)} className="ml-0.5 hover:text-destructive"><X className="h-2.5 w-2.5" /></button>
            </span>
          );
        })}

        <button
          onClick={() => { setPickerOpen(!pickerOpen); setSelectedType(null); }}
          className="flex items-center gap-0.5 rounded-full border border-dashed px-1.5 py-0.5 text-[9px] text-muted-foreground transition-colors hover:border-primary hover:text-primary"
        >
          <Plus className="h-2.5 w-2.5" />연결
        </button>
      </div>

      {pickerOpen && (
        <div className="mt-2 ml-5 rounded-lg border bg-background p-2 shadow-sm">
          {!selectedType ? (
            <div>
              <p className="mb-1.5 text-[10px] font-semibold text-muted-foreground">데이터 소스 유형</p>
              <div className="grid grid-cols-3 gap-1">
                {CONNECTOR_TYPE_OPTIONS.map((opt) => {
                  const count = connectors.filter((c) => c.type === opt.type).length;
                  return (
                    <button
                      key={opt.type}
                      disabled={count === 0}
                      className={`flex flex-col items-center gap-1 rounded-md border p-2 text-center transition-all ${count > 0 ? "hover:border-primary/40 hover:bg-primary/5" : "opacity-30"}`}
                      onClick={() => setSelectedType(opt.type)}
                    >
                      <opt.icon className={`h-4 w-4 ${opt.color}`} />
                      <span className="text-[9px] font-medium">{opt.label}</span>
                      <span className="text-[8px] text-muted-foreground">{count}개</span>
                    </button>
                  );
                })}
              </div>
            </div>
          ) : (
            <div>
              <div className="mb-1.5 flex items-center justify-between">
                <button onClick={() => setSelectedType(null)} className="flex items-center gap-1 text-[10px] text-primary hover:underline">
                  <ArrowDown className="h-3 w-3 rotate-90" />뒤로
                </button>
                <p className="text-[10px] font-semibold text-muted-foreground">
                  {CONNECTOR_TYPE_OPTIONS.find((o) => o.type === selectedType)?.label} 선택
                </p>
              </div>
              <div className="max-h-32 space-y-0.5 overflow-auto">
                {filteredConnectors.length === 0 ? (
                  <p className="py-3 text-center text-[10px] text-muted-foreground">등록된 항목이 없습니다</p>
                ) : (
                  filteredConnectors.map((conn) => {
                    const Icon = CONNECTOR_ICONS[conn.type] || Database;
                    const alreadyAdded = memberConnectors.some((mc: any) => mc.connection_id === conn.connection_id && mc.type === conn.type);
                    return (
                      <button
                        key={`${conn.type}-${conn.connection_id}`}
                        disabled={alreadyAdded}
                        className={`flex w-full items-center gap-2 rounded-md px-2 py-1.5 text-left text-xs transition-colors ${alreadyAdded ? "opacity-40" : "hover:bg-accent"}`}
                        onClick={() => {
                          onAddConnector(conn);
                          setPickerOpen(false);
                          setSelectedType(null);
                        }}
                      >
                        <Icon className="h-3.5 w-3.5 text-muted-foreground" />
                        <span className="flex-1 font-medium">{conn.name}</span>
                        {conn.database_name && <span className="text-[10px] text-muted-foreground">{conn.database_name}</span>}
                        {conn.base_url && <span className="truncate text-[10px] text-muted-foreground max-w-[120px]">{conn.base_url}</span>}
                        {alreadyAdded && <span className="text-[9px] text-muted-foreground">연결됨</span>}
                      </button>
                    );
                  })
                )}
              </div>
            </div>
          )}
          <button onClick={() => { setPickerOpen(false); setSelectedType(null); }} className="mt-1.5 w-full rounded py-1 text-[10px] text-muted-foreground hover:bg-muted">
            닫기
          </button>
        </div>
      )}
    </div>
  );
}
