"use client";

import React, { useCallback, useState, useEffect, useMemo } from "react";
import { cn } from "@/lib/utils";
import { Label } from "@/components/ui/label";
import { Input } from "@/components/ui/input";
import { Button } from "@/components/ui/button";
import { Checkbox } from "@/components/ui/checkbox";
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "@/components/ui/select";
import {
  AlertDialog,
  AlertDialogAction,
  AlertDialogCancel,
  AlertDialogContent,
  AlertDialogDescription,
  AlertDialogFooter,
  AlertDialogHeader,
  AlertDialogTitle,
} from "@/components/ui/alert-dialog";
import { PopComponentRegistry } from "@/lib/registry/PopComponentRegistry";
import { DataFlowAPI } from "@/lib/api/dataflow";
import { usePopAction } from "@/hooks/pop/usePopAction";
import { usePopDesignerContext } from "@/components/pop/designer/PopDesignerContext";
import { usePopEvent } from "@/hooks/pop/usePopEvent";
import {
  Save,
  Trash2,
  LogOut,
  Menu,
  ExternalLink,
  Plus,
  Check,
  X,
  Edit,
  Search,
  RefreshCw,
  Download,
  Upload,
  Send,
  Copy,
  Settings,
  ChevronDown,
  ShoppingCart,
  ShoppingBag,
  PackageCheck,
  type LucideIcon,
} from "lucide-react";
import { toast } from "sonner";
import type { CollectedDataResponse, StatusChangeRule } from "./types";
import { apiClient } from "@/lib/api/client";
import { TableCombobox } from "./pop-shared/TableCombobox";
import { ColumnCombobox } from "./pop-shared/ColumnCombobox";
import {
  fetchTableList,
  fetchTableColumns,
  type TableInfo,
  type ColumnInfo,
} from "./pop-dashboard/utils/dataFetcher";

// ========================================
// STEP 1: 타입 정의
// ========================================

/** 메인 액션 타입 (5종) */
export type ButtonActionType = "save" | "delete" | "api" | "modal" | "event";

/** 후속 액션 타입 (4종) */
export type FollowUpActionType = "event" | "refresh" | "navigate" | "close-modal";

/** 버튼 variant (shadcn 기반 4종) */
export type ButtonVariant = "default" | "secondary" | "outline" | "destructive";

/** 모달 열기 방식 */
export type ModalMode = "dropdown" | "fullscreen" | "screen-ref";

/** 확인 다이얼로그 설정 */
export interface ConfirmConfig {
  enabled: boolean;
  message?: string; // 빈값이면 기본 메시지
}

/** 후속 액션 1건 */
export interface FollowUpAction {
  type: FollowUpActionType;
  // event
  eventName?: string;
  eventPayload?: Record<string, unknown>;
  // navigate
  targetScreenId?: string;
  params?: Record<string, string>;
}

/** 드롭다운 모달 메뉴 항목 */
export interface ModalMenuItem {
  label: string;
  screenId?: string;
  action?: string; // 커스텀 이벤트명
}

/** 메인 액션 설정 */
export interface ButtonMainAction {
  type: ButtonActionType;
  // save/delete 공통
  targetTable?: string;
  // api
  apiEndpoint?: string;
  apiMethod?: "GET" | "POST" | "PUT" | "DELETE";
  // modal
  modalMode?: ModalMode;
  modalScreenId?: string;
  modalTitle?: string;
  modalItems?: ModalMenuItem[];
  // event
  eventName?: string;
  eventPayload?: Record<string, unknown>;
}

/** 프리셋 이름 */
export type ButtonPreset =
  | "save"
  | "delete"
  | "logout"
  | "menu"
  | "modal-open"
  | "cart"
  | "inbound-confirm"
  | "custom";

/** row_data 저장 모드 */
export type RowDataMode = "all" | "selected";

/** 장바구니 버튼 전용 설정 */
export interface CartButtonConfig {
  cartScreenId?: string;
  rowDataMode?: RowDataMode;
  selectedColumns?: string[];
}

/** pop-button 전체 설정 */
export interface PopButtonConfig {
  label: string;
  variant: ButtonVariant;
  icon?: string;
  iconOnly?: boolean;
  preset: ButtonPreset;
  confirm?: ConfirmConfig;
  action: ButtonMainAction;
  followUpActions?: FollowUpAction[];
  cart?: CartButtonConfig;
  statusChangeRules?: StatusChangeRule[];
  /** @deprecated inboundConfirm.statusChangeRules -> statusChangeRules로 이동 */
  inboundConfirm?: { statusChangeRules?: StatusChangeRule[] };
}

// ========================================
// 상수
// ========================================

/** 메인 액션 타입 라벨 */
const ACTION_TYPE_LABELS: Record<ButtonActionType, string> = {
  save: "저장",
  delete: "삭제",
  api: "API 호출",
  modal: "모달 열기",
  event: "이벤트 발행",
};

/** 후속 액션 타입 라벨 */
const FOLLOWUP_TYPE_LABELS: Record<FollowUpActionType, string> = {
  event: "이벤트 발행",
  refresh: "새로고침",
  navigate: "화면 이동",
  "close-modal": "모달 닫기",
};

/** variant 라벨 */
const VARIANT_LABELS: Record<ButtonVariant, string> = {
  default: "기본 (Primary)",
  secondary: "보조 (Secondary)",
  outline: "외곽선 (Outline)",
  destructive: "위험 (Destructive)",
};

/** 프리셋 라벨 */
const PRESET_LABELS: Record<ButtonPreset, string> = {
  save: "저장",
  delete: "삭제",
  logout: "로그아웃",
  menu: "메뉴 (드롭다운)",
  "modal-open": "모달 열기",
  cart: "장바구니 저장",
  "inbound-confirm": "입고 확정",
  custom: "직접 설정",
};

/** 모달 모드 라벨 */
const MODAL_MODE_LABELS: Record<ModalMode, string> = {
  dropdown: "드롭다운",
  fullscreen: "전체 모달",
  "screen-ref": "화면 선택",
};

/** API 메서드 라벨 */
const API_METHOD_LABELS: Record<string, string> = {
  GET: "GET",
  POST: "POST",
  PUT: "PUT",
  DELETE: "DELETE",
};

/** 주요 Lucide 아이콘 목록 (설정 패널용) */
const ICON_OPTIONS: { value: string; label: string }[] = [
  { value: "none", label: "없음" },
  { value: "Save", label: "저장 (Save)" },
  { value: "Trash2", label: "삭제 (Trash)" },
  { value: "LogOut", label: "로그아웃 (LogOut)" },
  { value: "Menu", label: "메뉴 (Menu)" },
  { value: "ExternalLink", label: "외부링크 (ExternalLink)" },
  { value: "Plus", label: "추가 (Plus)" },
  { value: "Check", label: "확인 (Check)" },
  { value: "X", label: "취소 (X)" },
  { value: "Edit", label: "수정 (Edit)" },
  { value: "Search", label: "검색 (Search)" },
  { value: "RefreshCw", label: "새로고침 (RefreshCw)" },
  { value: "Download", label: "다운로드 (Download)" },
  { value: "Upload", label: "업로드 (Upload)" },
  { value: "Send", label: "전송 (Send)" },
  { value: "Copy", label: "복사 (Copy)" },
  { value: "Settings", label: "설정 (Settings)" },
  { value: "ChevronDown", label: "아래 화살표 (ChevronDown)" },
  { value: "ShoppingCart", label: "장바구니 (ShoppingCart)" },
  { value: "ShoppingBag", label: "장바구니 담김 (ShoppingBag)" },
];

