/**
 * 类名合并工具（project_rules §3.9 强制使用）
 *
 * 用于管理条件类名，禁止字符串拼接动态类名（如 `bg-${color}-500`）。
 * 基于 clsx + tailwind-merge 的轻量实现，后续接入 shadcn/ui 时替换为官方 cn()。
 */

type ClassValue =
  | string
  | number
  | null
  | false
  | undefined
  | ClassValue[]
  | { [key: string]: unknown };

/**
 * 合并类名，过滤 falsy 值。
 *
 * @example
 * cn("px-2 py-1", isActive && "bg-primary", { "text-muted": isDisabled })
 */
export function cn(...inputs: ClassValue[]): string {
  const classes: string[] = [];

  for (const input of inputs) {
    if (!input) continue;

    if (typeof input === "string" || typeof input === "number") {
      classes.push(String(input));
      continue;
    }

    if (Array.isArray(input)) {
      const nested = cn(...input);
      if (nested) classes.push(nested);
      continue;
    }

    if (typeof input === "object") {
      for (const [key, value] of Object.entries(input)) {
        if (value) classes.push(key);
      }
    }
  }

  // 去重 + 合并 Tailwind 冲突类（基础实现，后续替换为 tailwind-merge）
  return dedupeTailwindClasses(classes.join(" "));
}

/**
 * 基础 Tailwind 类去重（同一前缀后者覆盖前者）。
 * 完整实现待引入 tailwind-merge。
 */
function dedupeTailwindClasses(className: string): string {
  const seen = new Set<string>();
  const tokens = className.split(/\s+/).filter(Boolean);

  // 反向遍历，保留后出现的同类令牌
  for (let i = tokens.length - 1; i >= 0; i--) {
    const token = tokens[i];
    if (!token) continue;

    const prefix = getTailwindPrefix(token);
    const key = prefix ? `__${prefix}` : token;

    if (seen.has(key)) continue;
    seen.add(key);
  }

  // 恢复原始顺序
  return tokens
    .filter((t) => t && (seen.has(t) || seen.has(`__${getTailwindPrefix(t)}`)))
    .join(" ");
}

function getTailwindPrefix(token: string): string | null {
  // 匹配 Tailwind 前缀：bg- text- p- m- w- h- border- 等
  const match = token.match(
    /^(bg|text|p|m|px|py|mx|my|w|h|min-h|min-w|border|rounded|shadow|font|leading|tracking|gap|space|flex|grid|col|row|inset|top|right|bottom|left|z|opacity|transition|duration|delay|animate|hover|focus|sm|md|lg|xl|2xl)-/,
  );
  return match ? match[1] : null;
}
