/**
 * CharacterSprite
 *
 * docs/character-design-guide.md 에 정의된 카와이 치비 스타일을 SVG로 구현.
 * 각 원소의 색상·Tier·파티클 유형에 따라 고유한 캐릭터를 생성합니다.
 */
import { Fragment, useMemo, type ReactElement } from 'react';
import {
  CHARACTER_VISUAL,
  DEFAULT_VISUAL,
  type EyeStyle,
  type ParticleType,
  type PatternType,
} from '../data/characterVisual';

// ─── 색상 유틸 ───────────────────────────────────────────────

function hexToRgb(hex: string): [number, number, number] {
  const h = hex.replace('#', '');
  return [
    parseInt(h.slice(0, 2), 16),
    parseInt(h.slice(2, 4), 16),
    parseInt(h.slice(4, 6), 16),
  ];
}

function rgbToHex(r: number, g: number, b: number): string {
  return (
    '#' +
    [r, g, b]
      .map((x) => Math.min(255, Math.max(0, Math.round(x))).toString(16).padStart(2, '0'))
      .join('')
  );
}

function lighten(hex: string, amt: number): string {
  const [r, g, b] = hexToRgb(hex);
  return rgbToHex(r + amt, g + amt, b + amt);
}

function darken(hex: string, amt: number): string {
  const [r, g, b] = hexToRgb(hex);
  return rgbToHex(r - amt, g - amt, b - amt);
}

// ─── 파티클 위치 ──────────────────────────────────────────────

interface ParticlePos {
  angle: number; // 도 (degree)
  r: number;     // 궤도 반지름
  dur: number;   // 애니메이션 주기 (초)
  delay: number; // 시작 딜레이 (초)
}

const PARTICLE_POSITIONS: Record<number, ParticlePos[]> = {
  1: [
    { angle: -70, r: 42, dur: 2.0, delay: 0 },
    { angle: 50,  r: 44, dur: 2.3, delay: 0.8 },
    { angle: 170, r: 41, dur: 1.9, delay: 1.5 },
  ],
  2: [
    { angle: -60, r: 43, dur: 2.0, delay: 0 },
    { angle: 0,   r: 44, dur: 2.3, delay: 0.4 },
    { angle: 60,  r: 42, dur: 2.1, delay: 0.8 },
    { angle: 130, r: 44, dur: 2.4, delay: 1.2 },
    { angle: 200, r: 41, dur: 1.9, delay: 1.6 },
    { angle: 270, r: 43, dur: 2.2, delay: 2.0 },
  ],
  3: [
    { angle: -80, r: 44, dur: 2.0, delay: 0 },
    { angle: -35, r: 46, dur: 2.3, delay: 0.3 },
    { angle: 10,  r: 44, dur: 2.1, delay: 0.6 },
    { angle: 55,  r: 46, dur: 2.4, delay: 0.9 },
    { angle: 100, r: 43, dur: 1.9, delay: 1.2 },
    { angle: 150, r: 45, dur: 2.2, delay: 1.5 },
    { angle: 200, r: 44, dur: 2.0, delay: 1.8 },
    { angle: 255, r: 46, dur: 2.3, delay: 2.1 },
  ],
  4: [
    { angle: -80, r: 45, dur: 2.0, delay: 0 },
    { angle: -35, r: 47, dur: 2.2, delay: 0.25 },
    { angle: 10,  r: 45, dur: 2.1, delay: 0.5 },
    { angle: 55,  r: 47, dur: 2.3, delay: 0.75 },
    { angle: 100, r: 44, dur: 1.9, delay: 1.0 },
    { angle: 150, r: 46, dur: 2.1, delay: 1.25 },
    { angle: 200, r: 45, dur: 2.0, delay: 1.5 },
    { angle: 255, r: 47, dur: 2.2, delay: 1.75 },
  ],
  5: [
    { angle: -80,  r: 45, dur: 1.8, delay: 0 },
    { angle: -50,  r: 47, dur: 2.0, delay: 0.2 },
    { angle: -20,  r: 45, dur: 1.9, delay: 0.4 },
    { angle: 10,   r: 47, dur: 2.1, delay: 0.6 },
    { angle: 40,   r: 45, dur: 1.8, delay: 0.8 },
    { angle: 70,   r: 47, dur: 2.0, delay: 1.0 },
    { angle: 100,  r: 44, dur: 1.9, delay: 1.2 },
    { angle: 130,  r: 47, dur: 2.1, delay: 1.4 },
    { angle: 160,  r: 45, dur: 1.8, delay: 1.6 },
    { angle: 195,  r: 47, dur: 2.0, delay: 1.8 },
    { angle: 230,  r: 45, dur: 1.9, delay: 2.0 },
    { angle: 265,  r: 47, dur: 2.1, delay: 2.2 },
  ],
};