/** 프리셋별 기본 설정 */
const PRESET_DEFAULTS: Record<ButtonPreset, Partial<PopButtonConfig>> = {
  save: {
    label: "저장",
    variant: "default",
    icon: "Save",
    confirm: { enabled: false },
    action: { type: "save" },
  },
  delete: {
    label: "삭제",
    variant: "destructive",
    icon: "Trash2",
    confirm: { enabled: true, message: "" },
    action: { type: "delete" },
  },
  logout: {
    label: "로그아웃",
    variant: "outline",
    icon: "LogOut",
    confirm: { enabled: true, message: "로그아웃 하시겠습니까?" },
    action: {
      type: "api",
      apiEndpoint: "/api/auth/logout",
      apiMethod: "POST",
    },
  },
  menu: {
    label: "메뉴",
    variant: "secondary",
    icon: "Menu",
    confirm: { enabled: false },
    action: { type: "modal", modalMode: "dropdown" },
  },
  "modal-open": {
    label: "열기",
    variant: "outline",
    icon: "ExternalLink",
    confirm: { enabled: false },
    action: { type: "modal", modalMode: "fullscreen" },
  },
  cart: {
    label: "장바구니 저장",
    variant: "default",
    icon: "ShoppingCart",
    confirm: { enabled: true, message: "장바구니에 담은 항목을 저장하시겠습니까?" },
    action: { type: "event" },
  },
  "inbound-confirm": {
    label: "입고 확정",
    variant: "default",
    icon: "PackageCheck",
    confirm: { enabled: true, message: "선택한 품목을 입고 확정하시겠습니까?" },
    action: { type: "event" },
  },
  custom: {
    label: "버튼",
    variant: "default",
    icon: "none",
    confirm: { enabled: false },
    action: { type: "save" },
  },
};

/** 확인 다이얼로그 기본 메시지 (액션별) */
const DEFAULT_CONFIRM_MESSAGES: Record<ButtonActionType, string> = {
  save: "저장하시겠습니까?",
  delete: "삭제하시겠습니까? 이 작업은 되돌릴 수 없습니다.",
  api: "실행하시겠습니까?",
  modal: "열기하시겠습니까?",
  event: "실행하시겠습니까?",
};

// ========================================
// 헬퍼 함수
// ========================================

/** 섹션 구분선 */
function SectionDivider({ label }: { label: string }) {
  return (
    <div className="pt-3 pb-1">
      <div className="flex items-center gap-2">
        <div className="h-px flex-1 bg-muted/60" />
        <span className="text-xs font-medium text-muted-foreground">{label}</span>
        <div className="h-px flex-1 bg-muted/60" />
      </div>
    </div>
  );
}

/** 장바구니 데이터 매핑 행 (읽기 전용) */
function CartMappingRow({
  source,
  target,
  desc,
  auto,
}: {
  source: string;
  target: string;
  desc?: string;
  auto?: boolean;
}) {
  return (
    <div className="flex items-start gap-1 py-0.5">
      <span className={cn("min-w-0 flex-1 text-[10px]", auto ? "text-muted-foreground" : "text-foreground")}>
        {source}
      </span>
      <span className="shrink-0 text-[10px] text-muted-foreground">&rarr;</span>
      <div className="shrink-0 text-right">
        <code className="rounded bg-muted px-1 font-mono text-[10px] text-foreground">
          {target}
        </code>
        {desc && (
          <p className="mt-0.5 text-[9px] text-muted-foreground leading-tight">{desc}</p>
        )}
      </div>
    </div>
  );
}

/** 허용된 아이콘 맵 (개별 import로 트리 쉐이킹 적용) */
const LUCIDE_ICON_MAP: Record<string, LucideIcon> = {
  Save, Trash2, LogOut, Menu, ExternalLink, Plus, Check, X,
  Edit, Search, RefreshCw, Download, Upload, Send, Copy, Settings, ChevronDown,
  ShoppingCart,
  ShoppingBag,
  PackageCheck,
};

/** Lucide 아이콘 동적 렌더링 */
function DynamicLucideIcon({
  name,
  size = 16,
  className,
}: {
  name: string;
  size?: number;
  className?: string;
}) {
  const IconComponent = LUCIDE_ICON_MAP[name];
  if (!IconComponent) return null;
  return <IconComponent size={size} className={className} />;
}

// ========================================
// STEP 2: 메인 컴포넌트
// ========================================

interface PopButtonComponentProps {
  config?: PopButtonConfig;
  label?: string;
  isDesignMode?: boolean;
  screenId?: string;
  componentId?: string;
}

