import { useId } from 'react';
import { getMotionSpeedCssVars, MOTION_SPEED_BASELINE, MOTION_SPEED_IDS } from '../motion-speed.js';
import { TOKEN_GRADIENTS } from '../token-gradients.js';

/** 与 IconLoading.tokens.js / theme.css --gradient-ai-fill-3 对齐 */
export const ICON_LOADING_DEFAULT_FILL_TOKEN = '--gradient-ai-fill-3';

/**
 * IconLoading — B 端渐变环图形 loading
 *
 * 独立渐变环 SVG + 旋转动效，适用于空白页、按钮旁、区块居中等图形 wait 态。
 * 填充色支持 AI 渐变色 token（`--gradient-ai-fill-*`）与实色 token（`--color-*`）。
 *
 * **何时用**：空白页 / 区域居中 / 按钮 loading 旁图形 / 表格内等待等独立图形 loading。
 * **不用**：内容骨架占位 → Skeleton；文案级 loading → TextShimmer；所有渐变环 loading（含行内 pending）→ IconLoading。
 *
 * @prop {'sm'|'md'|'lg'} [size='md'] — sm 16px / md 20px / lg 24px
 * @prop {string} [className=''] — 附加类名
 * @prop {typeof MOTION_SPEED_IDS[number]} [speed=MOTION_SPEED_BASELINE] — 循环速率档位（见 TOKEN_MOTION_SPEED）
 * @prop {string} [fillToken=--gradient-ai-fill-3] — 环填充色 token（渐变或实色）
 * @prop {string} [ariaLabel='加载中'] — 无障碍朗读文案
 */

const RING_SIZE_PX = { sm: 16, md: 20, lg: 24 };

const RING_PATH =
  'M12 2.75C17.1086 2.75 21.25 6.89137 21.25 12C21.25 17.1086 17.1086 21.25 12 21.25C6.89137 21.25 2.75 17.1086 2.75 12C2.75 6.89137 6.89137 2.75 12 2.75Z';

function gradientVarToKey(token) {
  return String(token || '').replace(/^--gradient-/, '');
}

function parseLinearGradientStops(css) {
  if (!css || !css.includes('linear-gradient')) return null;
  const stops = [];
  const re = /(rgba?\([^)]+\)|#[0-9a-fA-F]{3,8})\s*(\d+(?:\.\d+)?%?)?/g;
  let match = re.exec(css);
  while (match) {
    stops.push({
      stopColor: match[1],
      offset: match[2] || (stops.length === 0 ? '0%' : '100%'),
    });
    match = re.exec(css);
  }
  return stops.length > 0 ? stops : null;
}

function resolveRingGradientStops(fillToken) {
  if (!fillToken?.startsWith('--gradient-')) return null;
  const key = gradientVarToKey(fillToken);
  const css = TOKEN_GRADIENTS[key]?.css;
  return parseLinearGradientStops(css);
}

const CSS_COLOR_PATTERN = /^(#|rgb|hsl|color\()/i;

function extractVarToken(value) {
  if (typeof value !== 'string') return null;
  const match = value.match(/var\((--[^)]+)\)/);
  return match ? match[1] : null;
}

function isRawCssColor(value) {
  return typeof value === 'string' && CSS_COLOR_PATTERN.test(value.trim());
}

function normalizeFillSpec(value) {
  if (!value) {
    return { kind: 'gradient-token', token: ICON_LOADING_DEFAULT_FILL_TOKEN };
  }
  if (value.startsWith('--color-')) {
    return { kind: 'solid', stroke: `var(${value})` };
  }
  if (isRawCssColor(value)) {
    return { kind: 'solid', stroke: value.trim() };
  }
  if (value.startsWith('--gradient-')) {
    return { kind: 'gradient-token', token: value };
  }
  return { kind: 'gradient-token', token: ICON_LOADING_DEFAULT_FILL_TOKEN };
}

