/* ============================================================================
 * TDS Asset (Mobile, 2026-03)  ─  Task #158
 * ----------------------------------------------------------------------------
 *  - 루트 namespace `Asset` 글로벌 + Frame 베이스 + 5 Wrapped + 5 Content + frameShape 프리셋 11종
 *  - Stepper.AssetFrame(#149) 와는 의도적으로 분리: Stepper 안 좌측 마커 전용 vs 화면 어디서나 쓰는 범용 Asset.
 *  - Toast.Icon(#154) 와도 분리: Toast 내부 24×24 고정 아이콘 vs 자유 크기 Asset.Icon.
 *  - 모든 색·라운드·간격은 var(--tds-…) 토큰 사용. 하드코딩 없음.
 *  - window.adaptive (#157 에서 IIFE 로 초기화됨) 를 backgroundColor 인자에 그대로 사용 가능.
 * ========================================================================= */

(function ensureAdaptive() {
  // AgreementV4(#157) 가 먼저 로드되어 있으면 그대로 사용.
  // 단독 데모 등으로 Asset 만 먼저 마운트되는 경우를 대비해 가드.
  if (typeof window === "undefined") return;
  if (window.adaptive && typeof window.adaptive === "object") return;
  var hues = ["red", "orange", "yellow", "green", "teal", "blue", "purple", "grey"];
  var steps = [50, 100, 200, 300, 400, 500, 600, 700, 800, 900];
  var out = { white: "#ffffff", black: "#000000", transparent: "transparent" };
  hues.forEach(function (h) {
    steps.forEach(function (s) { out[h + s] = "var(--tds-" + h + "-" + s + ")"; });
  });
  window.adaptive = out;
})();

/* ----------------------------------------------------------------------------
 * 1. Frame 프리셋 (`Asset.frameShape`)
 *    - radius 는 number(px) 또는 string('50%' / 'var(--tds-radius-…)')
 *    - 호출자가 직접 {width,height,radius} 를 줘도 동작 (FrameShapeType)
 * ------------------------------------------------------------------------- */
const __ASSET_FRAME_SHAPES = Object.freeze({
  // Square — 정사각, 작은 라운드
  SquareSmall:      Object.freeze({ width: 36, height: 36, radius: 8  }),
  SquareMedium:     Object.freeze({ width: 48, height: 48, radius: 10 }),
  SquareLarge:      Object.freeze({ width: 64, height: 64, radius: 14 }),
  // Rectangle — 가로 긴 직사각
  RectangleMedium:  Object.freeze({ width: 64, height: 48, radius: 10 }),
  RectangleLarge:   Object.freeze({ width: 96, height: 64, radius: 14 }),
  // Circle — 정원
  CircleSmall:      Object.freeze({ width: 36, height: 36, radius: "50%" }),
  CircleMedium:     Object.freeze({ width: 48, height: 48, radius: "50%" }),
  CircleLarge:      Object.freeze({ width: 64, height: 64, radius: "50%" }),
  // Card — 세로 긴 카드
  CardSmall:        Object.freeze({ width: 80,  height: 96,  radius: 12 }),
  CardMedium:       Object.freeze({ width: 104, height: 120, radius: 14 }),
  CardLarge:        Object.freeze({ width: 128, height: 144, radius: 16 }),
});

const __ASSET_ACC_POSITIONS = ["top-left", "top-right", "bottom-left", "bottom-right"];
const __ASSET_ACC_MASKINGS  = ["circle", "none"];
const __ASSET_SCALE_TYPES   = ["fit", "crop"];

/* ------- helpers ---------------------------------------------------------- */
function __assetSizeToCss(v) {
  // number → "Npx", string → 그대로, 그 외 → undefined
  if (typeof v === "number" && Number.isFinite(v)) return v + "px";
  if (typeof v === "string" && v.length > 0) return v;
  return undefined;
}
function __assetClampScale(v) {
  if (typeof v !== "number" || !Number.isFinite(v)) return 1;
  if (v <= 0) return 1;
  if (v > 1) return 1;
  return v;
}
function __assetWarn(msg) {
  if (typeof console !== "undefined" && console.warn) console.warn("[Asset] " + msg);
}
function __assetEnum(value, allowed, fallback, propName) {
  if (allowed.indexOf(value) === -1) {
    __assetWarn(propName + ' 는 ' + JSON.stringify(allowed) + " 중 하나여야 해요. 받은 값: " +
      JSON.stringify(value) + " — '" + fallback + "' 로 폴백.");
    return fallback;
  }
  return value;
}

/* ============================================================================
 * 2. Asset.Frame ─ 베이스 컨테이너
 *    props: content*, shape*, backgroundColor, color, acc, accPosition, accMasking, overlap
 * ========================================================================= */