export function PopButtonComponent({
  config,
  label,
  isDesignMode,
  screenId,
  componentId,
}: PopButtonComponentProps) {
  const {
    execute,
    isLoading,
    pendingConfirm,
    confirmExecute,
    cancelConfirm,
  } = usePopAction(screenId || "");

  const { subscribe, publish } = usePopEvent(screenId || "default");

  // 장바구니 모드 상태
  const isCartMode = config?.preset === "cart";
  const isInboundConfirmMode = config?.preset === "inbound-confirm";
  const [cartCount, setCartCount] = useState(0);
  const [cartIsDirty, setCartIsDirty] = useState(false);
  const [cartSaving, setCartSaving] = useState(false);
  const [showCartConfirm, setShowCartConfirm] = useState(false);
  const [confirmProcessing, setConfirmProcessing] = useState(false);
  const [showInboundConfirm, setShowInboundConfirm] = useState(false);
  const [inboundSelectedCount, setInboundSelectedCount] = useState(0);

  // 입고 확정 모드: 선택 항목 수 수신
  useEffect(() => {
    if (!isInboundConfirmMode || !componentId) return;
    const unsub = subscribe(
      `__comp_input__${componentId}__selected_items`,
      (payload: unknown) => {
        const data = payload as { value?: unknown[] } | undefined;
        const items = Array.isArray(data?.value) ? data.value : [];
        setInboundSelectedCount(items.length);
      }
    );
    return unsub;
  }, [isInboundConfirmMode, componentId, subscribe]);

  // 장바구니 상태 수신 (카드 목록에서 count/isDirty 전달)
  useEffect(() => {
    if (!isCartMode || !componentId) return;
    const unsub = subscribe(
      `__comp_input__${componentId}__cart_updated`,
      (payload: unknown) => {
        const data = payload as { value?: { count?: number; isDirty?: boolean } } | undefined;
        const inner = data?.value;
        if (inner?.count !== undefined) setCartCount(inner.count);
        if (inner?.isDirty !== undefined) setCartIsDirty(inner.isDirty);
      }
    );
    return unsub;
  }, [isCartMode, componentId, subscribe]);

  // 저장 완료 수신 (카드 목록에서 saveToDb 완료 후 전달)
  const cartScreenIdRef = React.useRef(config?.cart?.cartScreenId);
  cartScreenIdRef.current = config?.cart?.cartScreenId;

  useEffect(() => {
    if (!isCartMode || !componentId) return;
    const unsub = subscribe(
      `__comp_input__${componentId}__cart_save_completed`,
      (payload: unknown) => {
        const data = payload as { value?: { success?: boolean } } | undefined;
        setCartSaving(false);
        if (data?.value?.success) {
          setCartIsDirty(false);
          const targetScreenId = cartScreenIdRef.current;
          if (targetScreenId) {
            const cleanId = targetScreenId.replace(/^.*\/(\d+)$/, "$1").trim();
            window.location.href = `/pop/screens/${cleanId}`;
          } else {
            toast.success("장바구니가 저장되었습니다.");
          }
        } else {
          toast.error("장바구니 저장에 실패했습니다.");
        }
      }
    );
    return unsub;
  }, [isCartMode, componentId, subscribe]);

  const getConfirmMessage = useCallback((): string => {
    if (pendingConfirm?.confirm?.message) return pendingConfirm.confirm.message;
    if (config?.confirm?.message) return config.confirm.message;
    return DEFAULT_CONFIRM_MESSAGES[config?.action?.type || "save"];
  }, [pendingConfirm?.confirm?.message, config?.confirm?.message, config?.action?.type]);

  // 장바구니 저장 트리거 (연결 미설정 시 10초 타임아웃으로 복구)
  const cartSaveTimeoutRef = React.useRef<ReturnType<typeof setTimeout> | null>(null);

  const handleCartSave = useCallback(() => {
    if (!componentId) return;
    setCartSaving(true);
    const selectedCols =
      config?.cart?.rowDataMode === "selected" ? config.cart.selectedColumns : undefined;
    publish(`__comp_output__${componentId}__cart_save_trigger`, {
      selectedColumns: selectedCols,
    });

    if (cartSaveTimeoutRef.current) clearTimeout(cartSaveTimeoutRef.current);
    cartSaveTimeoutRef.current = setTimeout(() => {
      setCartSaving((prev) => {
        if (prev) {
          toast.error("장바구니 저장 응답이 없습니다. 연결 설정을 확인하세요.");
        }
        return false;
      });
    }, 10_000);
  }, [componentId, publish, config?.cart?.rowDataMode, config?.cart?.selectedColumns]);

  // 저장 완료 시 타임아웃 정리
  useEffect(() => {
    if (!cartSaving && cartSaveTimeoutRef.current) {
      clearTimeout(cartSaveTimeoutRef.current);
      cartSaveTimeoutRef.current = null;
    }
  }, [cartSaving]);

  // 입고 확정: 데이터 수집 → API 호출
  const handleInboundConfirm = useCallback(async () => {
    if (!componentId) return;
    setConfirmProcessing(true);

    try {
      // 동기적 이벤트 수집 (connectionResolver가 동기 중계)
      const responses: CollectedDataResponse[] = [];
      const unsub = subscribe(
        `__comp_input__${componentId}__collected_data`,
        (payload: unknown) => {
          const enriched = payload as { value?: CollectedDataResponse };
          if (enriched?.value) {
            responses.push(enriched.value);
          }
        }
      );

      publish(`__comp_output__${componentId}__collect_data`, {
        requestId: crypto.randomUUID(),
        action: "inbound-confirm",
      });

      unsub();

      if (responses.length === 0) {
        toast.error("연결된 컴포넌트에서 데이터를 수집할 수 없습니다. 연결 설정을 확인하세요.");
        return;
      }

      const cardListData = responses.find(r => r.componentType === "pop-card-list");
      const fieldData = responses.find(r => r.componentType === "pop-field");

      const selectedItems = cardListData?.data?.items ?? [];
      if (selectedItems.length === 0) {
        toast.error("확정할 항목을 선택해주세요.");
        return;
      }

      const fieldValues = fieldData?.data?.values ?? {};

      const statusChangeRules = config?.statusChangeRules ?? config?.inboundConfirm?.statusChangeRules ?? [];

      const cardListMapping = cardListData?.mapping ?? null;
      const fieldMapping = fieldData?.mapping ?? null;

      const result = await apiClient.post("/pop/execute-action", {
        action: "inbound-confirm",
        data: {
          items: selectedItems,
          fieldValues,
        },
        mappings: {
          cardList: cardListMapping,
          field: fieldMapping,
        },
        statusChanges: statusChangeRules,
      });

      if (result.data?.success) {
        toast.success(`${selectedItems.length}건 입고 확정 완료`);
        publish(`__comp_output__${componentId}__action_completed`, {
          action: "inbound-confirm",
          success: true,
          count: selectedItems.length,
        });

        // 후속 액션 실행 (navigate, refresh 등)
        const followUps = config?.followUpActions ?? [];
        for (const fa of followUps) {
          switch (fa.type) {
            case "navigate":
              if (fa.targetScreenId) {
                publish("__pop_navigate__", { screenId: fa.targetScreenId, params: fa.params });
              }
              break;
            case "refresh":
              publish("__pop_refresh__");
              break;
            case "event":
              if (fa.eventName) publish(fa.eventName, fa.eventPayload);
              break;
          }
        }
      } else {
        toast.error(result.data?.message || "입고 확정에 실패했습니다.");
      }
    } catch (err: unknown) {
      const message = err instanceof Error ? err.message : "입고 확정 중 오류가 발생했습니다.";
      toast.error(message);
    } finally {
      setConfirmProcessing(false);
      setShowInboundConfirm(false);
    }
  }, [componentId, subscribe, publish, config?.statusChangeRules, config?.inboundConfirm?.statusChangeRules, config?.followUpActions]);

  // 클릭 핸들러
  const handleClick = useCallback(async () => {
    if (isDesignMode) {
      const modeLabel = isCartMode ? "장바구니 저장" : isInboundConfirmMode ? "입고 확정" : ACTION_TYPE_LABELS[config?.action?.type || "save"];
      toast.info(`[디자인 모드] ${modeLabel} 액션`);
      return;
    }

    // 입고 확정 모드: confirm 다이얼로그 후 데이터 수집 → API 호출
    if (isInboundConfirmMode) {
      if (config?.confirm?.enabled !== false) {
        setShowInboundConfirm(true);
      } else {
        await handleInboundConfirm();
      }
      return;
    }

    // 장바구니 모드: isDirty 여부에 따라 분기
    if (isCartMode) {
      if (cartCount === 0 && !cartIsDirty) {
        toast.info("장바구니가 비어 있습니다.");
        return;
      }

      if (cartIsDirty) {
        // 새로 담은 항목이 있음 → 확인 후 저장
        setShowCartConfirm(true);
      } else {
        // 이미 저장된 상태 → 바로 장바구니 화면 이동
        const targetScreenId = config?.cart?.cartScreenId;
        if (targetScreenId) {
          const cleanId = targetScreenId.replace(/^.*\/(\d+)$/, "$1").trim();
          window.location.href = `/pop/screens/${cleanId}`;
        } else {
          toast.info("장바구니 화면이 설정되지 않았습니다.");
        }
      }
      return;
    }

    const action = config?.action;
    if (!action) return;

    await execute(action, {
      confirm: config?.confirm,
      followUpActions: config?.followUpActions,
    });
  }, [isDesignMode, isCartMode, isInboundConfirmMode, config, cartCount, cartIsDirty, execute, handleCartSave, handleInboundConfirm]);

  // 외형
  const buttonLabel = config?.label || label || "버튼";
  const variant = config?.variant || "default";
  const iconName = config?.icon || "";
  const isIconOnly = config?.iconOnly || false;

  // 장바구니 3상태 아이콘: 빈 장바구니 / 저장 완료 / 변경사항 있음
  const cartIconName = useMemo(() => {
    if (!isCartMode) return iconName;
    if (cartCount === 0 && !cartIsDirty) return "ShoppingCart";
    if (cartCount > 0 && !cartIsDirty) return "ShoppingBag";
    return "ShoppingCart";
  }, [isCartMode, cartCount, cartIsDirty, iconName]);

  // 장바구니 3상태 버튼 색상
  const cartButtonClass = useMemo(() => {
    if (!isCartMode) return "";
    if (cartCount > 0 && !cartIsDirty) {
      return "bg-emerald-600 hover:bg-emerald-700 text-white border-emerald-600";
    }
    if (cartIsDirty) {
      return "bg-amber-500 hover:bg-orange-600 text-white border-orange-500 animate-pulse";
    }
    return "";
  }, [isCartMode, cartCount, cartIsDirty]);

  // 입고 확정 2상태 아이콘: 미선택(기본 아이콘) / 선택됨(체크 아이콘)
  const inboundIconName = useMemo(() => {
    if (!isInboundConfirmMode) return iconName;
    return inboundSelectedCount > 0 ? (config?.icon || "PackageCheck") : (config?.icon || "PackageCheck");
  }, [isInboundConfirmMode, inboundSelectedCount, config?.icon, iconName]);

  // 입고 확정 2상태 버튼 색상: 미선택(기본) / 선택됨(초록)
  const inboundButtonClass = useMemo(() => {
    if (!isInboundConfirmMode) return "";
    return inboundSelectedCount > 0
      ? "bg-emerald-600 hover:bg-emerald-700 text-white border-emerald-600"
      : "";
  }, [isInboundConfirmMode, inboundSelectedCount]);

  return (
    <>
      <div className="flex h-full w-full items-center justify-center">
        <div className="relative">
          <Button
            variant={variant}
            onClick={handleClick}
            disabled={isLoading || cartSaving || confirmProcessing}
            className={cn(
              "transition-transform active:scale-95",
              isIconOnly && "px-2",
              cartButtonClass,
              inboundButtonClass,
            )}
          >
            {(isCartMode ? cartIconName : isInboundConfirmMode ? inboundIconName : iconName) && (
              <DynamicLucideIcon
                name={isCartMode ? cartIconName : isInboundConfirmMode ? inboundIconName : iconName}
                size={16}
                className={isIconOnly ? "" : "mr-1.5"}
              />
            )}
            {!isIconOnly && <span>{buttonLabel}</span>}
          </Button>

          {/* 장바구니 배지 */}
          {isCartMode && cartCount > 0 && (
            <div
              className={cn(
                "absolute -top-2 -right-2 flex items-center justify-center rounded-full text-[10px] font-bold",
                cartIsDirty
                  ? "bg-amber-500 text-white"
                  : "bg-emerald-600 text-white",
              )}
              style={{ minWidth: 18, height: 18, padding: "0 4px" }}
            >
              {cartCount}
            </div>
          )}

          {/* 입고 확정 선택 개수 배지 */}
          {isInboundConfirmMode && inboundSelectedCount > 0 && (
            <div
              className="absolute -top-2 -right-2 flex items-center justify-center rounded-full bg-emerald-600 text-white text-[10px] font-bold"
              style={{ minWidth: 18, height: 18, padding: "0 4px" }}
            >
              {inboundSelectedCount}
            </div>
          )}
        </div>
      </div>

      {/* 장바구니 확인 다이얼로그 */}
      <AlertDialog open={showCartConfirm} onOpenChange={setShowCartConfirm}>
        <AlertDialogContent className="max-w-[95vw] sm:max-w-[400px]">
          <AlertDialogHeader>
            <AlertDialogTitle className="text-base sm:text-lg">
              장바구니 저장
            </AlertDialogTitle>
            <AlertDialogDescription className="text-xs sm:text-sm">
              {config?.confirm?.message || `${cartCount}개 항목을 장바구니에 저장하시겠습니까?`}
            </AlertDialogDescription>
          </AlertDialogHeader>
          <AlertDialogFooter className="gap-2 sm:gap-0">
            <AlertDialogCancel className="h-8 flex-1 text-xs sm:h-10 sm:flex-none sm:text-sm">
              취소
            </AlertDialogCancel>
            <AlertDialogAction
              onClick={() => {
                setShowCartConfirm(false);
                handleCartSave();
              }}
              className="h-8 flex-1 text-xs sm:h-10 sm:flex-none sm:text-sm"
            >
              저장
            </AlertDialogAction>
          </AlertDialogFooter>
        </AlertDialogContent>
      </AlertDialog>

      {/* 입고 확정 확인 다이얼로그 */}
      <AlertDialog open={showInboundConfirm} onOpenChange={setShowInboundConfirm}>
        <AlertDialogContent className="max-w-[95vw] sm:max-w-[400px]">
          <AlertDialogHeader>
            <AlertDialogTitle className="text-base sm:text-lg">
              입고 확정
            </AlertDialogTitle>
            <AlertDialogDescription className="text-xs sm:text-sm">
              {config?.confirm?.message || "선택한 품목을 입고 확정하시겠습니까?"}
            </AlertDialogDescription>
          </AlertDialogHeader>
          <AlertDialogFooter className="gap-2 sm:gap-0">
            <AlertDialogCancel
              disabled={confirmProcessing}
              className="h-8 flex-1 text-xs sm:h-10 sm:flex-none sm:text-sm"
            >
              취소
            </AlertDialogCancel>
            <AlertDialogAction
              onClick={() => { handleInboundConfirm(); }}
              disabled={confirmProcessing}
              className="h-8 flex-1 text-xs sm:h-10 sm:flex-none sm:text-sm"
            >
              {confirmProcessing ? "처리 중..." : "확정"}
            </AlertDialogAction>
          </AlertDialogFooter>
        </AlertDialogContent>
      </AlertDialog>

      {/* 일반 확인 다이얼로그 */}
      <AlertDialog open={!!pendingConfirm} onOpenChange={(open) => { if (!open) cancelConfirm(); }}>
        <AlertDialogContent className="max-w-[95vw] sm:max-w-[400px]">
          <AlertDialogHeader>
            <AlertDialogTitle className="text-base sm:text-lg">
              실행 확인
            </AlertDialogTitle>
            <AlertDialogDescription className="text-xs sm:text-sm">
              {getConfirmMessage()}
            </AlertDialogDescription>
          </AlertDialogHeader>
          <AlertDialogFooter className="gap-2 sm:gap-0">
            <AlertDialogCancel className="h-8 flex-1 text-xs sm:h-10 sm:flex-none sm:text-sm">
              취소
            </AlertDialogCancel>
            <AlertDialogAction
              onClick={confirmExecute}
              className={cn(
                "h-8 flex-1 text-xs sm:h-10 sm:flex-none sm:text-sm",
                config?.action?.type === "delete" &&
                  "bg-destructive text-destructive-foreground hover:bg-destructive/90"
              )}
            >
              확인
            </AlertDialogAction>
          </AlertDialogFooter>
        </AlertDialogContent>
      </AlertDialog>
    </>
  );
}