function extractFillSpecFromStyle(style) {
  if (!style || typeof style !== 'object') return null;

  for (const key of ['backgroundImage', 'backgroundColor']) {
    const raw = style[key];
    if (typeof raw !== 'string' || !raw || raw === 'none') continue;

    const varToken = extractVarToken(raw);
    if (varToken) return normalizeFillSpec(varToken);

    if (raw.includes('linear-gradient')) {
      const stops = parseLinearGradientStops(raw);
      if (stops?.length) return { kind: 'inline-gradient', stops };
      continue;
    }

    if (isRawCssColor(raw)) {
      return { kind: 'solid', stroke: raw.trim() };
    }
  }

  return null;
}

function resolveFillSpec(fillTokenProp, style) {
  if (fillTokenProp) return normalizeFillSpec(fillTokenProp);
  const fromStyle = extractFillSpecFromStyle(style);
  if (fromStyle) return fromStyle;
  return normalizeFillSpec(ICON_LOADING_DEFAULT_FILL_TOKEN);
}

export function extractFillTokenFromStyle(style) {
  const spec = extractFillSpecFromStyle(style);
  if (!spec) return null;
  if (spec.kind === 'gradient-token') return spec.token;
  if (spec.kind === 'solid' && spec.stroke?.startsWith('var(')) {
    return extractVarToken(spec.stroke);
  }
  return null;
}

function IconLoadingRing({ size = 'md', fillSpec }) {
  const uid = useId().replace(/:/g, '');
  const px = RING_SIZE_PX[size] ?? RING_SIZE_PX.md;
  const gradientId = `${uid}-ring-fill`;
  const resolvedFill = fillSpec || normalizeFillSpec(ICON_LOADING_DEFAULT_FILL_TOKEN);
  const gradientStops = resolvedFill.kind === 'inline-gradient'
    ? resolvedFill.stops
    : resolvedFill.kind === 'gradient-token'
      ? resolveRingGradientStops(resolvedFill.token)
      : null;
  const accentStroke = resolvedFill.kind === 'solid'
    ? resolvedFill.stroke
    : gradientStops
      ? `url(#${gradientId})`
      : `var(${resolvedFill.token || ICON_LOADING_DEFAULT_FILL_TOKEN})`;

  return (
    <svg
      xmlns="http://www.w3.org/2000/svg"
      width={px}
      height={px}
      viewBox="0 0 24 24"
      fill="none"
      className="tfds-icon tfds-icon-spin shrink-0 overflow-visible"
      aria-hidden="true"
     data-tfds-component="IconLoadingRing">
      {gradientStops ? (
        <defs>
          <linearGradient
            id={gradientId}
            x1="5.5"
            y1="17.5"
            x2="18.5"
            y2="6.5"
            gradientUnits="userSpaceOnUse"
          >
            {gradientStops.map((stop, index) => (
              <stop key={index} offset={stop.offset} stopColor={stop.stopColor} />
            ))}
          </linearGradient>
        </defs>
      ) : null}
      <path
        d={RING_PATH}
        stroke="var(--color-border-default)"
        strokeWidth="3"
        strokeOpacity="0.7"
        strokeLinecap="round"
        strokeLinejoin="round"
      />
      <path
        d={RING_PATH}
        stroke={accentStroke}
        strokeWidth="3"
        strokeOpacity="1"
        strokeDasharray="43 15"
        strokeDashoffset="3"
        strokeLinecap="round"
        strokeLinejoin="round"
      />
    </svg>
  );
}

export default function IconLoading({
  size = 'md',
  speed = MOTION_SPEED_BASELINE,
  className = '',
  fillToken: fillTokenProp,
  ariaLabel = '加载中',
  style,
  ...rest
}) {
  const speedStyle = getMotionSpeedCssVars(speed);
  const fillSpec = resolveFillSpec(fillTokenProp, style);
  const { backgroundImage, WebkitBackgroundClip, backgroundClip, backgroundColor, color, ...restStyle } = style || {};
  const mergedStyle = restStyle ? { ...speedStyle, ...restStyle } : speedStyle;

  return (
    <span
      data-tfds-component="IconLoading"
      role="status"
      aria-label={ariaLabel}
      style={mergedStyle}
      className={['tfds-loader tfds-loader--ring inline-flex shrink-0', className].filter(Boolean).join(' ')}
      {...rest}
    >
      <IconLoadingRing size={size} fillSpec={fillSpec} />
    </span>
  );
}