function AssetFrame(props) {
  const {
    content,
    shape,
    backgroundColor,
    color,
    acc,
    accPosition = "bottom-right",
    accMasking  = "none",
    overlap,
    id,
    className,
    style,
    ...rest
  } = props || {};

  if (content == null) __assetWarn("Asset.Frame 에 content 가 없어요. 빈 프레임이 그려져요.");
  if (shape == null || typeof shape !== "object") __assetWarn("Asset.Frame 에 shape 가 없어요. width·height 가 자동 부여되지 않아 크기가 0 일 수 있어요.");

  const safeShape  = (shape && typeof shape === "object") ? shape : {};
  const accPos     = __assetEnum(accPosition, __ASSET_ACC_POSITIONS, "bottom-right", "accPosition");
  const accMask    = __assetEnum(accMasking,  __ASSET_ACC_MASKINGS,  "none",         "accMasking");

  // 인라인 style 매핑 (CSS 변수로 흘려서 ::before/::after 도 사용)
  const cssVars = {};
  const w = __assetSizeToCss(safeShape.width);
  const h = __assetSizeToCss(safeShape.height);
  const r = __assetSizeToCss(safeShape.radius);
  if (w) cssVars["--tds-asset-w"] = w;
  if (h) cssVars["--tds-asset-h"] = h;
  if (r) cssVars["--tds-asset-r"] = r;
  if (backgroundColor) cssVars["--tds-asset-bg"]    = backgroundColor;
  if (color)           cssVars["--tds-asset-color"] = color;

  // 액세서리 사이즈/위치 (acc.width/height/x/y 모두 옵셔널)
  if (acc != null) {
    var accCfg = (safeShape && safeShape.acc && typeof safeShape.acc === "object") ? safeShape.acc : {};
    var aw = __assetSizeToCss(accCfg.width);
    var ah = __assetSizeToCss(accCfg.height);
    var ax = __assetSizeToCss(accCfg.x);
    var ay = __assetSizeToCss(accCfg.y);
    if (aw) cssVars["--tds-asset-acc-w"] = aw;
    if (ah) cssVars["--tds-asset-acc-h"] = ah;
    if (ax) cssVars["--tds-asset-acc-x"] = ax;
    if (ay) cssVars["--tds-asset-acc-y"] = ay;
  }

  // overlap — 배경에 겹침 효과 (border 색 = overlap.color, ::before pseudo 로 표현)
  // FrameOverlapShapeType 의 x/y/blur/spread 는 shape.overlap 에서 옴 (옵셔널).
  if (overlap && typeof overlap === "object" && overlap.color) {
    cssVars["--tds-asset-overlap-color"] = overlap.color;
    var ovlCfg = (safeShape && safeShape.overlap && typeof safeShape.overlap === "object") ? safeShape.overlap : {};
    var ox = __assetSizeToCss(ovlCfg.x)      || "6px";
    var oy = __assetSizeToCss(ovlCfg.y)      || "6px";
    var ob = __assetSizeToCss(ovlCfg.blur)   || "0px";
    var os = __assetSizeToCss(ovlCfg.spread) || "0px";
    cssVars["--tds-asset-overlap-x"]      = ox;
    cssVars["--tds-asset-overlap-y"]      = oy;
    cssVars["--tds-asset-overlap-blur"]   = ob;
    cssVars["--tds-asset-overlap-spread"] = os;
  }

  const classes = [
    "tds-asset-frame",
    overlap && overlap.color ? "tds-asset-frame--has-overlap" : "",
    acc != null ? "tds-asset-frame--has-acc" : "",
    acc != null ? "tds-asset-frame--acc-" + accPos : "",
    acc != null && accMask === "circle" ? "tds-asset-frame--acc-mask-circle" : "",
    className || "",
  ].filter(Boolean).join(" ");

  return (
    <div id={id} className={classes} style={Object.assign({}, cssVars, style || {})} {...rest}>
      <div className="tds-asset-frame__bg" aria-hidden="true" />
      <div className="tds-asset-frame__content">{content}</div>
      {acc != null ? <div className="tds-asset-frame__acc">{acc}</div> : null}
    </div>
  );
}

/* ============================================================================
 * 3. Content 컴포넌트 5종
 * ========================================================================= */

