"use client";

/**
 * pop-card-list-v2 셀 타입별 렌더러
 *
 * 각 셀 타입은 독립 함수로 구현되어 CardV2Grid에서 type별 dispatch로 호출된다.
 * 기존 pop-card-list의 카드 내부 렌더링과 pop-string-list의 CardModeView 패턴을 결합.
 */

import React, { useMemo, useState } from "react";
import {
  ShoppingCart, X, Package, Truck, Box, Archive, Heart, Star,
  Loader2, CheckCircle2, CircleDot, Clock,
  type LucideIcon,
} from "lucide-react";
import { Button } from "@/components/ui/button";
import {
  Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription,
} from "@/components/ui/dialog";
import { cn } from "@/lib/utils";
import type { CardCellDefinitionV2, PackageEntry, TimelineProcessStep, ActionButtonDef } from "../types";
import { DEFAULT_CARD_IMAGE, VIRTUAL_SUB_STATUS, VIRTUAL_SUB_SEMANTIC } from "../types";
import type { ButtonVariant } from "../pop-button";

type RowData = Record<string, unknown>;

// ===== 공통 유틸 =====

const LUCIDE_ICON_MAP: Record<string, LucideIcon> = {
  ShoppingCart, Package, Truck, Box, Archive, Heart, Star,
};

function DynamicLucideIcon({ name, size = 20 }: { name?: string; size?: number }) {
  if (!name) return <ShoppingCart size={size} />;
  const IconComp = LUCIDE_ICON_MAP[name];
  if (!IconComp) return <ShoppingCart size={size} />;
  return <IconComp size={size} />;
}

function formatValue(value: unknown): string {
  if (value === null || value === undefined) return "-";
  if (typeof value === "number") return value.toLocaleString();
  if (typeof value === "boolean") return value ? "예" : "아니오";
  if (value instanceof Date) return value.toLocaleDateString();
  if (typeof value === "string" && /^\d{4}-\d{2}-\d{2}/.test(value)) {
    const date = new Date(value);
    if (!isNaN(date.getTime())) {
      return `${String(date.getMonth() + 1).padStart(2, "0")}-${String(date.getDate()).padStart(2, "0")}`;
    }
  }
  return String(value);
}

const FONT_SIZE_MAP = { xs: "10px", sm: "11px", md: "12px", lg: "14px" } as const;
const FONT_WEIGHT_MAP = { normal: 400, medium: 500, bold: 700 } as const;

// ===== 셀 렌더러 Props =====

export interface CellRendererProps {
  cell: CardCellDefinitionV2;
  row: RowData;
  inputValue?: number;
  isCarted?: boolean;
  isButtonLoading?: boolean;
  onInputClick?: (e: React.MouseEvent) => void;
  onCartAdd?: () => void;
  onCartCancel?: () => void;
  onButtonClick?: (cell: CardCellDefinitionV2, row: RowData) => void;
  onActionButtonClick?: (taskPreset: string, row: RowData, buttonConfig?: Record<string, unknown>) => void;
  onEnterSelectMode?: (whenStatus: string, buttonConfig: Record<string, unknown>) => void;
  packageEntries?: PackageEntry[];
  inputUnit?: string;
  currentUserId?: string;
}

// ===== 메인 디스패치 =====

export function renderCellV2(props: CellRendererProps): React.ReactNode {
  switch (props.cell.type) {
    case "text":
      return <TextCell {...props} />;
    case "field":
      return <FieldCell {...props} />;
    case "image":
      return <ImageCell {...props} />;
    case "badge":
      return <BadgeCell {...props} />;
    case "button":
      return <ButtonCell {...props} />;
    case "number-input":
      return <NumberInputCell {...props} />;
    case "cart-button":
      return <CartButtonCell {...props} />;
    case "package-summary":
      return <PackageSummaryCell {...props} />;
    case "status-badge":
      return <StatusBadgeCell {...props} />;
    case "timeline":
      return <TimelineCell {...props} />;
    case "action-buttons":
      return <ActionButtonsCell {...props} />;
    case "footer-status":
      return <FooterStatusCell {...props} />;
    default:
      return <span className="text-[10px] text-muted-foreground">알 수 없는 셀 타입</span>;
  }
}

