import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import type { AxiosError } from "axios";
import {
  ArrowRight,
  Briefcase,
  Building2,
  ChevronDown,
  ChevronRight,
  Download,
  ExternalLink,
  FolderOpen,
  LayoutDashboard,
  MoreHorizontal,
  Network,
  Plus,
  RefreshCw,
  Search,
  Settings,
  Trash2,
  UserCircle,
  UserPlus,
  Users,
} from "lucide-react";
import * as React from "react";
import { useMemo, useState } from "react";
import { Link, useNavigate, useParams } from "react-router-dom";
import { Badge } from "../../../components/ui/badge";
import { Button } from "../../../components/ui/button";
import {
  Card,
  CardContent,
  CardDescription,
  CardHeader,
  CardTitle,
} from "../../../components/ui/card";
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
} from "../../../components/ui/dialog";
import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuLabel,
  DropdownMenuSeparator,
  DropdownMenuTrigger,
} from "../../../components/ui/dropdown-menu";
import { Input } from "../../../components/ui/input";
import { ScrollArea } from "../../../components/ui/scroll-area";
import {
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableHeader,
  TableRow,
} from "../../../components/ui/table";
import { toast } from "../../../components/ui/use-toast";
import {
  bulkUpdateUsers,
  exportTenantsCSV,
  exportUsersCSV,
  fetchAllTenants,
  fetchUsers,
  type TenantSummary,
  type UserSummary,
  updateTenant,
  updateUser,
} from "../../../lib/adminApi";
import { t } from "../../../lib/i18n";
import { buildTenantFullTree, type TenantNode } from "../../../lib/tenantTree";
import {
  buildAuthenticatedOrgChartUserMultiPickerUrl,
  parseOrgChartUserSelections,
} from "../../users/orgChartPicker";

// --- Icons & Helpers ---
const getTenantIcon = (type?: string) => {
  switch (type?.toUpperCase()) {
    case "COMPANY_GROUP":
      return Briefcase;
    case "PERSONAL":
      return UserCircle;
    case "ORGANIZATION":
    case "USER_GROUP":
      return Network;
    default:
      return Building2;
  }
};

// --- Components ---

const SidebarNode: React.FC<{
  node: TenantNode;
  level: number;
  selectedId: string;
  onSelect: (id: string) => void;
  searchTerm: string;
}> = ({ node, level, selectedId, onSelect, searchTerm }) => {
  const [isExpanded, setIsExpanded] = useState(true);
  const hasChildren = node.children && node.children.length > 0;
  const isSelected = selectedId === node.id;
  const TypeIcon = getTenantIcon(node.type);

  // Auto-expand on search
  React.useEffect(() => {
    if (searchTerm) {
      const matchInDescendants = (n: TenantNode): boolean => {
        return n.children.some(
          (c) =>
            c.name.toLowerCase().includes(searchTerm.toLowerCase()) ||
            matchInDescendants(c),
        );
      };
      if (matchInDescendants(node)) setIsExpanded(true);
    }
  }, [searchTerm, node]);

  const isMatching =
    searchTerm && node.name.toLowerCase().includes(searchTerm.toLowerCase());

  return (
    <div className="flex flex-col">
      <button
        type="button"
        className={`w-full text-left flex items-center group px-2 py-1.5 rounded-md cursor-pointer transition-colors ${
          isSelected
            ? "bg-primary text-primary-foreground font-semibold"
            : "hover:bg-muted/60 text-muted-foreground hover:text-foreground"
        } ${isMatching ? "ring-1 ring-primary/30 bg-primary/5" : ""}`}
        onClick={() => {
          onSelect(node.id);
          if (hasChildren) setIsExpanded(!isExpanded);
        }}
      >
        <div className="flex items-center flex-1 min-w-0">
          {/* Indent & Expander */}
          <div style={{ width: `${level * 1.2}rem` }} className="shrink-0" />
          <div className="w-5 h-5 flex items-center justify-center mr-1">
            {hasChildren ? (
              <span className="rounded p-0.5">
                {isExpanded ? (
                  <ChevronDown size={14} />
                ) : (
                  <ChevronRight size={14} />
                )}
              </span>
            ) : (
              level > 0 && <div className="w-1 h-1 rounded-full bg-border" />
            )}
          </div>

          <TypeIcon
            size={16}
            className={`shrink-0 mr-2 ${isSelected ? "text-primary-foreground" : "text-primary/70"}`}
          />
          <span className="text-sm truncate">{node.name}</span>
        </div>

        <Badge
          variant={isSelected ? "secondary" : "outline"}
          className={`ml-2 text-[10px] px-1 h-4 min-w-[1.5rem] justify-center ${
            isSelected ? "" : "opacity-60"
          }`}
        >
          {node.recursiveMemberCount}
        </Badge>
      </button>

      {isExpanded && hasChildren && (
        <div className="flex flex-col">
          {node.children.map((child) => (
            <SidebarNode
              key={child.id}
              node={child}
              level={level + 1}
              selectedId={selectedId}
              onSelect={onSelect}
              searchTerm={searchTerm}
            />
          ))}
        </div>
      )}
    </div>
  );
};