// ========================================
// STEP 3: 설정 패널
// ========================================

interface PopButtonConfigPanelProps {
  config: PopButtonConfig;
  onUpdate: (config: PopButtonConfig) => void;
  allComponents?: { id: string; type: string; config?: Record<string, unknown> }[];
  connections?: { sourceComponent: string; targetComponent: string; sourceOutput?: string; targetInput?: string }[];
  componentId?: string;
}

export function PopButtonConfigPanel({
  config,
  onUpdate,
  allComponents,
  connections,
  componentId,
}: PopButtonConfigPanelProps) {
  const isCustom = config?.preset === "custom";

  // 컬럼 불러오기용 상태
  const [loadedColumns, setLoadedColumns] = useState<{ name: string; label: string }[]>([]);
  const [colLoading, setColLoading] = useState(false);
  const [connectedTableName, setConnectedTableName] = useState<string | null>(null);

  // 연결된 카드 목록의 테이블명 자동 탐색
  useEffect(() => {
    if (config?.preset !== "cart" || !componentId || !connections || !allComponents) {
      setConnectedTableName(null);
      return;
    }

    // 방법 1: 버튼(source) -> 카드목록(target) cart_save_trigger 연결
    let cardListId: string | undefined;
    const outConn = connections.find(
      (c) =>
        c.sourceComponent === componentId &&
        c.sourceOutput === "cart_save_trigger",
    );
    if (outConn) {
      cardListId = outConn.targetComponent;
    }

    // 방법 2: 카드목록(source) -> 버튼(target) cart_updated 연결 (역방향)
    if (!cardListId) {
      const inConn = connections.find(
        (c) =>
          c.targetComponent === componentId &&
          (c.sourceOutput === "cart_updated" || c.sourceOutput === "cart_save_completed"),
      );
      if (inConn) {
        cardListId = inConn.sourceComponent;
      }
    }

    // 방법 3: 버튼과 연결된 pop-card-list 타입 컴포넌트 탐색
    if (!cardListId) {
      const anyConn = connections.find(
        (c) =>
          (c.sourceComponent === componentId || c.targetComponent === componentId),
      );
      if (anyConn) {
        const otherId = anyConn.sourceComponent === componentId
          ? anyConn.targetComponent
          : anyConn.sourceComponent;
        const otherComp = allComponents.find((c) => c.id === otherId);
        if (otherComp?.type === "pop-card-list") {
          cardListId = otherId;
        }
      }
    }

    if (!cardListId) {
      setConnectedTableName(null);
      return;
    }

    const cardList = allComponents.find((c) => c.id === cardListId);
    const cfg = cardList?.config as Record<string, unknown> | undefined;
    const dataSource = cfg?.dataSource as Record<string, unknown> | undefined;
    const tableName = (dataSource?.tableName as string) || (cfg?.tableName as string) || undefined;
    setConnectedTableName(tableName || null);
  }, [config?.preset, componentId, connections, allComponents]);

  // 선택 저장 모드 + 연결 테이블명이 있으면 컬럼 자동 로드
  useEffect(() => {
    if (config?.cart?.rowDataMode !== "selected" || !connectedTableName) {
      return;
    }
    // 이미 같은 테이블의 컬럼이 로드되어 있으면 스킵
    if (loadedColumns.length > 0) return;

    let cancelled = false;
    setColLoading(true);
    DataFlowAPI.getTableColumns(connectedTableName)
      .then((cols) => {
        if (cancelled) return;
        setLoadedColumns(
          cols
            .filter((c: { columnName: string }) =>
              !["id", "created_at", "updated_at", "created_by", "updated_by"].includes(c.columnName),
            )
            .map((c: { columnName: string; displayName?: string }) => ({
              name: c.columnName,
              label: c.displayName || c.columnName,
            })),
        );
      })
      .catch(() => {
        if (!cancelled) setLoadedColumns([]);
      })
      .finally(() => {
        if (!cancelled) setColLoading(false);
      });
    return () => { cancelled = true; };
  }, [config?.cart?.rowDataMode, connectedTableName, loadedColumns.length]);

  // 프리셋 변경 핸들러
  const handlePresetChange = (preset: ButtonPreset) => {
    const defaults = PRESET_DEFAULTS[preset];
    onUpdate({
      ...config,
      preset,
      label: defaults.label || config.label,
      variant: defaults.variant || config.variant,
      icon: defaults.icon ?? config.icon,
      confirm: defaults.confirm || config.confirm,
      action: (defaults.action as ButtonMainAction) || config.action,
      // 후속 액션은 프리셋 변경 시 유지
    });
  };

  // 메인 액션 업데이트 헬퍼
  const updateAction = (updates: Partial<ButtonMainAction>) => {
    onUpdate({
      ...config,
      action: { ...config.action, ...updates },
    });
  };

  return (
    <div className="space-y-2 overflow-y-auto pr-1 pb-32">
      {/* 프리셋 선택 */}
      <SectionDivider label="프리셋" />
      <Select
        value={config?.preset || "custom"}
        onValueChange={(v) => handlePresetChange(v as ButtonPreset)}
      >
        <SelectTrigger className="h-8 text-xs">
          <SelectValue />
        </SelectTrigger>
        <SelectContent>
          {Object.entries(PRESET_LABELS).map(([key, label]) => (
            <SelectItem key={key} value={key} className="text-xs">
              {label}
            </SelectItem>
          ))}
        </SelectContent>
      </Select>
      {!isCustom && (
        <p className="text-[10px] text-muted-foreground">
          프리셋 변경 시 외형과 액션이 자동 설정됩니다
        </p>
      )}

      {/* 외형 설정 */}
      <SectionDivider label="외형" />
      <div className="space-y-2">
        {/* 라벨 */}
        <div>
          <Label className="text-xs">라벨</Label>
          <Input
            value={config?.label || ""}
            onChange={(e) => onUpdate({ ...config, label: e.target.value })}
            placeholder="버튼 텍스트"
            className="h-8 text-xs"
          />
        </div>

        {/* variant */}
        <div>
          <Label className="text-xs">스타일</Label>
          <Select
            value={config?.variant || "default"}
            onValueChange={(v) =>
              onUpdate({ ...config, variant: v as ButtonVariant })
            }
          >
            <SelectTrigger className="h-8 text-xs">
              <SelectValue />
            </SelectTrigger>
            <SelectContent>
              {Object.entries(VARIANT_LABELS).map(([key, label]) => (
                <SelectItem key={key} value={key} className="text-xs">
                  {label}
                </SelectItem>
              ))}
            </SelectContent>
          </Select>
        </div>

        {/* 아이콘 */}
        <div>
          <Label className="text-xs">아이콘</Label>
          <Select
            value={config?.icon || "none"}
            onValueChange={(v) =>
              onUpdate({ ...config, icon: v === "none" ? "" : v })
            }
          >
            <SelectTrigger className="h-8 text-xs">
              <SelectValue placeholder="없음" />
            </SelectTrigger>
            <SelectContent>
              {ICON_OPTIONS.map((opt) => (
                <SelectItem key={opt.value} value={opt.value} className="text-xs">
                  <div className="flex items-center gap-2">
                    {opt.value && (
                      <DynamicLucideIcon name={opt.value} size={14} />
                    )}
                    <span>{opt.label}</span>
                  </div>
                </SelectItem>
              ))}
            </SelectContent>
          </Select>
        </div>

        {/* 아이콘 전용 모드 */}
        <div className="flex items-center gap-2">
          <Checkbox
            id="iconOnly"
            checked={config?.iconOnly || false}
            onCheckedChange={(checked) =>
              onUpdate({ ...config, iconOnly: checked === true })
            }
          />
          <Label htmlFor="iconOnly" className="text-xs">
            아이콘만 표시 (라벨 숨김)
          </Label>
        </div>
      </div>

      {/* 장바구니 설정 (cart 프리셋 전용) */}
      {config?.preset === "cart" && (
        <>
          <SectionDivider label="장바구니 설정" />
          <div className="space-y-3">
            <div>
              <Label className="text-xs">장바구니 화면 ID</Label>
              <Input
                value={config?.cart?.cartScreenId || ""}
                onChange={(e) =>
                  onUpdate({
                    ...config,
                    cart: { ...config.cart, cartScreenId: e.target.value },
                  })
                }
                placeholder="저장 후 이동할 POP 화면 ID"
                className="h-8 text-xs"
              />
              <p className="text-muted-foreground mt-1 text-[10px]">
                저장 완료 후 이동할 장바구니 리스트 화면 ID입니다.
                비어있으면 이동 없이 저장만 합니다.
              </p>
            </div>
          </div>

          {/* 데이터 저장 흐름 시각화 */}
          <SectionDivider label="데이터 저장 흐름" />
          <div className="space-y-2">
            <p className="text-muted-foreground text-[10px]">
              카드 목록에서 &quot;담기&quot; 클릭 시 아래와 같이 <code className="rounded bg-muted px-1 font-mono text-foreground">cart_items</code> 테이블에 저장됩니다.
            </p>

            <div className="space-y-0.5">
              {/* 사용자 입력 데이터 */}
              <div className="rounded-md border bg-amber-50/50 px-2.5 py-1.5 dark:bg-amber-950/20">
                <p className="mb-1 text-[10px] font-medium text-amber-700 dark:text-amber-400">사용자 입력</p>
                <CartMappingRow source="입력한 수량" target="quantity" />
                <CartMappingRow source="포장 단위" target="package_unit" />
                <CartMappingRow source="포장 내역 (JSON)" target="package_entries" />
                <CartMappingRow source="메모" target="memo" />
              </div>

              {/* 원본 데이터 */}
              <div className="rounded-md border bg-primary/10/50 px-2.5 py-1.5 dark:bg-primary/10">
                <p className="mb-1 text-[10px] font-medium text-primary dark:text-primary/80">원본 행 데이터</p>

                {/* 저장 모드 선택 */}
                <div className="mb-1.5 flex items-center gap-1.5">
                  <span className="text-[10px] text-muted-foreground">저장 모드:</span>
                  <Select
                    value={config?.cart?.rowDataMode || "all"}
                    onValueChange={(v) =>
                      onUpdate({
                        ...config,
                        cart: { ...config.cart, rowDataMode: v as RowDataMode },
                      })
                    }
                  >
                    <SelectTrigger className="h-6 w-[100px] text-[10px]">
                      <SelectValue />
                    </SelectTrigger>
                    <SelectContent>
                      <SelectItem value="all" className="text-xs">전체 저장</SelectItem>
                      <SelectItem value="selected" className="text-xs">선택 저장</SelectItem>
                    </SelectContent>
                  </Select>
                </div>

                {config?.cart?.rowDataMode === "selected" ? (
                  <>
                    {/* 선택 저장 모드: 컬럼 목록 관리 */}
                    <div className="space-y-1.5">
                      {connectedTableName ? (
                        <p className="text-[10px] text-muted-foreground">
                          연결: <code className="rounded bg-muted px-1 font-mono text-foreground">{connectedTableName}</code>
                        </p>
                      ) : (
                        <p className="text-[9px] text-amber-600 dark:text-amber-400">
                          카드 목록과 연결(cart_save_trigger)하면 컬럼이 자동으로 표시됩니다.
                        </p>
                      )}

                      {colLoading && (
                        <p className="text-[9px] text-muted-foreground">컬럼 불러오는 중...</p>
                      )}

                      {/* 불러온 컬럼 체크박스 */}
                      {loadedColumns.length > 0 && (
                        <div className="max-h-[160px] space-y-0.5 overflow-y-auto rounded border bg-background p-1.5">
                          {loadedColumns.map((col) => {
                            const isChecked = (config?.cart?.selectedColumns || []).includes(col.name);
                            return (
                              <label key={col.name} className="flex cursor-pointer items-center gap-1.5 rounded px-1 py-0.5 hover:bg-muted/50">
                                <Checkbox
                                  checked={isChecked}
                                  onCheckedChange={(checked) => {
                                    const prev = config?.cart?.selectedColumns || [];
                                    const next = checked
                                      ? [...prev, col.name]
                                      : prev.filter((c) => c !== col.name);
                                    onUpdate({
                                      ...config,
                                      cart: { ...config.cart, selectedColumns: next },
                                    });
                                  }}
                                  className="h-3 w-3"
                                />
                                <span className="text-[10px]">{col.label}</span>
                                {col.label !== col.name && (
                                  <span className="text-[9px] text-muted-foreground">({col.name})</span>
                                )}
                              </label>
                            );
                          })}
                        </div>
                      )}

                      {/* 선택된 컬럼 요약 */}
                      {(config?.cart?.selectedColumns?.length ?? 0) > 0 ? (
                        <CartMappingRow
                          source={`선택된 ${config!.cart!.selectedColumns!.length}개 컬럼 (JSON)`}
                          target="row_data"
                          desc={config!.cart!.selectedColumns!.join(", ")}
                        />
                      ) : (
                        <p className="text-[9px] text-amber-600 dark:text-amber-400">
                          저장할 컬럼을 선택하세요. 미선택 시 전체 저장됩니다.
                        </p>
                      )}
                    </div>
                  </>
                ) : (
                  <CartMappingRow source="행 전체 (JSON)" target="row_data" desc="원본 테이블의 모든 컬럼이 JSON으로 저장" />
                )}

                <CartMappingRow source="행 식별키 (PK)" target="row_key" />
                <CartMappingRow source="원본 테이블명" target="source_table" />
              </div>

              {/* 시스템 자동 */}
              <div className="rounded-md border bg-muted/30 px-2.5 py-1.5">
                <p className="mb-1 text-[10px] font-medium text-muted-foreground">자동 설정</p>
                <CartMappingRow source="현재 화면 ID" target="screen_id" auto />
                <CartMappingRow source='장바구니 타입 (미사용)' target="cart_type" auto />
                <CartMappingRow source='상태 ("in_cart")' target="status" auto />
                <CartMappingRow source="회사 코드" target="company_code" auto />
                <CartMappingRow source="사용자 ID" target="user_id" auto />
              </div>
            </div>

            <p className="text-muted-foreground text-[10px] leading-relaxed">
              장바구니 목록 화면에서 <code className="rounded bg-muted px-1 font-mono text-foreground">row_data</code>의 JSON을 풀어서
              최종 대상 테이블로 매핑할 수 있습니다.
            </p>
          </div>
        </>
      )}

      {/* 메인 액션 (cart 프리셋에서는 숨김) */}
      {config?.preset !== "cart" && (
        <>
          <SectionDivider label="메인 액션" />
          <div className="space-y-2">
            <div>
              <Label className="text-xs">액션 유형</Label>
              <Select
                value={config?.action?.type || "save"}
                onValueChange={(v) =>
                  updateAction({ type: v as ButtonActionType })
                }
                disabled={!isCustom}
              >
                <SelectTrigger className="h-8 text-xs">
                  <SelectValue />
                </SelectTrigger>
                <SelectContent>
                  {Object.entries(ACTION_TYPE_LABELS).map(([key, label]) => (
                    <SelectItem key={key} value={key} className="text-xs">
                      {label}
                    </SelectItem>
                  ))}
                </SelectContent>
              </Select>
              {!isCustom && (
                <p className="text-[10px] text-muted-foreground mt-1">
                  프리셋에 의해 고정됨. 변경하려면 &quot;직접 설정&quot; 선택
                </p>
              )}
            </div>
            <ActionDetailFields
              action={config?.action}
              onUpdate={updateAction}
              disabled={!isCustom}
            />
          </div>
        </>
      )}

      {/* 확인 다이얼로그 */}
      <SectionDivider label="확인 메시지" />
      <div className="space-y-2">
        <div className="flex items-center gap-2">
          <Checkbox
            id="confirmEnabled"
            checked={config?.confirm?.enabled || false}
            onCheckedChange={(checked) =>
              onUpdate({
                ...config,
                confirm: {
                  ...config?.confirm,
                  enabled: checked === true,
                },
              })
            }
          />
          <Label htmlFor="confirmEnabled" className="text-xs">
            실행 전 확인 메시지 표시
          </Label>
        </div>
        {config?.confirm?.enabled && (
          <div>
            <Input
              value={config?.confirm?.message || ""}
              onChange={(e) =>
                onUpdate({
                  ...config,
                  confirm: {
                    ...config?.confirm,
                    enabled: true,
                    message: e.target.value,
                  },
                })
              }
              placeholder="비워두면 기본 메시지 사용"
              className="h-8 text-xs"
            />
            <p className="text-[10px] text-muted-foreground mt-1">
              기본:{" "}
              {DEFAULT_CONFIRM_MESSAGES[config?.action?.type || "save"]}
            </p>
          </div>
        )}
      </div>

      {/* 상태 변경 규칙 (cart 프리셋 제외 모두 표시) */}
      {config?.preset !== "cart" && (
        <>
          <SectionDivider label="상태 변경 규칙" />
          <StatusChangeRuleEditor
            rules={config?.statusChangeRules ?? config?.inboundConfirm?.statusChangeRules ?? []}
            onUpdate={(rules) => onUpdate({ ...config, statusChangeRules: rules })}
          />
        </>
      )}

      {/* 후속 액션 */}
      <SectionDivider label="후속 액션" />
      <FollowUpActionsEditor
        actions={config?.followUpActions || []}
        onUpdate={(actions) =>
          onUpdate({ ...config, followUpActions: actions })
        }
      />
    </div>
  );
}