// ===== 1. text =====

function TextCell({ cell, row }: CellRendererProps) {
  const value = cell.columnName ? row[cell.columnName] : "";
  const fs = FONT_SIZE_MAP[cell.fontSize || "md"];
  const fw = FONT_WEIGHT_MAP[cell.fontWeight || "normal"];

  return (
    <span
      className="truncate"
      style={{ fontSize: fs, fontWeight: fw, color: cell.textColor || undefined }}
    >
      {formatValue(value)}
    </span>
  );
}

// ===== 2. field (라벨+값) =====

function FieldCell({ cell, row, inputValue }: CellRendererProps) {
  const valueType = cell.valueType || "column";
  const fs = FONT_SIZE_MAP[cell.fontSize || "md"];

  const displayValue = useMemo(() => {
    if (valueType !== "formula") {
      const raw = cell.columnName ? row[cell.columnName] : undefined;
      const formatted = formatValue(raw);
      return cell.unit ? `${formatted} ${cell.unit}` : formatted;
    }

    if (cell.formulaLeft && cell.formulaOperator) {
      const rightVal =
        (cell.formulaRightType || "input") === "input"
          ? (inputValue ?? 0)
          : Number(row[cell.formulaRight || ""] ?? 0);
      const leftVal = Number(row[cell.formulaLeft] ?? 0);

      let result: number | null = null;
      switch (cell.formulaOperator) {
        case "+": result = leftVal + rightVal; break;
        case "-": result = leftVal - rightVal; break;
        case "*": result = leftVal * rightVal; break;
        case "/": result = rightVal !== 0 ? leftVal / rightVal : null; break;
      }

      if (result !== null && isFinite(result)) {
        const formatted = (Math.round(result * 100) / 100).toLocaleString();
        return cell.unit ? `${formatted} ${cell.unit}` : formatted;
      }
      return "-";
    }
    return "-";
  }, [valueType, cell, row, inputValue]);

  const isFormula = valueType === "formula";
  const isLabelLeft = cell.labelPosition === "left";

  return (
    <div
      className={isLabelLeft ? "flex items-baseline gap-1" : "flex flex-col"}
      style={{ fontSize: fs }}
    >
      {cell.label && (
        <span className="shrink-0 text-[10px] text-muted-foreground">
          {cell.label}{isLabelLeft ? ":" : ""}
        </span>
      )}
      <span
        className="truncate font-medium"
        style={{ color: cell.textColor || (isFormula ? "#ea580c" : undefined) }}
      >
        {displayValue}
      </span>
    </div>
  );
}

// ===== 3. image =====

function ImageCell({ cell, row }: CellRendererProps) {
  const value = cell.columnName ? row[cell.columnName] : "";
  const imageUrl = value ? String(value) : (cell.defaultImage || DEFAULT_CARD_IMAGE);

  return (
    <div className="flex h-full w-full items-center justify-center overflow-hidden rounded-md border bg-muted/30">
      <img
        src={imageUrl}
        alt={cell.label || ""}
        className="h-full w-full object-contain p-1"
        onError={(e) => {
          const target = e.target as HTMLImageElement;
          if (target.src !== DEFAULT_CARD_IMAGE) target.src = DEFAULT_CARD_IMAGE;
        }}
      />
    </div>
  );
}

// ===== 4. badge =====

function BadgeCell({ cell, row }: CellRendererProps) {
  const value = cell.columnName ? row[cell.columnName] : "";
  return (
    <span className="inline-flex items-center rounded-full bg-primary/10 px-2 py-0.5 text-[10px] font-medium text-primary">
      {formatValue(value)}
    </span>
  );
}

// ===== 5. button =====