const MemberTable: React.FC<{
  tenantSlug: string;
  onRefreshTrigger?: number;
  allTenants?: TenantSummary[];
}> = ({ tenantSlug, onRefreshTrigger, allTenants }) => {
  const queryClient = useQueryClient();
  const { data, isLoading, refetch } = useQuery({
    queryKey: ["tenant-members-v2", tenantSlug, onRefreshTrigger],
    queryFn: () => fetchUsers(100, 0, undefined, tenantSlug),
    enabled: !!tenantSlug,
  });

  const members = data?.items ?? [];

  const [isMoveOpen, setIsMoveOpen] = useState(false);
  const [selectedUser, setSelectedUser] = useState<UserSummary | null>(null);
  const [targetTenantSlug, setTargetTenantSlug] = useState("");
  const [searchTenant, setSearchTenant] = useState("");

  const moveMutation = useMutation({
    mutationFn: (newSlug: string) => {
      if (!selectedUser) throw new Error("No user selected");
      return updateUser(selectedUser.id, { tenantSlug: newSlug });
    },
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ["tenants-full-tree-v2"] });
      toast.success(
        t("msg.info.saved_success", "사용자 조직이 변경되었습니다."),
      );
      setIsMoveOpen(false);
      setSelectedUser(null);
      refetch();
    },
    onError: () => toast.error(t("msg.common.error", "오류가 발생했습니다.")),
  });

  const removeMutation = useMutation({
    mutationFn: (userId: string) =>
      updateUser(userId, { tenantSlug, isRemoveTenant: true }),
    onSuccess: (_result, userId) => {
      queryClient.invalidateQueries({ queryKey: ["tenants-full-tree-v2"] });
      queryClient.invalidateQueries({ queryKey: ["users"] });
      queryClient.invalidateQueries({ queryKey: ["user", userId] });
      toast.success(t("msg.info.saved_success", "조직에서 제외되었습니다."));
      refetch();
    },
    onError: () => toast.error(t("msg.common.error", "오류가 발생했습니다.")),
  });

  const handleMoveClick = (user: UserSummary) => {
    setSelectedUser(user);
    setTargetTenantSlug("");
    setIsMoveOpen(true);
  };

  const filteredTenants = React.useMemo(() => {
    if (!allTenants) return [];
    if (!searchTenant) return allTenants;
    return allTenants.filter(
      (t) =>
        t.name.toLowerCase().includes(searchTenant.toLowerCase()) ||
        t.slug.toLowerCase().includes(searchTenant.toLowerCase()),
    );
  }, [allTenants, searchTenant]);

  if (isLoading)
    return (
      <div className="py-20 text-center text-muted-foreground animate-pulse">
        {t("msg.common.loading", "멤버 정보를 불러오는 중...")}
      </div>
    );

  if (members.length === 0)
    return (
      <div className="py-20 flex flex-col items-center justify-center text-muted-foreground opacity-50 border-2 border-dashed rounded-lg">
        <Users size={48} className="mb-4" />
        <p>
          {t("msg.admin.users.list.empty", "이 조직에 소속된 멤버가 없습니다.")}
        </p>
      </div>
    );

  return (
    <div className="border rounded-md overflow-hidden bg-[var(--color-panel)]">
      <Table>
        <TableHeader className="bg-muted/30">
          <TableRow>
            <TableHead>{t("ui.admin.users.table.name", "이름")}</TableHead>
            <TableHead>{t("ui.admin.users.table.email", "이메일")}</TableHead>
            <TableHead className="text-right">
              {t("ui.admin.users.table.role", "역할")}
            </TableHead>
            <TableHead className="w-[50px]" />
          </TableRow>
        </TableHeader>
        <TableBody>
          {members.map((user) => (
            <TableRow
              key={user.id}
              className="hover:bg-muted/30 transition-colors"
            >
              <TableCell className="font-medium">{user.name}</TableCell>
              <TableCell className="text-xs font-mono">{user.email}</TableCell>
              <TableCell className="text-right">
                <Badge
                  variant="secondary"
                  className="text-[10px] font-bold uppercase"
                >
                  {user.role}
                </Badge>
              </TableCell>
              <TableCell>
                <DropdownMenu>
                  <DropdownMenuTrigger asChild>
                    <Button
                      variant="ghost"
                      size="icon"
                      className="h-8 w-8"
                      data-testid={`tenant-org-member-actions-${user.id}`}
                    >
                      <MoreHorizontal size={14} />
                    </Button>
                  </DropdownMenuTrigger>
                  <DropdownMenuContent align="end">
                    <DropdownMenuItem asChild>
                      <Link to={`/users/${user.id}`}>
                        <ExternalLink size={14} className="mr-2" />
                        {t("ui.common.detail", "상세보기")}
                      </Link>
                    </DropdownMenuItem>
                    <DropdownMenuSeparator />
                    <DropdownMenuItem onClick={() => handleMoveClick(user)}>
                      <ArrowRight size={14} className="mr-2" />
                      {t("ui.common.move_org", "타 조직으로 이동")}
                    </DropdownMenuItem>
                    <DropdownMenuItem
                      data-testid={`tenant-org-member-remove-${user.id}`}
                      onClick={() => {
                        if (
                          window.confirm(
                            t(
                              "msg.admin.users.confirm_remove_org",
                              "이 조직에서 사용자를 제외하시겠습니까?",
                            ),
                          )
                        ) {
                          removeMutation.mutate(user.id);
                        }
                      }}
                    >
                      <FolderOpen size={14} className="mr-2" />
                      {t("ui.common.remove_org", "조직에서 제외")}
                    </DropdownMenuItem>
                  </DropdownMenuContent>
                </DropdownMenu>
              </TableCell>
            </TableRow>
          ))}
        </TableBody>
      </Table>

      <Dialog open={isMoveOpen} onOpenChange={setIsMoveOpen}>
        <DialogContent className="sm:max-w-[400px]">
          <DialogHeader>
            <DialogTitle>
              {t("ui.common.move_org", "타 조직으로 이동")}
            </DialogTitle>
            <DialogDescription>
              {selectedUser?.name} 사용자를 이동할 타 조직을 선택하세요.
            </DialogDescription>
          </DialogHeader>
          <div className="space-y-4 py-4">
            <Input
              placeholder={t("ui.common.search", "조직 검색...")}
              value={searchTenant}
              onChange={(e) => setSearchTenant(e.target.value)}
            />
            <ScrollArea className="h-48 border rounded-md p-2">
              <div className="space-y-1">
                {filteredTenants.map((tItem) => (
                  <Button
                    key={tItem.id}
                    variant={
                      targetTenantSlug === tItem.slug ? "secondary" : "ghost"
                    }
                    className="w-full justify-start text-sm"
                    onClick={() => setTargetTenantSlug(tItem.slug)}
                  >
                    {React.createElement(getTenantIcon(tItem.type), {
                      size: 14,
                      className: "mr-2 opacity-70",
                    })}
                    <span>{tItem.name}</span>
                    <span className="ml-2 text-[10px] text-muted-foreground opacity-50">
                      {tItem.slug}
                    </span>
                  </Button>
                ))}
                {filteredTenants.length === 0 && (
                  <div className="py-4 text-center text-sm text-muted-foreground">
                    {t("msg.common.no_results", "검색 결과가 없습니다.")}
                  </div>
                )}
              </div>
            </ScrollArea>
          </div>
          <DialogFooter>
            <Button variant="outline" onClick={() => setIsMoveOpen(false)}>
              {t("ui.common.cancel", "취소")}
            </Button>
            <Button
              onClick={() => moveMutation.mutate(targetTenantSlug)}
              disabled={!targetTenantSlug || moveMutation.isPending}
            >
              {moveMutation.isPending ? "..." : t("ui.common.move", "이동")}
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>
    </div>
  );
};