// ========================================
// 액션 세부 필드 (타입별)
// ========================================

function ActionDetailFields({
  action,
  onUpdate,
  disabled,
}: {
  action?: ButtonMainAction;
  onUpdate: (updates: Partial<ButtonMainAction>) => void;
  disabled?: boolean;
}) {
  // 디자이너 컨텍스트 (뷰어에서는 null)
  const designerCtx = usePopDesignerContext();
  const actionType = action?.type || "save";

  switch (actionType) {
    case "save":
    case "delete":
      return (
        <div>
          <Label className="text-xs">대상 테이블</Label>
          <Input
            value={action?.targetTable || ""}
            onChange={(e) => onUpdate({ targetTable: e.target.value })}
            placeholder="테이블명 입력"
            className="h-8 text-xs"
            disabled={disabled}
          />
        </div>
      );

    case "api":
      return (
        <div className="space-y-2">
          <div>
            <Label className="text-xs">엔드포인트</Label>
            <Input
              value={action?.apiEndpoint || ""}
              onChange={(e) => onUpdate({ apiEndpoint: e.target.value })}
              placeholder="/api/..."
              className="h-8 text-xs"
              disabled={disabled}
            />
          </div>
          <div>
            <Label className="text-xs">HTTP 메서드</Label>
            <Select
              value={action?.apiMethod || "POST"}
              onValueChange={(v) =>
                onUpdate({
                  apiMethod: v as "GET" | "POST" | "PUT" | "DELETE",
                })
              }
              disabled={disabled}
            >
              <SelectTrigger className="h-8 text-xs">
                <SelectValue />
              </SelectTrigger>
              <SelectContent>
                {Object.entries(API_METHOD_LABELS).map(([key, label]) => (
                  <SelectItem key={key} value={key} className="text-xs">
                    {label}
                  </SelectItem>
                ))}
              </SelectContent>
            </Select>
          </div>
        </div>
      );

    case "modal":
      return (
        <div className="space-y-2">
          <div>
            <Label className="text-xs">모달 방식</Label>
            <Select
              value={action?.modalMode || "fullscreen"}
              onValueChange={(v) =>
                onUpdate({ modalMode: v as ModalMode })
              }
              disabled={disabled}
            >
              <SelectTrigger className="h-8 text-xs">
                <SelectValue />
              </SelectTrigger>
              <SelectContent>
                {Object.entries(MODAL_MODE_LABELS).map(([key, label]) => (
                  <SelectItem key={key} value={key} className="text-xs">
                    {label}
                  </SelectItem>
                ))}
              </SelectContent>
            </Select>
          </div>
          {action?.modalMode === "screen-ref" && (
            <div>
              <Label className="text-xs">화면 ID</Label>
              <Input
                value={action?.modalScreenId || ""}
                onChange={(e) =>
                  onUpdate({ modalScreenId: e.target.value })
                }
                placeholder="화면 ID"
                className="h-8 text-xs"
                disabled={disabled}
              />
            </div>
          )}
          <div>
            <Label className="text-xs">모달 제목</Label>
            <Input
              value={action?.modalTitle || ""}
              onChange={(e) => onUpdate({ modalTitle: e.target.value })}
              placeholder="모달 제목 (선택)"
              className="h-8 text-xs"
              disabled={disabled}
            />
          </div>
          {/* 모달 캔버스 생성/열기 (fullscreen 모드 + 디자이너 내부) */}
          {action?.modalMode === "fullscreen" && designerCtx && (
            <div>
              {action?.modalScreenId ? (
                <Button
                  variant="outline"
                  size="sm"
                  className="h-8 w-full text-xs"
                  onClick={() => designerCtx.navigateToCanvas(action.modalScreenId!)}
                >
                  모달 캔버스 열기
                </Button>
              ) : (
                <Button
                  variant="outline"
                  size="sm"
                  className="h-8 w-full text-xs"
                  onClick={() => {
                    const selectedId = designerCtx.selectedComponentId;
                    if (!selectedId) return;
                    const modalId = designerCtx.createModalCanvas(
                      selectedId,
                      action?.modalTitle || "새 모달"
                    );
                    onUpdate({ modalScreenId: modalId });
                  }}
                >
                  모달 캔버스 생성
                </Button>
              )}
            </div>
          )}
        </div>
      );

    case "event":
      return (
        <div className="space-y-2">
          <div>
            <Label className="text-xs">이벤트명</Label>
            <Input
              value={action?.eventName || ""}
              onChange={(e) => onUpdate({ eventName: e.target.value })}
              placeholder="예: data-saved, item-selected"
              className="h-8 text-xs"
              disabled={disabled}
            />
          </div>
        </div>
      );

    default:
      return null;
  }
}