function ButtonCell({ cell, row, isButtonLoading, onButtonClick }: CellRendererProps) {
  return (
    <Button
      variant={cell.buttonVariant || "outline"}
      size="sm"
      className="h-7 text-[10px]"
      disabled={isButtonLoading}
      onClick={(e) => {
        e.stopPropagation();
        onButtonClick?.(cell, row);
      }}
    >
      {isButtonLoading ? (
        <Loader2 className="mr-1 h-3 w-3 animate-spin" />
      ) : null}
      {cell.label || formatValue(cell.columnName ? row[cell.columnName] : "")}
    </Button>
  );
}

// ===== 6. number-input =====

function NumberInputCell({ cell, row, inputValue, onInputClick }: CellRendererProps) {
  const unit = cell.inputUnit || "EA";
  return (
    <button
      type="button"
      onClick={(e) => {
        e.stopPropagation();
        onInputClick?.(e);
      }}
      className="w-full rounded-lg border-2 border-input bg-background px-2 py-1.5 text-center hover:border-primary active:bg-muted"
    >
      <span className="block text-lg font-bold leading-tight">
        {(inputValue ?? 0).toLocaleString()}
      </span>
      <span className="block text-[12px] text-muted-foreground">{unit}</span>
    </button>
  );
}

// ===== 7. cart-button =====

function CartButtonCell({ cell, row, isCarted, onCartAdd, onCartCancel }: CellRendererProps) {
  const iconSize = 18;
  const label = cell.cartLabel || "담기";
  const cancelLabel = cell.cartCancelLabel || "취소";

  if (isCarted) {
    return (
      <button
        type="button"
        onClick={(e) => { e.stopPropagation(); onCartCancel?.(); }}
        className="flex w-full flex-col items-center justify-center gap-0.5 rounded-xl bg-destructive px-2 py-1.5 text-destructive-foreground transition-colors duration-150 hover:bg-destructive/90 active:bg-destructive/80"
      >
        <X size={iconSize} />
        <span className="text-[10px] font-semibold leading-tight">{cancelLabel}</span>
      </button>
    );
  }

  return (
    <button
      type="button"
      onClick={(e) => { e.stopPropagation(); onCartAdd?.(); }}
      className="flex w-full flex-col items-center justify-center gap-0.5 rounded-xl bg-linear-to-br from-amber-400 to-orange-500 px-2 py-1.5 text-white transition-colors duration-150 hover:from-amber-500 hover:to-orange-600 active:from-amber-600 active:to-orange-700"
    >
      {cell.cartIconType === "emoji" && cell.cartIconValue ? (
        <span style={{ fontSize: `${iconSize}px` }}>{cell.cartIconValue}</span>
      ) : (
        <DynamicLucideIcon name={cell.cartIconValue} size={iconSize} />
      )}
      <span className="text-[10px] font-semibold leading-tight">{label}</span>
    </button>
  );
}

// ===== 8. package-summary =====

function PackageSummaryCell({ cell, packageEntries, inputUnit }: CellRendererProps) {
  if (!packageEntries || packageEntries.length === 0) return null;

  return (
    <div className="w-full border-t bg-emerald-50">
      {packageEntries.map((entry, idx) => (
        <div key={idx} className="flex items-center justify-between px-3 py-1.5">
          <div className="flex items-center gap-2">
            <span className="rounded-full bg-emerald-500 px-2 py-0.5 text-[10px] font-bold text-white">
              포장완료
            </span>
            <Package className="h-4 w-4 text-emerald-600" />
            <span className="text-xs font-medium text-emerald-700">
              {entry.packageCount}{entry.unitLabel} x {entry.quantityPerUnit}
            </span>
          </div>
          <span className="text-xs font-bold text-emerald-700">
            = {entry.totalQuantity.toLocaleString()}{inputUnit || "EA"}
          </span>
        </div>
      ))}
    </div>
  );
}

// ===== 9. status-badge =====

const STATUS_COLORS: Record<string, { bg: string; text: string }> = {
  waiting: { bg: "#94a3b820", text: "#64748b" },
  accepted: { bg: "#3b82f620", text: "#2563eb" },
  in_progress: { bg: "#f59e0b20", text: "#d97706" },
  completed: { bg: "#10b98120", text: "#059669" },
};