// --- Main Component ---

function TenantUserGroupsTab() {
  const { tenantId } = useParams<{ tenantId: string }>();
  const _navigate = useNavigate();
  const queryClient = useQueryClient();

  const [selectedNodeId, setSelectedNodeId] = useState<string>(tenantId || "");
  const [treeSearch, setTreeSearch] = useState("");
  const [refreshMembersCount, setRefreshMembersCount] = useState(0);

  const [isUserAddOpen, setIsUserAddOpen] = useState(false);
  const [isAddExistingOpen, setIsAddExistingOpen] = useState(false);
  const [existingSearch, setExistingSearch] = useState("");

  const exportChildrenMutation = useMutation({
    mutationFn: (parentId: string) => exportTenantsCSV(true, parentId),
    onSuccess: ({ blob, filename }) => {
      const url = window.URL.createObjectURL(blob);
      const link = document.createElement("a");
      link.href = url;
      link.download = filename;
      document.body.appendChild(link);
      link.click();
      link.remove();
      window.URL.revokeObjectURL(url);
    },
    onError: () =>
      toast.error(
        t("msg.admin.tenants.export_error", "테넌트 내보내기에 실패했습니다."),
      ),
  });

  const exportCurrentMembersMutation = useMutation({
    mutationFn: (tenantSlug: string) => exportUsersCSV("", tenantSlug, false),
    onSuccess: ({ blob, filename }) => {
      const url = window.URL.createObjectURL(blob);
      const link = document.createElement("a");
      link.href = url;
      link.download = filename;
      document.body.appendChild(link);
      link.click();
      link.remove();
      window.URL.revokeObjectURL(url);
    },
    onError: () =>
      toast.error(
        t("msg.admin.users.export_error", "사용자 내보내기에 실패했습니다."),
      ),
  });

  // Data Fetching
  const {
    data: allTenantsData,
    isLoading: isTenantsLoading,
    refetch: refetchTree,
  } = useQuery({
    queryKey: ["tenants-full-tree-v2"],
    queryFn: () => fetchAllTenants(),
  });

  const { currentBase } = useMemo(() => {
    const allItems = allTenantsData?.items ?? [];
    return buildTenantFullTree(allItems, tenantId);
  }, [allTenantsData, tenantId]);

  const selectedNode = useMemo(() => {
    // Find selected node in the built tree
    const findNode = (nodes: TenantNode[], id: string): TenantNode | null => {
      if (!currentBase) return null;
      if (currentBase.id === id) return currentBase;

      for (const node of nodes) {
        if (node.id === id) return node;
        if (node.children.length > 0) {
          const found = findNode(node.children, id);
          if (found) return found;
        }
      }
      return null;
    };

    if (!currentBase) return null;
    return findNode(currentBase.children, selectedNodeId) || currentBase;
  }, [currentBase, selectedNodeId]);

  // Mutations
  const updateParentMutation = useMutation({
    mutationFn: ({
      id,
      parentId,
    }: {
      id: string;
      parentId: string | undefined;
    }) => updateTenant(id, { parentId: parentId || "" }),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ["tenants-full-tree-v2"] });
      toast.success(
        t("msg.info.saved_success", "조직 구조가 업데이트되었습니다."),
      );
      setIsAddExistingOpen(false);
    },
  });

  const handleRemoveNode = (id: string, name: string) => {
    if (
      window.confirm(
        t(
          "msg.admin.tenants.remove_sub_confirm",
          `${name} 조직을 하위에서 제외할까요?`,
          { name },
        ),
      )
    ) {
      updateParentMutation.mutate({ id, parentId: undefined });
      if (selectedNodeId === id) setSelectedNodeId(tenantId || "");
    }
  };

  if (isTenantsLoading)
    return (
      <div className="p-12 text-center text-muted-foreground animate-pulse">
        {t("msg.common.loading", "조직 정보를 불러오는 중...")}
      </div>
    );
  if (!currentBase)
    return (
      <div className="p-12 text-center text-muted-foreground">
        테넌트를 찾을 수 없습니다.
      </div>
    );

  const candidates = (allTenantsData?.items ?? []).filter(
    (t) =>
      t.id !== tenantId &&
      t.parentId !== tenantId &&
      (existingSearch === "" ||
        t.name.toLowerCase().includes(existingSearch.toLowerCase()) ||
        t.slug.toLowerCase().includes(existingSearch.toLowerCase())),
  );

  return (
    <div className="flex h-[calc(100vh-theme(spacing.32))] gap-6 mt-6 overflow-hidden">
      {/* --- Left Panel: Sidebar Tree --- */}
      <Card className="w-80 flex flex-col shrink-0 border-none shadow-sm bg-[var(--color-panel)] overflow-hidden">
        <CardHeader className="p-4 pb-2 space-y-3">
          <div className="flex items-center justify-between">
            <CardTitle className="text-sm font-bold flex items-center gap-2">
              <Network size={16} className="text-primary" />
              조직도
            </CardTitle>
            <Button
              variant="ghost"
              size="icon"
              className="h-7 w-7"
              onClick={() => refetchTree()}
            >
              <RefreshCw size={14} />
            </Button>
          </div>
          <div className="relative">
            <Search className="absolute left-2.5 top-2.5 h-3.5 w-3.5 text-muted-foreground" />
            <Input
              placeholder={t("ui.common.search", "조직 검색...")}
              className="pl-8 h-8 text-xs bg-muted/40"
              value={treeSearch}
              onChange={(e) => setTreeSearch(e.target.value)}
            />
          </div>
        </CardHeader>
        <CardContent className="flex-1 overflow-hidden p-2">
          <ScrollArea className="h-full pr-2">
            <SidebarNode
              node={currentBase}
              level={0}
              selectedId={selectedNodeId}
              onSelect={setSelectedNodeId}
              searchTerm={treeSearch}
            />
          </ScrollArea>
        </CardContent>
        <div className="p-3 border-t bg-muted/5">
          <Button
            variant="outline"
            size="sm"
            className="w-full text-xs h-8"
            onClick={() => setIsAddExistingOpen(true)}
          >
            <Plus size={14} className="mr-1" />
            {t("ui.admin.tenants.sub.add_existing", "기존 테넌트 연결")}
          </Button>
        </div>
      </Card>

      {/* --- Right Panel: Selected Node Content --- */}
      <div className="flex-1 flex flex-col min-w-0">
        {selectedNode ? (
          <Card className="flex-1 flex flex-col border-none shadow-sm bg-[var(--color-panel)] overflow-hidden">
            <CardHeader className="border-b bg-muted/5 py-4 flex flex-row items-center justify-between">
              <div className="flex items-center gap-3">
                <div className="p-2 rounded-lg bg-primary/10 text-primary">
                  {React.createElement(getTenantIcon(selectedNode.type), {
                    size: 24,
                  })}
                </div>
                <div>
                  <div className="flex items-center gap-2">
                    <CardTitle className="text-xl font-bold">
                      {selectedNode.name}
                    </CardTitle>
                    <Badge
                      variant="outline"
                      className="text-[10px] font-mono opacity-60"
                    >
                      {selectedNode.slug}
                    </Badge>
                  </div>
                  <div className="text-sm text-muted-foreground flex items-center gap-2 mt-0.5">
                    <span className="flex items-center gap-1">
                      <Users size={12} /> {selectedNode.recursiveMemberCount}{" "}
                      {t("ui.admin.tenants.table.members", "명")}
                    </span>
                    <span className="opacity-30">|</span>
                    <Badge variant="secondary" className="text-[10px] h-4">
                      {t(
                        `domain.tenant_type.${selectedNode.type.toLowerCase()}`,
                        selectedNode.type,
                      )}
                    </Badge>
                  </div>
                </div>
              </div>

              <div className="flex items-center gap-2">
                <Button
                  type="button"
                  variant="outline"
                  size="sm"
                  onClick={() => setIsUserAddOpen(true)}
                  data-testid="tenant-org-member-add-open-btn"
                >
                  <UserPlus size={16} className="mr-2" />
                  {t("ui.admin.users.list.add", "멤버 추가")}
                </Button>
                <Button
                  variant="outline"
                  size="sm"
                  onClick={() =>
                    exportCurrentMembersMutation.mutate(selectedNode.slug)
                  }
                  disabled={
                    !selectedNode.slug || exportCurrentMembersMutation.isPending
                  }
                  data-testid="tenant-current-users-export-btn"
                >
                  <Download size={16} className="mr-2" />
                  {t("ui.admin.tenants.members.export", "선택 조직 사용자 CSV")}
                </Button>
                <Button
                  variant="outline"
                  size="sm"
                  onClick={() => exportChildrenMutation.mutate(selectedNode.id)}
                  disabled={exportChildrenMutation.isPending}
                  data-testid="tenant-subtree-export-btn"
                >
                  <Download size={16} className="mr-2" />
                  {t("ui.admin.tenants.sub.export", "하위 조직 CSV")}
                </Button>

                <DropdownMenu>
                  <DropdownMenuTrigger asChild>
                    <Button variant="outline" size="icon" className="h-9 w-9">
                      <Settings size={16} />
                    </Button>
                  </DropdownMenuTrigger>
                  <DropdownMenuContent align="end">
                    <DropdownMenuLabel>
                      {t("ui.common.manage", "조직 관리")}
                    </DropdownMenuLabel>
                    <DropdownMenuSeparator />
                    <DropdownMenuItem asChild>
                      <Link to={`/tenants/${selectedNode.id}`}>
                        <LayoutDashboard size={14} className="mr-2" />
                        상세 프로필로 이동
                      </Link>
                    </DropdownMenuItem>
                    {!selectedNode.parentId && (
                      <DropdownMenuItem asChild>
                        <Link to={`/tenants/new?parentId=${selectedNode.id}`}>
                          <Plus size={14} className="mr-2" />
                          {t("ui.admin.tenants.sub.add", "하위 부서 생성")}
                        </Link>
                      </DropdownMenuItem>
                    )}
                    {selectedNode.id !== tenantId && (
                      <DropdownMenuItem
                        className="text-destructive"
                        onClick={() =>
                          handleRemoveNode(selectedNode.id, selectedNode.name)
                        }
                      >
                        <Trash2 size={14} className="mr-2" />
                        {t("ui.common.remove", "조직 계층에서 제외")}
                      </DropdownMenuItem>
                    )}
                  </DropdownMenuContent>
                </DropdownMenu>
              </div>
            </CardHeader>

            <CardContent className="flex-1 overflow-hidden p-0 flex flex-col">
              <ScrollArea className="flex-1">
                <div className="p-6 space-y-8">
                  {selectedNode.children.length > 0 && (
                    <div className="space-y-4">
                      <h3 className="text-sm font-bold flex items-center gap-2">
                        <Network size={16} className="text-muted-foreground" />
                        하위 조직 ({selectedNode.children.length})
                      </h3>
                      <div className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-4">
                        {selectedNode.children?.map((child) => (
                          <Card
                            key={child.id}
                            className="cursor-pointer hover:border-primary/50 transition-colors bg-muted/20"
                            onClick={() => setSelectedNodeId(child.id)}
                          >
                            <CardHeader className="p-4 space-y-1">
                              <div className="flex items-center justify-between">
                                <div className="p-1.5 rounded bg-background">
                                  {React.createElement(
                                    getTenantIcon(child.type),
                                    {
                                      size: 14,
                                      className: "text-primary",
                                    },
                                  )}
                                </div>
                                <Badge variant="outline" className="text-[9px]">
                                  {child.recursiveMemberCount}{" "}
                                  {t("ui.admin.tenants.table.members", "명")}
                                </Badge>
                              </div>
                              <CardTitle className="text-sm">
                                {child.name}
                              </CardTitle>
                              <CardDescription className="text-[10px] truncate">
                                {child.slug}
                              </CardDescription>
                            </CardHeader>
                          </Card>
                        ))}
                      </div>
                    </div>
                  )}

                  <div className="space-y-4">
                    <h3 className="text-sm font-bold flex items-center gap-2">
                      <Users size={16} className="text-muted-foreground" />
                      {t("ui.admin.tenants.members.list_title", "소속 멤버")}
                    </h3>
                    <MemberTable
                      tenantSlug={selectedNode.slug}
                      onRefreshTrigger={refreshMembersCount}
                      allTenants={allTenantsData?.items ?? []}
                    />
                  </div>
                </div>
              </ScrollArea>
            </CardContent>
          </Card>
        ) : (
          <div className="flex-1 flex items-center justify-center text-muted-foreground opacity-30 border-2 border-dashed rounded-lg">
            <div className="text-center">
              <FolderOpen size={64} className="mx-auto mb-4" />
              <p>조직을 선택해 주세요.</p>
            </div>
          </div>
        )}
      </div>

      {/* --- Dialogs --- */}
      <UserAddDialog
        tenantSlug={selectedNode?.slug || ""}
        tenantName={selectedNode?.name || ""}
        open={isUserAddOpen}
        onOpenChange={(open) => {
          setIsUserAddOpen(open);
          if (!open) setRefreshMembersCount((prev) => prev + 1);
        }}
      />

      <Dialog open={isAddExistingOpen} onOpenChange={setIsAddExistingOpen}>
        <DialogContent className="sm:max-w-[500px]">
          <DialogHeader>
            <DialogTitle>
              {t("ui.admin.tenants.sub.add_existing", "기존 테넌트 연결")}
            </DialogTitle>
            <DialogDescription>
              기존에 생성된 테넌트를 [{currentBase.name}] 하위로 가져옵니다.
            </DialogDescription>
          </DialogHeader>
          <div className="space-y-4 py-4">
            <div className="relative">
              <Search className="absolute left-2.5 top-2.5 h-4 w-4 text-muted-foreground" />
              <Input
                placeholder="검색..."
                className="pl-9"
                value={existingSearch}
                onChange={(e) => setExistingSearch(e.target.value)}
              />
            </div>
            <ScrollArea className="h-60 border rounded-md">
              <Table>
                <TableBody>
                  {candidates?.map((tenantItem) => (
                    <TableRow
                      key={tenantItem.id}
                      className="hover:bg-muted/50 cursor-pointer"
                      onClick={() =>
                        updateParentMutation.mutate({
                          id: tenantItem.id,
                          parentId: tenantId,
                        })
                      }
                    >
                      <TableCell>
                        <div className="flex items-center gap-2">
                          {React.createElement(getTenantIcon(tenantItem.type), {
                            size: 14,
                            className: "text-muted-foreground",
                          })}
                          <div>
                            <p className="text-sm font-medium">
                              {tenantItem.name}
                            </p>
                            <p className="text-[10px] font-mono text-muted-foreground">
                              {tenantItem.slug}
                            </p>
                          </div>
                        </div>
                      </TableCell>
                      <TableCell className="text-right">
                        <Button variant="ghost" size="sm" className="h-7 px-2">
                          <Plus size={14} className="mr-1" />{" "}
                          {t("ui.common.add", "추가")}
                        </Button>
                      </TableCell>
                    </TableRow>
                  ))}
                </TableBody>
              </Table>
            </ScrollArea>
          </div>
        </DialogContent>
      </Dialog>
    </div>
  );
}

