/**
 * 卡片渲染共用 helpers + 子组件。
 *
 * 4 张卡片（角色/场景/道具/声音）共享：
 * - 占位斜条纹背景
 * - 关联计数 dot
 * - 变体 chip
 * - 数据缺失时隐藏对应行（spec §3.4 Level 0）
 */
import React from 'react'
import { cn } from '../../../../utils/cn'

export const STRIPED_BG_CLASS =
  'bg-[repeating-linear-gradient(45deg,var(--nomi-ink-05)_0_23px,var(--nomi-ink-20)_23px_24px)]'

export function UsageDot({ count }: { count: number }): JSX.Element | null {
  if (count <= 0) return null
  return (
    <span className="inline-flex items-center gap-1">
      <span className="inline-block w-1.5 h-1.5 rounded-full bg-nomi-accent" aria-hidden />
      <span className="text-[11px] text-nomi-ink-60 tabular-nums">{count}</span>
    </span>
  )
}

export function VariantChip({ count }: { count: number }): JSX.Element | null {
  if (count <= 0) return null
  return (
    <span
      className={cn(
        'inline-flex items-center rounded-full',
        'bg-nomi-ink-05 text-nomi-ink-60',
        'text-[11px] px-2 py-[1px] tabular-nums',
      )}
    >
      ⊕{count}变体
    </span>
  )
}

export function PlaceholderCenter({ label }: { label: string }): JSX.Element {
  return (
    <div className={cn('flex flex-col items-center justify-center w-full h-full gap-1 pointer-events-none')}>
      <span className="text-[13px] font-medium text-nomi-ink-60 tabular-nums">{label}</span>
      <span className="text-[11px] text-nomi-ink-40">等待生成</span>
    </div>
  )
}

/**
 * L3: 生成节点的"待生成"占位卡。未选中时不再只显斜纹 + "等待生成"，而是给
 * 镜头序号徽标 + 标题 + 提示词首行预览，让用户一眼分清哪个镜头（J3 走查）。
 * - selected：参数面板会盖上来，这里不渲染
 * - needsFirstFrame：video 节点缺首帧 → 提示拖图进来
 * - shotIndex：仅 shots 分类有，非 shots 传 null（不显徽标）
 */
export function PendingGenerationPlaceholder({
  selected,
  needsFirstFrame,
  shotIndex,
  title,
  prompt,
}: {
  selected: boolean
  needsFirstFrame: boolean
  shotIndex: number | null
  title?: string
  prompt?: string
}): JSX.Element | null {
  if (selected) return null
  if (needsFirstFrame) {
    return (
      <div className="flex w-full h-full items-center justify-center pointer-events-none px-4 text-center">
        <span className="text-micro text-nomi-ink-40 leading-relaxed">
          把图片节点拖过来
          <br />
          作为首帧
        </span>
      </div>
    )
  }
  return (
    <div className="flex w-full h-full flex-col pointer-events-none p-2.5 gap-1 overflow-hidden">
      {shotIndex != null ? (
        <span className="self-start inline-flex items-center h-[18px] px-[7px] rounded-full bg-nomi-ink text-nomi-paper text-micro font-bold tabular-nums">
          镜头 {shotIndex}
        </span>
      ) : null}
      {title ? <span className="text-[13px] font-semibold text-nomi-ink-80 truncate">{title}</span> : null}
      {prompt ? (
        <span className="text-caption text-nomi-ink-60 leading-snug overflow-hidden [display:-webkit-box] [-webkit-box-orient:vertical] [-webkit-line-clamp:2]">
          {prompt}
        </span>
      ) : null}
      <span className="mt-auto text-micro text-nomi-ink-40">等待生成</span>
    </div>
  )
}

/**
 * v0.7.1: 卡片上传 CTA — 占位态时显示 + 上传按钮。
 * - image 卡（character/scene/prop）：accept=image/*
 * - audio 卡：accept=audio/*
 * 上传后通过 onUpload(dataUrl, file) 回调写到 node.result。
 */
export function UploadFallback({
  accept,
  label,
  onUpload,
}: {
  accept: string
  label: string
  onUpload: (dataUrl: string, file: File) => void
}): JSX.Element {
  const handleChange = React.useCallback(
    (event: React.ChangeEvent<HTMLInputElement>) => {
      const file = event.currentTarget.files?.[0]
      event.currentTarget.value = ''
      if (!file) return
      const reader = new FileReader()
      reader.onload = (loadEvent) => {
        const dataUrl = loadEvent.target?.result
        if (typeof dataUrl === 'string') onUpload(dataUrl, file)
      }
      reader.readAsDataURL(file)
    },
    [onUpload],
  )
  // v0.7.3 fix: 不 stopPropagation onPointerDown — 否则空卡片没法拖动。
  // drag threshold (2px) 保证短按弹文件框、长按拖动不冲突。
  // 但要拦 click 防止点 label 立刻弹文件框时也触发 selectNode 之外的副作用。
  return (
    <label
      className={cn(
        'flex flex-col items-center justify-center w-full h-full gap-1 cursor-pointer',
        'text-nomi-ink-60 hover:text-nomi-ink hover:bg-nomi-ink-05/50 transition-colors',
      )}
    >
      <span className="text-[13px] font-medium tabular-nums pointer-events-none">+ 上传{label}</span>
      <input className="hidden" type="file" accept={accept} onChange={handleChange} />
    </label>
  )
}

/**
 * 取节点的"placeholder 标签"
 * shots → "分镜 NN"（由 BaseGenerationNode 接管，不走这里）
 * 其它 → 分类名 / fallback title
 */
export function placeholderLabel(categoryName: string | undefined, title: string | undefined): string {
  return categoryName || title || '节点'
}

/** Scene3DEditor 懒加载期间的占位（React.Suspense fallback）。 */
export function Scene3DEditorLoading(): JSX.Element {
  return (
    <div className={cn('flex w-full h-full items-center justify-center bg-nomi-ink-05 text-[12px] text-nomi-ink-45')}>
      3D 编辑器加载中
    </div>
  )
}