function StatusBadgeCell({ cell, row }: CellRendererProps) {
  const hasSubStatus = row[VIRTUAL_SUB_STATUS] !== undefined;
  const effectiveValue = hasSubStatus
    ? row[VIRTUAL_SUB_STATUS]
    : (cell.statusColumn ? row[cell.statusColumn] : (cell.columnName ? row[cell.columnName] : ""));
  const strValue = String(effectiveValue || "");
  const mapped = cell.statusMap?.find((m) => m.value === strValue);

  if (mapped) {
    return (
      <span
        className="inline-flex items-center rounded-full px-2.5 py-0.5 text-[10px] font-semibold"
        style={{ backgroundColor: `${mapped.color}20`, color: mapped.color }}
      >
        {mapped.label}
      </span>
    );
  }

  const defaultColors = STATUS_COLORS[strValue];
  if (defaultColors) {
    const labelMap: Record<string, string> = {
      waiting: "대기", accepted: "접수", in_progress: "진행", completed: "완료",
    };
    return (
      <span
        className="inline-flex items-center rounded-full px-2.5 py-0.5 text-[10px] font-semibold"
        style={{ backgroundColor: defaultColors.bg, color: defaultColors.text }}
      >
        {labelMap[strValue] || strValue}
      </span>
    );
  }

  return (
    <span className="inline-flex items-center rounded-full bg-muted px-2.5 py-0.5 text-[10px] font-medium text-muted-foreground">
      {formatValue(effectiveValue)}
    </span>
  );
}

// ===== 10. timeline =====

type TimelineStyle = { chipBg: string; chipText: string; icon: React.ReactNode };

const TIMELINE_SEMANTIC_STYLES: Record<string, TimelineStyle> = {
  done: { chipBg: "#10b981", chipText: "#ffffff", icon: <CheckCircle2 className="h-2.5 w-2.5" /> },
  active: { chipBg: "#3b82f6", chipText: "#ffffff", icon: <CircleDot className="h-2.5 w-2.5 animate-pulse" /> },
  pending: { chipBg: "#e2e8f0", chipText: "#64748b", icon: <Clock className="h-2.5 w-2.5" /> },
};

// 레거시 status 값 → semantic 매핑 (기존 데이터 호환)
const LEGACY_STATUS_TO_SEMANTIC: Record<string, string> = {
  completed: "done", in_progress: "active", accepted: "active", waiting: "pending",
};

function getTimelineStyle(step: TimelineProcessStep): TimelineStyle {
  if (step.semantic) return TIMELINE_SEMANTIC_STYLES[step.semantic] || TIMELINE_SEMANTIC_STYLES.pending;
  const fallback = LEGACY_STATUS_TO_SEMANTIC[step.status];
  return TIMELINE_SEMANTIC_STYLES[fallback || "pending"];
}

