import { useEffect, useState, type CSSProperties } from 'react';
import { DAMAGE_NUMBER_DURATION_MS, DAMAGE_NUMBER_RISE_PX } from '../shared/constants';
import type { FloatingDamageData } from '../game/types';

interface FloatingDamageProps {
  damages: FloatingDamageData[];
}

interface DamageNumberProps {
  data: FloatingDamageData;
  onExpire: (id: number) => void;
}

function DamageNumber({ data, onExpire }: DamageNumberProps) {
  const [progress, setProgress] = useState(0);

  useEffect(() => {
    let rafId: number;
    const start = data.createdAt;

    const animate = () => {
      const elapsed = performance.now() - start;
      const p = Math.min(1, elapsed / DAMAGE_NUMBER_DURATION_MS);
      setProgress(p);

      if (p < 1) {
        rafId = requestAnimationFrame(animate);
      } else {
        onExpire(data.id);
      }
    };

    rafId = requestAnimationFrame(animate);
    return () => cancelAnimationFrame(rafId);
  }, [data.createdAt, data.id, onExpire]);

  const offsetY = -progress * DAMAGE_NUMBER_RISE_PX;
  const opacity = 1 - progress * progress; // ease-out fade
  const scale = data.isCrit && data.kind === 'damage' ? 1.4 - progress * 0.4 : 1;
  const isOutcomeText = data.kind === 'blocked' || data.kind === 'evaded';
  const color = data.kind === 'regen'
    ? '#44dd66'
    : isOutcomeText
      ? (data.target === 'hero' ? '#44dd66' : '#ff5566')
      : (data.isCrit ? '#ffdd44' : '#ffffff');
  const fontSize = isOutcomeText ? 16 : (data.isCrit ? 24 : 18);

  const style: CSSProperties = {
    position: 'absolute',
    left: data.x,
    top: data.y + offsetY,
    transform: `translate(-50%, -50%) scale(${scale})`,
    opacity,
    color,
    fontSize,
    fontWeight: 900,
    textShadow: '0 2px 4px rgba(0,0,0,0.9), 0 0 8px rgba(0,0,0,0.5)',
    pointerEvents: 'none',
    willChange: 'transform, opacity',
  };

  return (
    <div style={style}>
      {data.kind === 'damage' && (
        <>
          {data.isCrit && 'CRIT '}
          {Math.round(data.value)}
        </>
      )}
      {data.kind === 'regen' && `+${Math.round(data.value)}`}
      {data.kind === 'blocked' && 'BLOCKED'}
      {data.kind === 'evaded' && 'EVADED'}
    </div>
  );
}

/**
 * Floating damage numbers overlay.
 * Renders above the game canvas in screen space.
 */
export function FloatingDamage({ damages }: FloatingDamageProps) {
  const [activeDamages, setActiveDamages] = useState<FloatingDamageData[]>([]);

  // Sync incoming damages
  useEffect(() => {
    setActiveDamages((prev) => {
      const existingIds = new Set(prev.map((d) => d.id));
      const newDamages = damages.filter((d) => !existingIds.has(d.id));
      return [...prev, ...newDamages];
    });
  }, [damages]);

  const handleExpire = (id: number) => {
    setActiveDamages((prev) => prev.filter((d) => d.id !== id));
  };

  return (
    <div style={{
      position: 'absolute',
      top: 0,
      left: 0,
      width: '100%',
      height: '100%',
      pointerEvents: 'none',
      overflow: 'hidden',
    }}>
      {activeDamages.map((d) => (
        <DamageNumber key={d.id} data={d} onExpire={handleExpire} />
      ))}
    </div>
  );
}