function toRad(deg: number) {
  return (deg * Math.PI) / 180;
}

// ─── 파티클 SVG 모양 ──────────────────────────────────────────

function renderParticleShape(type: ParticleType, color: string, size = 1): ReactElement {
  const s = size;
  switch (type) {
    case 'flame':
      return (
        <polygon
          points={`0,${-6 * s} ${-4 * s},${3 * s} ${4 * s},${3 * s}`}
          fill={color}
          opacity="0.85"
        />
      );
    case 'water':
      return <ellipse rx={3 * s} ry={4 * s} fill={color} opacity="0.8" />;
    case 'wind':
      return (
        <path
          d={`M${-5 * s},0 C${-2 * s},${-3 * s} ${2 * s},${-3 * s} ${5 * s},0`}
          fill="none"
          stroke={color}
          strokeWidth={1.5 * s}
          strokeLinecap="round"
          opacity="0.8"
        />
      );
    case 'earth':
      return <circle r={3 * s} fill={color} opacity="0.75" />;
    case 'crystal':
      return (
        <polygon
          points={`0,${-5 * s} ${3.5 * s},0 0,${5 * s} ${-3.5 * s},0`}
          fill={color}
          opacity="0.8"
        />
      );
    case 'spark': {
      const p = 5 * s;
      return (
        <path
          d={`M0,${-p} L${2 * s},${-1 * s} L${1 * s},${-1 * s} L${3 * s},${p} L${-2 * s},0 L${-1 * s},0 Z`}
          fill={color}
          opacity="0.85"
        />
      );
    }
    case 'star':
      return (
        <polygon
          points={`0,${-5 * s} ${1.5 * s},${-1.8 * s} ${5 * s},${-1.6 * s} ${2.2 * s},${1.0 * s} ${3.1 * s},${4.8 * s} 0,${2.8 * s} ${-3.1 * s},${4.8 * s} ${-2.2 * s},${1.0 * s} ${-5 * s},${-1.6 * s} ${-1.5 * s},${-1.8 * s}`}
          fill={color}
          opacity="0.85"
        />
      );
    case 'smoke':
      return <circle r={4 * s} fill={color} opacity="0.4" />;
    case 'rainbow':
      return (
        <circle r={3 * s} fill={color} opacity="0.85" />
      );
    case 'leaf':
      return (
        <ellipse rx={4 * s} ry={2 * s} fill={color} opacity="0.8" transform="rotate(35)" />
      );
    default:
      return <circle r={3 * s} fill={color} opacity="0.6" />;
  }
}

function renderParticles(
  particleType: ParticleType,
  particleColors: string[],
  tier: number,
  cx: number,
  cy: number,
): ReactElement[] {
  const clampedTier = Math.min(tier, 5) as 1 | 2 | 3 | 4 | 5;
  const positions = PARTICLE_POSITIONS[clampedTier] ?? PARTICLE_POSITIONS[1];

  return positions.map((pos, i) => {
    const rad = toRad(pos.angle);
    const px = Number((cx + pos.r * Math.cos(rad)).toFixed(1));
    const py = Number((cy + pos.r * Math.sin(rad)).toFixed(1));
    const color = particleColors[i % particleColors.length];
    const floatAmt = tier >= 4 ? 5 : 4;
    const dx = Number((Math.cos(rad + Math.PI / 2) * floatAmt).toFixed(1));
    const dy = Number((-Math.abs(Math.sin(rad)) * floatAmt - 2).toFixed(1));

    // animateTransform on outer <g>, static position on inner <g>
    // outer: animates translate(0,0) → translate(dx,dy) → translate(0,0)
    // inner: static translate(px,py)
    // net particle position: (px,py) ↔ (px+dx, py+dy)
    return (
      <g key={i}>
        <animateTransform
          attributeName="transform"
          type="translate"
          values={`0,0; ${dx},${dy}; 0,0`}
          dur={`${pos.dur}s`}
          begin={`${pos.delay}s`}
          repeatCount="indefinite"
        />
        <g transform={`translate(${px},${py})`}>
          {renderParticleShape(particleType, color)}
        </g>
      </g>
    );
  });
}

// ─── 몸체 패턴 ───────────────────────────────────────────────