function TimelineCell({ cell, row }: CellRendererProps) {
  const processFlow = row.__processFlow__ as TimelineProcessStep[] | undefined;

  if (!processFlow || processFlow.length === 0) {
    const fallback = cell.processColumn ? row[cell.processColumn] : "";
    return (
      <span className="text-[10px] text-muted-foreground">
        {formatValue(fallback)}
      </span>
    );
  }

  const maxVisible = cell.visibleCount || 5;
  const currentIdx = processFlow.findIndex((s) => s.isCurrent);

  type DisplayItem =
    | { kind: "step"; step: TimelineProcessStep }
    | { kind: "count"; count: number; side: "before" | "after" };

  // 현재 항목 기준으로 앞뒤 배분하여 축약
  const displayItems = useMemo((): DisplayItem[] => {
    if (processFlow.length <= maxVisible) {
      return processFlow.map((s) => ({ kind: "step" as const, step: s }));
    }

    const effectiveIdx = Math.max(0, currentIdx);
    const priority = cell.timelinePriority || "before";
    // 숫자칩 2개를 제외한 나머지를 앞뒤로 배분 (priority에 따라 여분 슬롯 방향 결정)
    const slotForSteps = maxVisible - 2;
    const half = Math.floor(slotForSteps / 2);
    const extra = slotForSteps - half - 1;
    const beforeSlots = priority === "before" ? Math.max(half, extra) : Math.min(half, extra);
    const afterSlots = slotForSteps - beforeSlots - 1;

    let startIdx = effectiveIdx - beforeSlots;
    let endIdx = effectiveIdx + afterSlots;

    // 경계 보정
    if (startIdx < 0) {
      endIdx = Math.min(processFlow.length - 1, endIdx + Math.abs(startIdx));
      startIdx = 0;
    }
    if (endIdx >= processFlow.length) {
      startIdx = Math.max(0, startIdx - (endIdx - processFlow.length + 1));
      endIdx = processFlow.length - 1;
    }

    const items: DisplayItem[] = [];
    const beforeCount = startIdx;
    const afterCount = processFlow.length - 1 - endIdx;

    if (beforeCount > 0) {
      items.push({ kind: "count", count: beforeCount, side: "before" });
    }
    for (let i = startIdx; i <= endIdx; i++) {
      items.push({ kind: "step", step: processFlow[i] });
    }
    if (afterCount > 0) {
      items.push({ kind: "count", count: afterCount, side: "after" });
    }

    return items;
  }, [processFlow, maxVisible, currentIdx]);

  const [modalOpen, setModalOpen] = useState(false);

  const completedCount = processFlow.filter((s) => (s.semantic || LEGACY_STATUS_TO_SEMANTIC[s.status]) === "done").length;
  const totalCount = processFlow.length;

  return (
    <>
      <div
        className={cn(
          "flex w-full items-center gap-0.5 overflow-hidden px-0.5",
          cell.showDetailModal !== false && "cursor-pointer",
          cell.align === "center" ? "justify-center" : cell.align === "right" ? "justify-end" : "justify-start",
        )}
        onClick={cell.showDetailModal !== false ? (e) => { e.stopPropagation(); setModalOpen(true); } : undefined}
        title={cell.showDetailModal !== false ? "클릭하여 전체 현황 보기" : undefined}
      >
        {displayItems.map((item, idx) => {
          const isLast = idx === displayItems.length - 1;

          if (item.kind === "count") {
            return (
              <React.Fragment key={`cnt-${item.side}`}>
                <div
                  className="flex h-5 w-5 shrink-0 items-center justify-center rounded-full bg-muted text-[8px] font-bold text-muted-foreground"
                  title={item.side === "before" ? `이전 ${item.count}개` : `이후 ${item.count}개`}
                >
                  {item.count}
                </div>
                {!isLast && <div className="h-px w-1.5 shrink-0 border-t border-dashed border-muted-foreground/40" />}
              </React.Fragment>
            );
          }

          const styles = getTimelineStyle(item.step);

          return (
            <React.Fragment key={item.step.seqNo}>
              <div
                className="flex shrink-0 items-center gap-0.5 rounded-full px-1.5 py-0.5"
                style={{
                  backgroundColor: styles.chipBg,
                  color: styles.chipText,
                  outline: item.step.isCurrent ? "2px solid #2563eb" : "none",
                  outlineOffset: "1px",
                }}
                title={`${item.step.seqNo}. ${item.step.processName} (${item.step.status})`}
              >
                {styles.icon}
                <span className="max-w-[48px] truncate text-[9px] font-medium leading-tight">
                  {item.step.processName}
                </span>
              </div>
              {!isLast && <div className="h-px w-1.5 shrink-0 border-t border-dashed border-muted-foreground/40" />}
            </React.Fragment>
          );
        })}
      </div>

      <Dialog open={modalOpen} onOpenChange={setModalOpen}>
        <DialogContent className="max-w-[95vw] sm:max-w-[500px]">
          <DialogHeader>
            <DialogTitle className="text-base sm:text-lg">전체 현황</DialogTitle>
            <DialogDescription className="text-xs sm:text-sm">
              총 {totalCount}개 중 {completedCount}개 완료
            </DialogDescription>
          </DialogHeader>

          <div className="space-y-0">
            {processFlow.map((step, idx) => {
              const styles = getTimelineStyle(step);
              const sem = step.semantic || LEGACY_STATUS_TO_SEMANTIC[step.status] || "pending";
              const statusLabel = sem === "done" ? "완료" : sem === "active" ? "진행" : "대기";

              return (
                <div key={step.seqNo} className="flex items-center">
                  {/* 세로 연결선 + 아이콘 */}
                  <div className="flex w-8 shrink-0 flex-col items-center">
                    {idx > 0 && <div className="h-3 w-px bg-border" />}
                    <div
                      className="flex h-6 w-6 items-center justify-center rounded-full"
                      style={{ backgroundColor: styles.chipBg, color: styles.chipText }}
                    >
                      {styles.icon}
                    </div>
                    {idx < processFlow.length - 1 && <div className="h-3 w-px bg-border" />}
                  </div>

                  {/* 항목 정보 */}
                  <div className={cn(
                    "ml-2 flex flex-1 items-center justify-between rounded-md px-3 py-2",
                    step.isCurrent && "bg-primary/5 ring-1 ring-primary/30",
                  )}>
                    <div className="flex items-center gap-2">
                      <span className="text-xs text-muted-foreground">{step.seqNo}</span>
                      <span className={cn(
                        "text-sm",
                        step.isCurrent ? "font-semibold" : "font-medium",
                      )}>
                        {step.processName}
                      </span>
                      {step.isCurrent && (
                        <Star className="h-3 w-3 fill-primary text-primary" />
                      )}
                    </div>
                    <span
                      className="rounded-full px-2 py-0.5 text-[10px] font-medium"
                      style={{ backgroundColor: styles.chipBg, color: styles.chipText }}
                    >
                      {statusLabel}
                    </span>
                  </div>
                </div>
              );
            })}
          </div>

          {/* 하단 진행률 바 */}
          <div className="space-y-1 pt-2">
            <div className="flex justify-between text-xs text-muted-foreground">
              <span>진행률</span>
              <span>{totalCount > 0 ? Math.round((completedCount / totalCount) * 100) : 0}%</span>
            </div>
            <div className="h-2 w-full overflow-hidden rounded-full bg-secondary">
              <div
                className="h-full rounded-full bg-primary transition-all duration-300"
                style={{ width: `${totalCount > 0 ? (completedCount / totalCount) * 100 : 0}%` }}
              />
            </div>
          </div>
        </DialogContent>
      </Dialog>
    </>
  );
}

