import React, { useMemo } from "react";

function getByPath(obj, path) {
  if (!path) return undefined;
  const parts = String(path).split(".");
  let cur = obj;
  for (const p of parts) {
    if (cur == null) return undefined;
    cur = cur[p];
  }
  return cur;
}

function resolveStyleToken(styleKey, tokens) {
  const key = styleKey || "";
  const [group, name] = key.split(".");
  if (!group || !name) return {};
  const groupObj = tokens?.[group];
  return groupObj?.[name] ?? {};
}

function ClampText({ text, maxLines }) {
  if (!maxLines || maxLines <= 0) return <span>{text}</span>;
  return (
    <div
      style={{
        display: "-webkit-box",
        WebkitLineClamp: maxLines,
        WebkitBoxOrient: "vertical",
        overflow: "hidden",
      }}
    >
      {text}
    </div>
  );
}

function LayerView({ layer, ctx, themeTokens, onAction }) {
  const common = {
    position: "absolute",
    left: layer.x,
    top: layer.y,
    width: layer.w || "auto",
    height: layer.h || "auto",
    borderRadius: layer.radius ?? undefined,
  };

  const styleToken = resolveStyleToken(layer.style, themeTokens);
  const clickable = !!layer.action;

  const handleClick = () => {
    if (!layer.action || !onAction) return;
    const resolved = layer.action.bind
      ? getByPath(ctx, layer.action.bind)
      : layer.action.value;
    onAction(layer.action, resolved);
  };

  if (layer.type === "text") {
    const value = layer.bind ? getByPath(ctx, layer.bind) : layer.text;
    return (
      <div
        style={{
          ...common,
          ...styleToken,
          overflow: "hidden",
          textOverflow: "ellipsis",
          cursor: clickable ? "pointer" : "default",
        }}
        onClick={clickable ? handleClick : undefined}
      >
        <ClampText text={String(value ?? "")} maxLines={layer.maxLines || 0} />
      </div>
    );
  }

  if (layer.type === "chip") {
    const value = layer.bind ? getByPath(ctx, layer.bind) : layer.text;
    return (
      <div
        style={{
          ...common,
          ...styleToken,
          display: "inline-flex",
          alignItems: "center",
          justifyContent: "center",
          padding: "6px 10px",
          cursor: clickable ? "pointer" : "default",
        }}
        onClick={clickable ? handleClick : undefined}
      >
        {String(value ?? "")}
      </div>
    );
  }

  if (layer.type === "image") {
    const src = layer.bind ? getByPath(ctx, layer.bind) : undefined;
    return (
      <div
        style={{
          ...common,
          ...styleToken,
          backgroundImage: src ? `url(${src})` : undefined,
          backgroundSize: "cover",
          backgroundPosition: "center",
          cursor: clickable ? "pointer" : "default",
        }}
        onClick={clickable ? handleClick : undefined}
      />
    );
  }

  if (layer.type === "button") {
    const label = layer.bind ? getByPath(ctx, layer.bind) : layer.text;
    return (
      <button
        style={{
          ...common,
          ...styleToken,
          border: "none",
          cursor: "pointer",
        }}
        onClick={handleClick}
      >
        {String(label ?? "Open")}
      </button>
    );
  }

  if (layer.type === "icon") {
    const value = layer.bind ? getByPath(ctx, layer.bind) : layer.text;
    return <div style={{ ...common, ...styleToken }}>{String(value ?? "•")}</div>;
  }

  return null;
}

export default function CardRenderer({
  spec,
  data,
  themeTokens,
  onAction,
  className = "",
}) {
  const ctx = useMemo(() => ({ data }), [data]);

  const bgStyle = useMemo(() => {
    const bg = spec?.background || {};
    if (bg.type === "solid") {
      return { background: themeTokens.colors?.[bg.value] ?? bg.value };
    }
    if (bg.type === "gradient") {
      return { background: themeTokens.gradients?.[bg.value] ?? bg.value };
    }
    if (bg.type === "image") {
      const url = bg.bind ? getByPath(ctx, bg.bind) : undefined;
      return url
        ? {
            backgroundImage: `url(${url})`,
            backgroundSize: "cover",
            backgroundPosition: "center",
          }
        : { background: themeTokens.colors?.surface ?? "#111" };
    }
    return { background: themeTokens.colors?.surface ?? "#111" };
  }, [spec, themeTokens, ctx]);

  if (!spec) return null;

  return (
    <div
      className={className}
      style={{
        position: "relative",
        width: spec.size.w,
        height: spec.size.h,
        borderRadius: spec.radius ?? themeTokens.radius?.card ?? 18,
        overflow: "hidden",
        boxShadow: themeTokens.shadow?.card,
        ...bgStyle,
      }}
    >
      {spec.layers.map((layer) => (
        <LayerView
          key={layer.id}
          layer={layer}
          ctx={ctx}
          themeTokens={themeTokens}
          onAction={onAction}
        />
      ))}
    </div>
  );
}