// ========================================
// 후속 액션 편집기
// ========================================

function FollowUpActionsEditor({
  actions,
  onUpdate,
}: {
  actions: FollowUpAction[];
  onUpdate: (actions: FollowUpAction[]) => void;
}) {
  // 추가
  const handleAdd = () => {
    onUpdate([...actions, { type: "event" }]);
  };

  // 삭제
  const handleRemove = (index: number) => {
    onUpdate(actions.filter((_, i) => i !== index));
  };

  // 수정
  const handleUpdate = (index: number, updates: Partial<FollowUpAction>) => {
    const newActions = [...actions];
    newActions[index] = { ...newActions[index], ...updates };
    onUpdate(newActions);
  };

  return (
    <div className="space-y-2">
      {actions.length === 0 && (
        <p className="text-[10px] text-muted-foreground">
          메인 액션 성공 후 순차 실행할 후속 동작
        </p>
      )}

      {actions.map((fa, idx) => (
        <div
          key={idx}
          className="space-y-1.5 rounded border p-2"
        >
          <div className="flex items-center justify-between">
            <span className="text-[10px] font-medium text-muted-foreground">
              후속 {idx + 1}
            </span>
            <Button
              type="button"
              variant="ghost"
              size="sm"
              onClick={() => handleRemove(idx)}
              className="h-5 px-1 text-[10px] text-destructive"
            >
              삭제
            </Button>
          </div>

          {/* 타입 선택 */}
          <Select
            value={fa.type}
            onValueChange={(v) =>
              handleUpdate(idx, { type: v as FollowUpActionType })
            }
          >
            <SelectTrigger className="h-7 text-xs">
              <SelectValue />
            </SelectTrigger>
            <SelectContent>
              {Object.entries(FOLLOWUP_TYPE_LABELS).map(([key, label]) => (
                <SelectItem key={key} value={key} className="text-xs">
                  {label}
                </SelectItem>
              ))}
            </SelectContent>
          </Select>

          {/* 타입별 추가 입력 */}
          {fa.type === "event" && (
            <Input
              value={fa.eventName || ""}
              onChange={(e) =>
                handleUpdate(idx, { eventName: e.target.value })
              }
              placeholder="이벤트명"
              className="h-7 text-xs"
            />
          )}
          {fa.type === "navigate" && (
            <Input
              value={fa.targetScreenId || ""}
              onChange={(e) =>
                handleUpdate(idx, { targetScreenId: e.target.value })
              }
              placeholder="화면 ID"
              className="h-7 text-xs"
            />
          )}
        </div>
      ))}

      <Button
        type="button"
        variant="outline"
        size="sm"
        onClick={handleAdd}
        className="w-full h-7 text-xs"
      >
        후속 액션 추가
      </Button>
    </div>
  );
}