// --- Internal Support Components ---

const UserAddDialog: React.FC<{
  tenantSlug: string;
  tenantName: string;
  open: boolean;
  onOpenChange: (open: boolean) => void;
}> = ({ tenantSlug, tenantName, open, onOpenChange }) => {
  const queryClient = useQueryClient();
  const [userSearch, setUserSearch] = useState("");
  const [isSearching, setIsSearching] = useState(false);
  const [searchResults, setSearchResults] = useState<UserSummary[]>([]);
  const [queuedUsers, setQueuedUsers] = useState<UserSummary[]>([]);
  const [isSubmitting, setIsSubmitting] = useState(false);
  const orgChartMemberPickerUrl = React.useMemo(
    () =>
      buildAuthenticatedOrgChartUserMultiPickerUrl(
        import.meta.env.ORGFRONT_URL,
      ),
    [],
  );
  const queuedUserIds = React.useMemo(
    () => new Set(queuedUsers.map((user) => user.id)),
    [queuedUsers],
  );

  const handleSearch = async () => {
    if (!userSearch) return;
    setIsSearching(true);
    try {
      const res = await fetchUsers(20, 0, userSearch);
      setSearchResults(res.items);
    } catch (_err) {
      toast.error(t("msg.admin.users.list.fetch_error", "사용자 검색 실패"));
    } finally {
      setIsSearching(false);
    }
  };

  const handleAssign = async () => {
    if (queuedUsers.length === 0) return;
    setIsSubmitting(true);
    try {
      await bulkUpdateUsers({
        userIds: queuedUsers.map((user) => user.id),
        tenantSlug,
        isAddTenant: true,
      });
      queryClient.invalidateQueries({ queryKey: ["tenants-full-tree-v2"] });
      toast.success(
        t(
          "msg.admin.tenants.members.add_success",
          "{{count}}명의 구성원이 추가되었습니다.",
          { count: queuedUsers.length },
        ),
      );
      onOpenChange(false);
      resetFields();
    } catch (err) {
      const error = err as AxiosError<{ error?: string }>;
      toast.error(
        error.response?.data?.error ||
          t("msg.admin.users.detail.update_error", "배정 실패"),
      );
    } finally {
      setIsSubmitting(false);
    }
  };

  const resetFields = () => {
    setUserSearch("");
    setSearchResults([]);
    setQueuedUsers([]);
  };

  const queueUsers = React.useCallback((users: UserSummary[]) => {
    setQueuedUsers((current) => {
      const blockedIds = new Set(current.map((user) => user.id));
      const next = [...current];
      for (const user of users) {
        if (blockedIds.has(user.id)) continue;
        blockedIds.add(user.id);
        next.push(user);
      }
      return next;
    });
  }, []);

  const queueUser = (user: UserSummary) => {
    queueUsers([user]);
  };

  const removeQueuedUser = (userId: string) => {
    setQueuedUsers((current) => current.filter((user) => user.id !== userId));
  };

  React.useEffect(() => {
    if (!open) return;

    const onMessage = (event: MessageEvent) => {
      const selections = parseOrgChartUserSelections(event.data);
      if (selections.length === 0) return;

      queueUsers(
        selections.map((selection) => ({
          id: selection.id,
          name: selection.name,
          email: selection.email,
          role: "user",
          status: "active",
          createdAt: "",
          updatedAt: "",
        })),
      );
    };

    window.addEventListener("message", onMessage);
    return () => window.removeEventListener("message", onMessage);
  }, [open, queueUsers]);

  return (
    <Dialog
      open={open}
      onOpenChange={(v) => {
        onOpenChange(v);
        if (!v) resetFields();
      }}
    >
      <DialogContent className="max-w-5xl">
        <DialogHeader>
          <DialogTitle>
            {t("ui.admin.users.create.title", "멤버 추가")}
          </DialogTitle>
          <DialogDescription>
            [{tenantName}] 조직에 기존 사용자를 배정합니다.
          </DialogDescription>
        </DialogHeader>

        <div className="grid gap-4 py-4 lg:grid-cols-[minmax(0,1fr)_minmax(360px,1.2fr)]">
          <div className="space-y-3">
            <div className="flex gap-2">
              <Input
                placeholder={t(
                  "ui.admin.users.list.search_placeholder",
                  "이메일 검색...",
                )}
                value={userSearch}
                onChange={(e) => setUserSearch(e.target.value)}
                onKeyDown={(e) => e.key === "Enter" && handleSearch()}
                data-testid="tenant-org-member-search-input"
              />
              <Button
                variant="secondary"
                onClick={handleSearch}
                disabled={isSearching}
                data-testid="tenant-org-member-search-btn"
              >
                <Search size={16} />
              </Button>
            </div>
            <ScrollArea className="h-60 rounded-md border">
              <Table>
                <TableBody>
                  {searchResults?.map((user) => (
                    <TableRow
                      key={user.id}
                      data-testid={`tenant-org-member-search-result-${user.id}`}
                      className={`cursor-pointer hover:bg-muted/50 ${queuedUserIds.has(user.id) ? "bg-primary/5 opacity-60" : ""}`}
                      onClick={() => queueUser(user)}
                    >
                      <TableCell>
                        <div className="flex items-center justify-between">
                          <div>
                            <p className="text-sm font-medium">{user.name}</p>
                            <p className="text-[10px] text-muted-foreground">
                              {user.email}
                            </p>
                          </div>
                          {queuedUserIds.has(user.id) && (
                            <ChevronRight size={16} className="text-primary" />
                          )}
                        </div>
                      </TableCell>
                    </TableRow>
                  ))}
                </TableBody>
              </Table>
            </ScrollArea>
          </div>
          <div className="min-h-[360px] overflow-hidden rounded-md border">
            <iframe
              title={t(
                "ui.admin.tenants.members.org_picker_title",
                "조직도에서 구성원 선택",
              )}
              src={orgChartMemberPickerUrl}
              className="h-[420px] w-full"
              data-testid="tenant-org-member-picker-frame"
            />
          </div>
          <div
            className="min-h-16 rounded-md border bg-muted/20 p-3 lg:col-span-2"
            data-testid="tenant-org-member-add-queue"
          >
            {queuedUsers.length === 0 ? (
              <div className="flex h-10 items-center justify-center text-sm text-muted-foreground">
                {t(
                  "ui.admin.tenants.members.queue_empty",
                  "추가할 구성원을 선택하세요.",
                )}
              </div>
            ) : (
              <div className="flex flex-wrap gap-2">
                {queuedUsers.map((user) => (
                  <span
                    key={user.id}
                    className="inline-flex max-w-full items-center gap-2 rounded-md border bg-background px-2 py-1 text-sm"
                  >
                    <span className="max-w-52 truncate">{user.name}</span>
                    <button
                      type="button"
                      className="text-muted-foreground hover:text-foreground"
                      onClick={() => removeQueuedUser(user.id)}
                      aria-label={t(
                        "ui.admin.tenants.members.queue_remove",
                        "추가 명단에서 제거",
                      )}
                    >
                      <Trash2 size={14} />
                    </button>
                  </span>
                ))}
              </div>
            )}
          </div>
        </div>
        <DialogFooter>
          <Button variant="outline" onClick={() => onOpenChange(false)}>
            {t("ui.common.cancel", "취소")}
          </Button>
          <Button
            onClick={handleAssign}
            disabled={isSubmitting || queuedUsers.length === 0}
            data-testid="tenant-org-member-add-submit-btn"
          >
            {t("ui.common.add", "배정")}
          </Button>
        </DialogFooter>
      </DialogContent>
    </Dialog>
  );
};

export default TenantUserGroupsTab;