function renderBodyPattern(
  patternType: PatternType,
  patternColor: string,
  cx: number,
  cy: number,
): ReactElement | null {
  const opacity = 0.22;
  switch (patternType) {
    case 'swirl':
      return (
        <path
          d={`M${cx - 2},${cy - 6} C${cx - 2},${cy - 10} ${cx + 5},${cy - 10} ${cx + 6},${cy - 5} C${cx + 7},${cy} ${cx + 3},${cy + 5} ${cx - 1},${cy + 4}`}
          fill="none"
          stroke={patternColor}
          strokeWidth="1.8"
          opacity={opacity}
          strokeLinecap="round"
        />
      );
    case 'wave':
      return (
        <Fragment>
          <path
            d={`M${cx - 10},${cy + 1} C${cx - 6},${cy - 2} ${cx - 2},${cy + 4} ${cx + 2},${cy + 1} C${cx + 6},${cy - 2} ${cx + 10},${cy + 4} ${cx + 14},${cy + 1}`}
            fill="none"
            stroke={patternColor}
            strokeWidth="1.5"
            opacity={opacity}
          />
          <path
            d={`M${cx - 10},${cy + 7} C${cx - 6},${cy + 4} ${cx - 2},${cy + 10} ${cx + 2},${cy + 7} C${cx + 6},${cy + 4} ${cx + 10},${cy + 10} ${cx + 14},${cy + 7}`}
            fill="none"
            stroke={patternColor}
            strokeWidth="1.2"
            opacity={opacity * 0.85}
          />
        </Fragment>
      );
    case 'crack':
      return (
        <Fragment>
          <path
            d={`M${cx - 2},${cy - 8} L${cx},${cy - 1} L${cx - 4},${cy + 6}`}
            fill="none"
            stroke={patternColor}
            strokeWidth="1.2"
            opacity={opacity}
          />
          <path
            d={`M${cx + 4},${cy - 6} L${cx + 3},${cy + 1} L${cx + 6},${cy + 7}`}
            fill="none"
            stroke={patternColor}
            strokeWidth="1.0"
            opacity={opacity * 0.8}
          />
        </Fragment>
      );
    case 'spiral':
      return (
        <path
          d={`M${cx},${cy} C${cx},${cy - 5} ${cx + 5},${cy - 5} ${cx + 5},${cy} C${cx + 5},${cy + 5} ${cx - 5},${cy + 5} ${cx - 5},${cy} C${cx - 5},${cy - 7} ${cx + 2},${cy - 8} ${cx + 6},${cy - 4}`}
          fill="none"
          stroke={patternColor}
          strokeWidth="1.5"
          opacity={opacity}
          strokeLinecap="round"
        />
      );
    case 'crystal':
      return (
        <Fragment>
          <polygon
            points={`${cx},${cy - 7} ${cx + 6},${cy} ${cx},${cy + 7} ${cx - 6},${cy}`}
            fill="none"
            stroke={patternColor}
            strokeWidth="1.5"
            opacity={opacity}
          />
          <polygon
            points={`${cx},${cy - 7} ${cx + 6},${cy} ${cx},${cy + 7} ${cx - 6},${cy}`}
            fill={patternColor}
            opacity={opacity * 0.5}
          />
        </Fragment>
      );
    case 'none':
    default:
      return null;
  }
}

// ─── 눈 렌더링 ────────────────────────────────────────────────