// ========================================
// STEP 4: 미리보기 + 레지스트리 등록
// ========================================

function PopButtonPreviewComponent({
  config,
}: {
  config?: PopButtonConfig;
}) {
  const buttonLabel = config?.label || "버튼";
  const variant = config?.variant || "default";
  const iconName = config?.icon || "";
  const isIconOnly = config?.iconOnly || false;

  return (
    <div className="flex h-full w-full items-center justify-center overflow-hidden">
      <Button
        variant={variant}
        className={cn(
          "pointer-events-none",
          isIconOnly && "px-2"
        )}
        tabIndex={-1}
      >
        {iconName && (
          <DynamicLucideIcon
            name={iconName}
            size={16}
            className={isIconOnly ? "" : "mr-1.5"}
          />
        )}
        {!isIconOnly && <span>{buttonLabel}</span>}
      </Button>
    </div>
  );
}

// ========================================
// 상태 변경 규칙 편집기
// ========================================

const KNOWN_ITEM_FIELDS = [
  { value: "__cart_id", label: "__cart_id (카드 항목 ID)" },
  { value: "__cart_row_key", label: "__cart_row_key (원본 PK 값)" },
  { value: "id", label: "id" },
  { value: "row_key", label: "row_key" },
];

function StatusChangeRuleEditor({
  rules,
  onUpdate,
}: {
  rules: StatusChangeRule[];
  onUpdate: (rules: StatusChangeRule[]) => void;
}) {
  const [tables, setTables] = useState<TableInfo[]>([]);
  const [columnsMap, setColumnsMap] = useState<Record<string, ColumnInfo[]>>({});

  useEffect(() => {
    fetchTableList().then(setTables);
  }, []);

  const loadColumns = (tableName: string) => {
    if (!tableName || columnsMap[tableName]) return;
    fetchTableColumns(tableName).then((cols) => {
      setColumnsMap((prev) => ({ ...prev, [tableName]: cols }));
    });
  };

  const updateRule = (idx: number, partial: Partial<StatusChangeRule>) => {
    const next = [...rules];
    next[idx] = { ...next[idx], ...partial };
    onUpdate(next);
  };

  const removeRule = (idx: number) => {
    const next = [...rules];
    next.splice(idx, 1);
    onUpdate(next);
  };

  const addRule = () => {
    onUpdate([
      ...rules,
      {
        targetTable: "",
        targetColumn: "",
        valueType: "fixed",
        fixedValue: "",
      },
    ]);
  };

  return (
    <div className="space-y-2 px-1">
      {rules.map((rule, idx) => (
        <SingleRuleEditor
          key={idx}
          rule={rule}
          idx={idx}
          tables={tables}
          columns={columnsMap[rule.targetTable] ?? []}
          onLoadColumns={loadColumns}
          onUpdate={(partial) => updateRule(idx, partial)}
          onRemove={() => removeRule(idx)}
        />
      ))}
      <Button variant="outline" size="sm" className="w-full text-xs" onClick={addRule}>
        <Plus className="mr-1 h-3 w-3" />
        규칙 추가
      </Button>
    </div>
  );
}