/* ---- ContentImage -------------------------------------------------------- */
function AssetContentImage(props) {
  const { src, alt, scaleType = "fit", scale, style, className, ...rest } = props || {};
  if (!src) __assetWarn("Asset.ContentImage 에 src 가 없어요.");
  const t = __assetEnum(scaleType, __ASSET_SCALE_TYPES, "fit", "scaleType");
  const s = scale != null ? __assetClampScale(scale) : 1;
  const inlineStyle = Object.assign(
    {
      objectFit: t === "crop" ? "cover" : "contain",
      width:  s === 1 ? "100%" : (s * 100) + "%",
      height: s === 1 ? "100%" : (s * 100) + "%",
    },
    style || {}
  );
  return (
    <img
      src={src}
      alt={alt != null ? alt : ""}
      className={["tds-asset-content tds-asset-content--image", className || ""].filter(Boolean).join(" ")}
      style={inlineStyle}
      draggable={false}
      {...rest}
    />
  );
}

/* ---- ContentIcon --------------------------------------------------------- */
function AssetContentIcon(props) {
  const { name, color, size, style, className, ...rest } = props || {};
  if (!name) __assetWarn("Asset.ContentIcon 에 name 이 없어요.");

  // window.IOSIcon 가 있으면 그쪽으로 위임 (우리 앱 표준 아이콘 라이브러리)
  const IOSIcon = (typeof window !== "undefined") ? window.IOSIcon : null;

  const inlineStyle = Object.assign(
    color ? { color: color } : {},
    style || {}
  );

  if (IOSIcon) {
    return (
      <span
        className={["tds-asset-content tds-asset-content--icon", className || ""].filter(Boolean).join(" ")}
        style={inlineStyle}
        {...rest}
      >
        <IOSIcon name={name} size={size || "70%"} color="currentColor" />
      </span>
    );
  }

  // 폴백: 단순 동그라미 (IOSIcon 미로드)
  return (
    <span
      className={["tds-asset-content tds-asset-content--icon tds-asset-content--icon-fallback", className || ""].filter(Boolean).join(" ")}
      style={inlineStyle}
      aria-hidden="true"
      {...rest}
    />
  );
}

/* ---- ContentLottie ------------------------------------------------------- */
function AssetContentLottie(props) {
  const { src, scaleType = "fit", loop = true, autoplay = true, style, className, ...rest } = props || {};
  if (!src) __assetWarn("Asset.ContentLottie 에 src 가 없어요.");
  const t = __assetEnum(scaleType, __ASSET_SCALE_TYPES, "fit", "scaleType");

  const ref = React.useRef(null);
  React.useEffect(function () {
    if (!ref.current || !src) return undefined;
    const lottie = (typeof window !== "undefined") ? window.lottie : null;
    if (!lottie || typeof lottie.loadAnimation !== "function") return undefined;
    let anim = null;
    try {
      anim = lottie.loadAnimation({
        container: ref.current,
        renderer:  "svg",
        loop:      loop,
        autoplay:  autoplay,
        path:      src,
      });
    } catch (e) { __assetWarn("lottie loadAnimation 실패: " + (e && e.message ? e.message : e)); }
    return function cleanup() {
      try { if (anim) anim.destroy(); } catch (_) {}
    };
  }, [src, loop, autoplay]);

  // Lottie 미설치 폴백: src 가 .json 이면 빈 회색 박스 + 경고, .gif/.png 등이면 img 로 표시
  const isJson = typeof src === "string" && /\.json($|\?)/i.test(src);
  const fallbackImg = !isJson && src;

  const lottieStyle = Object.assign(
    {
      width:  "100%",
      height: "100%",
      objectFit: t === "crop" ? "cover" : "contain",
    },
    style || {}
  );

  return (
    <div
      ref={ref}
      className={["tds-asset-content tds-asset-content--lottie", className || ""].filter(Boolean).join(" ")}
      style={lottieStyle}
      role="img"
      aria-hidden={true}
      {...rest}
    >
      {/* lottie 가 마운트되면 SVG 가 ref 안에 채워짐. 미로드 + 이미지 src 면 폴백 이미지. */}
      {fallbackImg
        ? <img src={src} alt="" style={{ width: "100%", height: "100%", objectFit: t === "crop" ? "cover" : "contain" }} draggable={false} />
        : null}
    </div>
  );
}

/* ---- ContentText --------------------------------------------------------- */
function AssetContentText(props) {
  const { children, style, className, ...rest } = props || {};
  return (
    <span
      className={["tds-asset-content tds-asset-content--text", className || ""].filter(Boolean).join(" ")}
      style={style}
      {...rest}
    >
      {children}
    </span>
  );
}