function renderEyes(
  eyeStyle: EyeStyle,
  cx: number,
  cy: number,
  bodyRy: number,
  outlineColor: string,
): ReactElement {
  const eyeY = cy - bodyRy * 0.18;
  const lx = cx - 12;
  const rx = cx + 12;

  // 눈 스타일별 동공 오프셋 및 강조
  const offsets: Record<EyeStyle, { lpo: [number, number]; rpo: [number, number]; hl: [number, number] }> = {
    energetic:  { lpo: [1, -1],  rpo: [-1, -1], hl: [2, -1] },
    calm:       { lpo: [0,  1],  rpo: [0,   1], hl: [2, -1] },
    playful:    { lpo: [0, -1],  rpo: [0,   2], hl: [2, -1] },
    steady:     { lpo: [0,  0],  rpo: [0,   0], hl: [2, -2] },
    mysterious: { lpo: [-1, 0],  rpo: [1,   0], hl: [1, -2] },
    radiant:    { lpo: [0, -1],  rpo: [0,  -1], hl: [2, -2] },
  };
  const { lpo, rpo, hl } = offsets[eyeStyle] ?? offsets.steady;

  const eyeR = eyeStyle === 'radiant' ? 7.5 : 7;
  const pupilR = eyeStyle === 'radiant' ? 4.5 : 4;

  return (
    <Fragment>
      {/* 왼쪽 눈 */}
      <circle cx={lx} cy={eyeY} r={eyeR} fill="white" />
      <circle cx={lx + lpo[0]} cy={eyeY + lpo[1]} r={pupilR} fill="#1A1A1A" />
      <circle cx={lx + hl[0]} cy={eyeY + hl[1]} r={2} fill="white" />

      {/* 오른쪽 눈 */}
      <circle cx={rx} cy={eyeY} r={eyeR} fill="white" />
      <circle cx={rx + rpo[0]} cy={eyeY + rpo[1]} r={pupilR} fill="#1A1A1A" />
      <circle cx={rx + hl[0]} cy={eyeY + hl[1]} r={2} fill="white" />

      {/* radiant: 눈 주변 별 반짝임 */}
      {eyeStyle === 'radiant' && (
        <Fragment>
          <path d={`M${lx - 10},${eyeY - 10} L${lx - 8},${eyeY - 8}`} stroke={outlineColor} strokeWidth="1" opacity="0.6" />
          <path d={`M${lx - 11},${eyeY} L${lx - 9},${eyeY}`} stroke={outlineColor} strokeWidth="1" opacity="0.6" />
          <path d={`M${rx + 8},${eyeY - 10} L${rx + 10},${eyeY - 8}`} stroke={outlineColor} strokeWidth="1" opacity="0.6" />
          <path d={`M${rx + 9},${eyeY} L${rx + 11},${eyeY}`} stroke={outlineColor} strokeWidth="1" opacity="0.6" />
        </Fragment>
      )}
    </Fragment>
  );
}

// ─── Props 타입 ──────────────────────────────────────────────

export interface CharacterSpriteProps {
  elementId: string;
  elementColor: string;
  tier: number;
  /** 렌더 크기 (정사각형 px). 기본 120 */
  size?: number;
  /** obtained / locked / undiscovered */
  state?: 'obtained' | 'locked' | 'undiscovered';
}

// ─── 메인 컴포넌트 ────────────────────────────────────────────