function SingleRuleEditor({
  rule,
  idx,
  tables,
  columns,
  onLoadColumns,
  onUpdate,
  onRemove,
}: {
  rule: StatusChangeRule;
  idx: number;
  tables: TableInfo[];
  columns: ColumnInfo[];
  onLoadColumns: (tableName: string) => void;
  onUpdate: (partial: Partial<StatusChangeRule>) => void;
  onRemove: () => void;
}) {
  useEffect(() => {
    if (rule.targetTable) onLoadColumns(rule.targetTable);
  }, [rule.targetTable]); // eslint-disable-line react-hooks/exhaustive-deps

  const conditions = rule.conditionalValue?.conditions ?? [];
  const defaultValue = rule.conditionalValue?.defaultValue ?? "";

  const updateCondition = (cIdx: number, partial: Partial<(typeof conditions)[0]>) => {
    const next = [...conditions];
    next[cIdx] = { ...next[cIdx], ...partial };
    onUpdate({
      conditionalValue: { ...rule.conditionalValue, conditions: next, defaultValue },
    });
  };

  const removeCondition = (cIdx: number) => {
    const next = [...conditions];
    next.splice(cIdx, 1);
    onUpdate({
      conditionalValue: { ...rule.conditionalValue, conditions: next, defaultValue },
    });
  };

  const addCondition = () => {
    onUpdate({
      conditionalValue: {
        ...rule.conditionalValue,
        conditions: [...conditions, { whenColumn: "", operator: "=" as const, whenValue: "", thenValue: "" }],
        defaultValue,
      },
    });
  };

  return (
    <div className="space-y-2 rounded border border-border p-2">
      <div className="flex items-center justify-between">
        <span className="text-[10px] font-medium text-muted-foreground">규칙 {idx + 1}</span>
        <Button variant="ghost" size="icon" className="h-5 w-5" onClick={onRemove}>
          <Trash2 className="h-3 w-3" />
        </Button>
      </div>

      {/* 대상 테이블 */}
      <div className="space-y-1">
        <Label className="text-[10px]">대상 테이블</Label>
        <TableCombobox
          tables={tables}
          value={rule.targetTable}
          onSelect={(v) => onUpdate({ targetTable: v, targetColumn: "" })}
        />
      </div>

      {/* 변경 컬럼 */}
      {rule.targetTable && (
        <div className="space-y-1">
          <Label className="text-[10px]">변경 컬럼</Label>
          <ColumnCombobox
            columns={columns}
            value={rule.targetColumn}
            onSelect={(v) => onUpdate({ targetColumn: v })}
          />
        </div>
      )}

      {/* 조회 키 */}
      {rule.targetColumn && (
        <div className="space-y-1">
          <div className="flex items-center gap-2">
            <Label className="text-[10px]">조회 키</Label>
            <Select
              value={rule.lookupMode ?? "auto"}
              onValueChange={(v) => onUpdate({ lookupMode: v as "auto" | "manual" })}
            >
              <SelectTrigger className="h-6 w-16 text-[10px]">
                <SelectValue />
              </SelectTrigger>
              <SelectContent>
                <SelectItem value="auto" className="text-[10px]">자동</SelectItem>
                <SelectItem value="manual" className="text-[10px]">수동</SelectItem>
              </SelectContent>
            </Select>
          </div>
          {(rule.lookupMode ?? "auto") === "auto" ? (
            <p className="text-[10px] text-muted-foreground">
              {rule.targetTable === "cart_items"
                ? `카드 항목.__cart_id → ${rule.targetTable}.id`
                : `카드 항목.row_key → ${rule.targetTable}.${columns.find(c => c.isPrimaryKey)?.name ?? "PK(조회중)"}`}
            </p>
          ) : (
            <div className="flex items-center gap-1">
              <Select
                value={rule.manualItemField ?? ""}
                onValueChange={(v) => onUpdate({ manualItemField: v })}
              >
                <SelectTrigger className="h-7 flex-1 text-[10px]">
                  <SelectValue placeholder="카드 항목 필드" />
                </SelectTrigger>
                <SelectContent>
                  {KNOWN_ITEM_FIELDS.map((f) => (
                    <SelectItem key={f.value} value={f.value} className="text-[10px]">{f.label}</SelectItem>
                  ))}
                </SelectContent>
              </Select>
              <span className="shrink-0 text-[10px] text-muted-foreground">→</span>
              <ColumnCombobox
                columns={columns}
                value={rule.manualPkColumn ?? ""}
                onSelect={(v) => onUpdate({ manualPkColumn: v })}
                placeholder="대상 PK 컬럼"
              />
            </div>
          )}
        </div>
      )}

      {/* 변경 값 타입 */}
      {rule.targetColumn && (
        <>
          <div className="space-y-1">
            <Label className="text-[10px]">변경 값</Label>
            <div className="flex items-center gap-3">
              <label className="flex items-center gap-1 text-[10px]">
                <input
                  type="radio"
                  name={`valueType-${idx}`}
                  checked={rule.valueType === "fixed"}
                  onChange={() => onUpdate({ valueType: "fixed" })}
                  className="h-3 w-3"
                />
                고정값
              </label>
              <label className="flex items-center gap-1 text-[10px]">
                <input
                  type="radio"
                  name={`valueType-${idx}`}
                  checked={rule.valueType === "conditional"}
                  onChange={() => onUpdate({ valueType: "conditional" })}
                  className="h-3 w-3"
                />
                조건부
              </label>
            </div>
          </div>

          {/* 고정값 */}
          {rule.valueType === "fixed" && (
            <div className="space-y-1">
              <Input
                value={rule.fixedValue ?? ""}
                onChange={(e) => onUpdate({ fixedValue: e.target.value })}
                className="h-7 text-xs"
                placeholder="변경할 값 입력"
              />
            </div>
          )}

          {/* 조건부 */}
          {rule.valueType === "conditional" && (
            <div className="space-y-2 rounded border border-dashed border-muted-foreground/30 p-2">
              {conditions.map((cond, cIdx) => (
                <div key={cIdx} className="space-y-1">
                  <div className="flex items-center gap-1">
                    <span className="shrink-0 text-[10px] text-muted-foreground">만약</span>
                    <ColumnCombobox
                      columns={columns}
                      value={cond.whenColumn}
                      onSelect={(v) => updateCondition(cIdx, { whenColumn: v })}
                      placeholder="컬럼"
                    />
                    <Select
                      value={cond.operator}
                      onValueChange={(v) => updateCondition(cIdx, { operator: v as "=" | "!=" | ">" | "<" | ">=" | "<=" })}
                    >
                      <SelectTrigger className="h-7 w-14 text-[10px]">
                        <SelectValue />
                      </SelectTrigger>
                      <SelectContent>
                        {["=", "!=", ">", "<", ">=", "<="].map((op) => (
                          <SelectItem key={op} value={op} className="text-xs">{op}</SelectItem>
                        ))}
                      </SelectContent>
                    </Select>
                    <Input
                      value={cond.whenValue}
                      onChange={(e) => updateCondition(cIdx, { whenValue: e.target.value })}
                      className="h-7 w-16 text-[10px]"
                      placeholder="값"
                    />
                    <Button variant="ghost" size="icon" className="h-5 w-5 shrink-0" onClick={() => removeCondition(cIdx)}>
                      <X className="h-3 w-3" />
                    </Button>
                  </div>
                  <div className="flex items-center gap-1 pl-4">
                    <span className="shrink-0 text-[10px] text-muted-foreground">이면 -&gt;</span>
                    <Input
                      value={cond.thenValue}
                      onChange={(e) => updateCondition(cIdx, { thenValue: e.target.value })}
                      className="h-7 text-[10px]"
                      placeholder="변경할 값"
                    />
                  </div>
                </div>
              ))}
              <Button variant="ghost" size="sm" className="w-full text-[10px]" onClick={addCondition}>
                <Plus className="mr-1 h-3 w-3" />
                조건 추가
              </Button>
              <div className="flex items-center gap-1">
                <span className="shrink-0 text-[10px] text-muted-foreground">그 외 -&gt;</span>
                <Input
                  value={defaultValue}
                  onChange={(e) =>
                    onUpdate({
                      conditionalValue: { ...rule.conditionalValue, conditions, defaultValue: e.target.value },
                    })
                  }
                  className="h-7 text-[10px]"
                  placeholder="기본값"
                />
              </div>
            </div>
          )}

        </>
      )}
    </div>
  );
}

// 레지스트리 등록
PopComponentRegistry.registerComponent({
  id: "pop-button",
  name: "버튼",
  description: "액션 버튼 (저장/삭제/API/모달/이벤트/장바구니)",
  category: "action",
  icon: "MousePointerClick",
  component: PopButtonComponent,
  configPanel: PopButtonConfigPanel,
  preview: PopButtonPreviewComponent,
  defaultProps: {
    label: "버튼",
    variant: "default",
    preset: "custom",
    confirm: { enabled: false },
    action: { type: "save" },
  } as PopButtonConfig,
  connectionMeta: {
    sendable: [
      { key: "cart_save_trigger", label: "저장 요청", type: "event", category: "event", description: "장바구니 일괄 저장 요청 (카드 목록에 전달)" },
      { key: "collect_data", label: "데이터 수집 요청", type: "event", category: "event", description: "연결된 컴포넌트에 데이터+매핑 수집 요청" },
      { key: "action_completed", label: "액션 완료", type: "event", category: "event", description: "확정/저장 완료 후 결과 전달" },
    ],
    receivable: [
      { key: "cart_updated", label: "장바구니 상태", type: "event", category: "event", description: "카드 목록에서 장바구니 변경 시 count/isDirty 수신" },
      { key: "cart_save_completed", label: "저장 완료", type: "event", category: "event", description: "카드 목록에서 DB 저장 완료 시 수신" },
      { key: "collected_data", label: "수집된 데이터", type: "event", category: "event", description: "컴포넌트에서 수집한 데이터+매핑 응답" },
      { key: "selected_items", label: "선택된 항목", type: "event", category: "event", description: "카드 목록에서 체크박스로 선택된 항목 수 수신" },
    ],
  },
  touchOptimized: true,
  supportedDevices: ["mobile", "tablet"],
});