/* ---- ContentVideo -------------------------------------------------------- */
function AssetContentVideo(props) {
  const {
    src,
    autoPlay   = true,
    loop       = true,
    muted      = true,
    controls   = false,
    playsInline = true,
    scaleType  = "fit",
    poster,
    style,
    className,
    ...rest
  } = props || {};
  if (!src) __assetWarn("Asset.ContentVideo 에 src 가 없어요.");
  const t = __assetEnum(scaleType, __ASSET_SCALE_TYPES, "fit", "scaleType");

  const inlineStyle = Object.assign(
    {
      width:  "100%",
      height: "100%",
      objectFit: t === "crop" ? "cover" : "contain",
      background: "transparent",
    },
    style || {}
  );

  return (
    <video
      src={src}
      autoPlay={autoPlay}
      loop={loop}
      muted={muted}
      controls={controls}
      playsInline={playsInline}
      poster={poster}
      className={["tds-asset-content tds-asset-content--video", className || ""].filter(Boolean).join(" ")}
      style={inlineStyle}
      {...rest}
    />
  );
}

/* ============================================================================
 * 4. Wrapped 컴포넌트 5종 — Frame + Content 조합
 *    (스펙: Frame.shape → frameShape 로 prop 명 변경)
 * ========================================================================= */
function __assetSplitFrameProps(p) {
  // frameShape 는 string(프리셋 키) 또는 객체 둘 다 받음
  let shape = p.frameShape;
  if (typeof shape === "string") {
    if (__ASSET_FRAME_SHAPES[shape]) shape = __ASSET_FRAME_SHAPES[shape];
    else { __assetWarn("frameShape 프리셋 키 '" + shape + "' 를 찾을 수 없어요. 객체로 전달하세요."); shape = undefined; }
  }
  return {
    frameProps: {
      shape:           shape,
      backgroundColor: p.backgroundColor,
      color:           p.color,
      acc:             p.acc,
      accPosition:     p.accPosition,
      accMasking:      p.accMasking,
      overlap:         p.overlap,
      id:              p.id,
      className:       p.className,
      style:           p.style,
    },
    rest: p,
  };
}
function __assetStripFrameKeys(p) {
  const omit = ["frameShape", "backgroundColor", "color", "acc", "accPosition",
                "accMasking", "overlap", "id", "className", "style"];
  const out = {};
  Object.keys(p || {}).forEach(function (k) { if (omit.indexOf(k) === -1) out[k] = p[k]; });
  return out;
}

/* ---- Asset.Icon ---------------------------------------------------------- */
function AssetIcon(props) {
  const { frameProps } = __assetSplitFrameProps(props);
  const contentProps = __assetStripFrameKeys(props);
  // 아이콘 색은 Frame 의 color 변수를 따라가도록 currentColor 사용
  if (props.color && !frameProps.color) frameProps.color = props.color;
  return <AssetFrame {...frameProps} content={<AssetContentIcon {...contentProps} />} />;
}

/* ---- Asset.Image --------------------------------------------------------- */
function AssetImage(props) {
  const { frameProps } = __assetSplitFrameProps(props);
  const contentProps = __assetStripFrameKeys(props);
  return <AssetFrame {...frameProps} content={<AssetContentImage {...contentProps} />} />;
}

/* ---- Asset.Lottie -------------------------------------------------------- */
function AssetLottie(props) {
  const { frameProps } = __assetSplitFrameProps(props);
  const contentProps = __assetStripFrameKeys(props);
  return <AssetFrame {...frameProps} content={<AssetContentLottie {...contentProps} />} />;
}

/* ---- Asset.Text ---------------------------------------------------------- */
function AssetText(props) {
  const { frameProps } = __assetSplitFrameProps(props);
  const contentProps = __assetStripFrameKeys(props);
  return <AssetFrame {...frameProps} content={<AssetContentText {...contentProps} />} />;
}

/* ---- Asset.Video --------------------------------------------------------- */
function AssetVideo(props) {
  const { frameProps } = __assetSplitFrameProps(props);
  const contentProps = __assetStripFrameKeys(props);
  return <AssetFrame {...frameProps} content={<AssetContentVideo {...contentProps} />} />;
}

/* ============================================================================
 * 5. Asset namespace export
 * ========================================================================= */
const Asset = {
  // 베이스
  Frame: AssetFrame,
  // Content primitives (Frame.content 에 직접 넘길 때 사용)
  ContentIcon:   AssetContentIcon,
  ContentImage:  AssetContentImage,
  ContentLottie: AssetContentLottie,
  ContentText:   AssetContentText,
  ContentVideo:  AssetContentVideo,
  // Wrapped (Frame + Content 조합)
  Icon:   AssetIcon,
  Image:  AssetImage,
  Lottie: AssetLottie,
  Text:   AssetText,
  Video:  AssetVideo,
  // 프리셋
  frameShape: __ASSET_FRAME_SHAPES,
};

if (typeof window !== "undefined") {
  window.Asset = Asset;
  Object.assign(window, { Asset });
}