// ===== 11. action-buttons =====

function evaluateShowCondition(btn: ActionButtonDef, row: RowData, currentUserId?: string): "visible" | "disabled" | "hidden" {
  const cond = btn.showCondition;
  if (!cond || cond.type === "always") return "visible";

  let matched = false;

  if (cond.type === "timeline-status") {
    const subStatus = row[VIRTUAL_SUB_STATUS];
    matched = subStatus !== undefined && String(subStatus) === cond.value;
  } else if (cond.type === "column-value" && cond.column) {
    matched = String(row[cond.column] ?? "") === (cond.value ?? "");
  } else if (cond.type === "owner-match" && cond.column) {
    const ownerValue = String(row[cond.column] ?? "");
    matched = !!currentUserId && ownerValue === currentUserId;
  } else {
    return "visible";
  }

  if (matched) return "visible";
  return cond.unmatchBehavior === "disabled" ? "disabled" : "hidden";
}

function ActionButtonsCell({ cell, row, onActionButtonClick, onEnterSelectMode, currentUserId }: CellRendererProps) {
  const processFlow = row.__processFlow__ as { isCurrent: boolean; processId?: string | number }[] | undefined;
  const currentProcess = processFlow?.find((s) => s.isCurrent);
  const currentProcessId = currentProcess?.processId;

  if (cell.actionButtons && cell.actionButtons.length > 0) {
    const evaluated = cell.actionButtons.map((btn) => ({
      btn,
      state: evaluateShowCondition(btn, row, currentUserId),
    }));

    const activeBtn = evaluated.find((e) => e.state === "visible");
    const disabledBtn = activeBtn ? null : evaluated.find((e) => e.state === "disabled");
    const pick = activeBtn || disabledBtn;
    if (!pick) return null;

    const { btn, state } = pick;

    return (
      <div className="flex items-center gap-1">
        <Button
          variant={btn.variant || "outline"}
          size="sm"
          disabled={state === "disabled"}
          className="h-7 text-[10px]"
          onClick={(e) => {
            e.stopPropagation();
            const actions = (btn.clickActions && btn.clickActions.length > 0) ? btn.clickActions : [btn.clickAction];
            const firstAction = actions[0];

            const config: Record<string, unknown> = {
              ...firstAction,
              __allActions: actions,
              selectModeConfig: firstAction.selectModeButtons
                ? { filterStatus: btn.showCondition?.value || "", buttons: firstAction.selectModeButtons }
                : undefined,
            };
            if (currentProcessId !== undefined) config.__processId = currentProcessId;

            if (firstAction.type === "select-mode" && onEnterSelectMode) {
              onEnterSelectMode(btn.showCondition?.value || "", config);
              return;
            }

            onActionButtonClick?.(btn.label, row, config);
          }}
        >
          {btn.label}
        </Button>
      </div>
    );
  }

  // 기존 구조 (actionRules) 폴백
  const hasSubStatus = row[VIRTUAL_SUB_STATUS] !== undefined;
  const statusValue = hasSubStatus
    ? String(row[VIRTUAL_SUB_STATUS] || "")
    : (cell.statusColumn ? String(row[cell.statusColumn] || "") : (cell.columnName ? String(row[cell.columnName] || "") : ""));
  const rules = cell.actionRules || [];
  const matchedRule = rules.find((r) => r.whenStatus === statusValue);
  if (!matchedRule) return null;

  return (
    <div className="flex items-center gap-1">
      {matchedRule.buttons.map((btn, idx) => (
        <Button
          key={idx}
          variant={btn.variant || "outline"}
          size="sm"
          className="h-7 text-[10px]"
          onClick={(e) => {
            e.stopPropagation();
            const config = { ...(btn as unknown as Record<string, unknown>) };
            if (currentProcessId !== undefined) config.__processId = currentProcessId;
            if (btn.clickMode === "select-mode" && onEnterSelectMode) {
              onEnterSelectMode(matchedRule.whenStatus, config);
              return;
            }
            onActionButtonClick?.(btn.taskPreset, row, config);
          }}
        >
          {btn.label}
        </Button>
      ))}
    </div>
  );
}

// ===== 12. footer-status =====

function FooterStatusCell({ cell, row }: CellRendererProps) {
  const value = cell.footerStatusColumn ? row[cell.footerStatusColumn] : "";
  const strValue = String(value || "");
  const mapped = cell.footerStatusMap?.find((m) => m.value === strValue);

  if (!strValue && !cell.footerLabel) return null;

  return (
    <div
      className="flex w-full items-center justify-between px-2 py-1"
      style={{ borderTop: cell.showTopBorder !== false ? "1px solid hsl(var(--border))" : "none" }}
    >
      {cell.footerLabel && (
        <span className="text-[10px] text-muted-foreground">{cell.footerLabel}</span>
      )}
      {mapped ? (
        <span
          className="inline-flex items-center rounded-full px-2 py-0.5 text-[9px] font-semibold"
          style={{ backgroundColor: `${mapped.color}20`, color: mapped.color }}
        >
          {mapped.label}
        </span>
      ) : strValue ? (
        <span className="text-[10px] font-medium text-muted-foreground">
          {strValue}
        </span>
      ) : null}
    </div>
  );
}