export function CharacterSprite({
  elementId,
  elementColor,
  tier,
  size = 120,
  state = 'obtained',
}: CharacterSpriteProps) {
  const config = CHARACTER_VISUAL[elementId] ?? DEFAULT_VISUAL;
  const [bodyRx, bodyRy] = config.bodyShape ?? [33, 31];

  const colors = useMemo(() => {
    if (state === 'undiscovered') {
      return {
        body1: '#C8C8C8',
        body2: '#A0A0A0',
        body3: '#808080',
        outline: '#606060',
        pattern: '#888888',
        glow: '#AAAAAA',
      };
    }
    const isLocked = state === 'locked';
    const base = isLocked ? '#9E9E9E' : elementColor;
    return {
      body1: lighten(base, 45),
      body2: base,
      body3: darken(base, 20),
      outline: darken(base, 35),
      pattern: darken(base, 15),
      glow: isLocked ? '#CCCCCC' : config.glowColor,
    };
  }, [elementColor, state, config.glowColor]);

  // locked/undiscovered는 간소화 렌더
  const showDetails = state === 'obtained';
  const showGlow = showDetails && tier >= 3;
  const showRing = showDetails && tier >= 4;
  const showRainbow = showDetails && tier >= 5;

  const uid = `cs-${elementId}`;
  const CX = 60;
  const CY = 64;

  return (
    <svg
      viewBox="0 0 120 120"
      width={size}
      height={size}
      xmlns="http://www.w3.org/2000/svg"
      overflow="visible"
    >
      <defs>
        {/* 몸체 그라디언트 */}
        <radialGradient id={`${uid}-grad`} cx="38%" cy="32%" r="65%">
          <stop offset="0%" stopColor={colors.body1} />
          <stop offset="65%" stopColor={colors.body2} />
          <stop offset="100%" stopColor={colors.body3} />
        </radialGradient>

        {/* 글로우 필터 (T3+) */}
        {showGlow && (
          <filter id={`${uid}-glow`} x="-25%" y="-25%" width="150%" height="150%">
            <feGaussianBlur stdDeviation={tier >= 4 ? 3 : 2} result="blur" />
            <feMerge>
              <feMergeNode in="blur" />
              <feMergeNode in="SourceGraphic" />
            </feMerge>
          </filter>
        )}

        {/* 레인보우 그라디언트 (T5) */}
        {showRainbow && (
          <linearGradient
            id={`${uid}-rainbow`}
            x1="0"
            y1="0"
            x2="120"
            y2="0"
            gradientUnits="userSpaceOnUse"
          >
            <stop offset="0%" stopColor="#FF0000" />
            <stop offset="20%" stopColor="#FF9900" />
            <stop offset="40%" stopColor="#FFFF00" />
            <stop offset="60%" stopColor="#00FF00" />
            <stop offset="80%" stopColor="#0066FF" />
            <stop offset="100%" stopColor="#CC00FF" />
          </linearGradient>
        )}
      </defs>

      {/* ① 배경 글로우 헤일로 (T3+) */}
      {showGlow && (
        <ellipse
          cx={CX}
          cy={CY}
          rx={bodyRx + 12}
          ry={bodyRy + 12}
          fill={colors.glow}
          opacity={tier >= 5 ? 0.2 : tier >= 4 ? 0.15 : 0.1}
        />
      )}

      {/* ② 에너지 링 (T4) */}
      {showRing && !showRainbow && (
        <ellipse
          cx={CX}
          cy={CY}
          rx={bodyRx + 14}
          ry={bodyRy + 14}
          fill="none"
          stroke={elementColor}
          strokeWidth="1.5"
          opacity="0.4"
        >
          <animate
            attributeName="rx"
            values={`${bodyRx + 12};${bodyRx + 16};${bodyRx + 12}`}
            dur="2.4s"
            repeatCount="indefinite"
          />
          <animate
            attributeName="ry"
            values={`${bodyRy + 12};${bodyRy + 16};${bodyRy + 12}`}
            dur="2.4s"
            repeatCount="indefinite"
          />
          <animate attributeName="opacity" values="0.3;0.55;0.3" dur="2.4s" repeatCount="indefinite" />
        </ellipse>
      )}

      {/* ③ 레인보우 링 (T5) */}
      {showRainbow && (
        <ellipse
          cx={CX}
          cy={CY}
          rx={bodyRx + 14}
          ry={bodyRy + 14}
          fill="none"
          stroke={`url(#${uid}-rainbow)`}
          strokeWidth="2.5"
          opacity="0.75"
        >
          <animateTransform
            attributeName="transform"
            type="rotate"
            values={`0 ${CX} ${CY}; 360 ${CX} ${CY}`}
            dur="4s"
            repeatCount="indefinite"
          />
        </ellipse>
      )}

      {/* ④ 파티클 (뒤편) */}
      {showDetails &&
        renderParticles(config.particleType, config.particleColors, tier, CX, CY)}

      {/* ⑤ 몸체 */}
      <ellipse
        cx={CX}
        cy={CY}
        rx={bodyRx}
        ry={bodyRy}
        fill={`url(#${uid}-grad)`}
        stroke={colors.outline}
        strokeWidth={showGlow ? 2.5 : 2}
        filter={showGlow ? `url(#${uid}-glow)` : undefined}
      >
        {/* idle 호버링 애니메이션 */}
        {state === 'obtained' && (
          <animateTransform
            attributeName="transform"
            type="translate"
            values={`0,0; 0,-3; 0,0`}
            dur="2.2s"
            repeatCount="indefinite"
          />
        )}
      </ellipse>

      {/* ⑥ 몸체 패턴 */}
      {showDetails &&
        renderBodyPattern(config.patternType, colors.pattern, CX, CY)}

      {/* ⑦ 눈 */}
      {state !== 'undiscovered' &&
        renderEyes(
          showDetails ? config.eyeStyle : 'steady',
          CX,
          CY,
          bodyRy,
          colors.outline,
        )}

      {/* ⑧ 잠금 눈 가리개 */}
      {state === 'locked' && (
        <path
          d={`M${CX - 14},${CY - bodyRy * 0.18 - 2} Q${CX},${CY - bodyRy * 0.18 + 6} ${CX + 14},${CY - bodyRy * 0.18 - 2}`}
          fill={darken(colors.body2, 25)}
          opacity="0.5"
        />
      )}

      {/* ⑨ 미소 */}
      {state !== 'undiscovered' && (
        <path
          d={`M${CX - 8},${CY + bodyRy * 0.22} Q${CX},${CY + bodyRy * 0.22 + 6} ${CX + 8},${CY + bodyRy * 0.22}`}
          fill="none"
          stroke={colors.outline}
          strokeWidth="1.5"
          strokeLinecap="round"
        />
      )}

      {/* ⑩ 미발견 ? */}
      {state === 'undiscovered' && (
        <text
          x={CX}
          y={CY + 6}
          textAnchor="middle"
          fontSize="22"
          fill="#888888"
          fontWeight="bold"
          fontFamily="sans-serif"
        >
          ?
        </text>
      )}
    </svg>
  );
}
