import React, { useEffect, useRef, useState, useCallback } from 'react';
import * as THREE from 'three';
import {type DistortionArea, SpriteEffectArea} from '@/types';
import { ThreeScene } from '@/engine/ThreeScene';
import { ShaderManager } from '@/engine/ShaderManager';
import { AnimationLoop } from '@/engine/AnimationLoop';
import { SpriteEffectManager } from '@/engine/SpriteEffectManager';
import { useAnimationFrame } from '@/hooks/useAnimationFrame';
import { useMouseInteraction } from '@/hooks/useMouseInteraction';
import { SHADER_CONFIG } from '@/utils/constants';
import { MouseInteractionConfig } from '@/types/interaction';

/**
 * ImageDistortion 컴포넌트 Props
 */
export interface ImageDistortionProps {
  /** 이미지 소스 URL */
  imageSrc: string;
  /** 왜곡 영역 배열 */
  areas: DistortionArea[];
  /** 버텍스 셰이더 경로 (선택사항) */
  vertexShaderPath?: string;
  /** 프래그먼트 셰이더 경로 (선택사항) */
  fragmentShaderPath?: string;
  /** 컨테이너 스타일 */
  style?: React.CSSProperties;
  /** 컨테이너 클래스명 */
  className?: string;
  /** 마우스 인터랙션 설정 */
  mouseInteraction?: MouseInteractionConfig;
  /** 독립 스프라이트 이펙트 영역 (왜곡 영역과 분리) */
  spriteEffectAreas?: SpriteEffectArea[];
}

/**
 * GPU 가속 이미지 왜곡 컴포넌트
 * Three.js와 GLSL 셰이더를 사용하여 실시간 이미지 왜곡 효과를 제공합니다.
 */
export const ImageDistortion: React.FC<ImageDistortionProps> = ({
  imageSrc,
  areas,
  vertexShaderPath,
  fragmentShaderPath,
  style,
  className,
  mouseInteraction,
  spriteEffectAreas = [],
}) => {
  const containerRef = useRef<HTMLDivElement>(null);
  const sceneRef = useRef<ThreeScene | null>(null);
  const shaderManagerRef = useRef<ShaderManager>(new ShaderManager());
  const textureRef = useRef<THREE.Texture | null>(null);
  const spriteManagerRef = useRef<SpriteEffectManager | null>(null);
  const currentAreasRef = useRef<DistortionArea[]>(areas);

  const [isReady, setIsReady] = useState(false);
  const [imageLoaded, setImageLoaded] = useState(false);
  const [currentAreas, setCurrentAreas] = useState<DistortionArea[]>(areas);

  // 마우스 인터랙션 훅
  const mouseInteractionHook = useMouseInteraction(
    containerRef,
    mouseInteraction || {
      enabled: false,
      physics: {
        stiffness: 100,
        damping: 10,
        mass: 1,
        influenceRadius: 0.2,
        maxStrength: 1.0,
      },
    }
  );

  // 영역 변경 시 상태 업데이트
  useEffect(() => {
    setCurrentAreas(areas);
  }, [areas]);

  // currentAreasRef 동기화
  useEffect(() => {
    currentAreasRef.current = currentAreas;
  }, [currentAreas]);

  // 스프라이트 이펙트 매니저 초기화
  useEffect(() => {
    if (!sceneRef.current || !isReady) return;
    const manager = new SpriteEffectManager();
    manager.attachToScene(sceneRef.current.getScene());
    spriteManagerRef.current = manager;
    return () => {
      manager.dispose();
      spriteManagerRef.current = null;
    };
  }, [isReady]);

  // 이펙트 영역 변경 또는 매니저 준비 시 스프라이트 이펙트 동기화
  useEffect(() => {
    spriteManagerRef.current?.syncEffects(spriteEffectAreas);
  }, [spriteEffectAreas, isReady]);

  // 마우스 인터랙션 설정 변경 시 업데이트
  useEffect(() => {
    if (mouseInteraction) {
      mouseInteractionHook.updateConfig(mouseInteraction);
    }
  }, [mouseInteraction, mouseInteractionHook]);

  // Three.js 씬 초기화
  useEffect(() => {
    console.log('[ImageDistortion] useEffect 실행, containerRef.current:', containerRef.current);

    if (!containerRef.current) {
      console.warn('[ImageDistortion] containerRef.current가 null입니다. 컴포넌트가 제대로 마운트되지 않았습니다.');
      return;
    }

    console.log('[ImageDistortion] v1.5.1 초기화 시작');
    const scene = new ThreeScene(containerRef.current);
    sceneRef.current = scene;

    // 셰이더 로드
    const vertPath = vertexShaderPath || '/shaders/distortion.vert.glsl';
    const fragPath = fragmentShaderPath || '/shaders/distortion.frag.glsl';

    console.log('[ImageDistortion] 셰이더 로드 시도:', { vertPath, fragPath });

    shaderManagerRef.current
      .loadShaders(vertPath, fragPath)
      .then(({ vertex, fragment }) => {
        console.log('[ImageDistortion] 셰이더 로드 성공');
        scene.setShaderMaterial(vertex, fragment);
        setIsReady(true);
      })
      .catch((error) => {
        console.error('[ImageDistortion] 셰이더 로드 실패:', error);
      });

    return () => {
      scene.dispose();
      if (textureRef.current) {
        textureRef.current.dispose();
      }
    };
  }, [vertexShaderPath, fragmentShaderPath]);

  // 이미지 텍스처 로드
  useEffect(() => {
    if (!imageSrc || !isReady) {
      console.log('[ImageDistortion] 이미지 로드 스킵:', { imageSrc, isReady });
      return;
    }

    console.log('[ImageDistortion] 이미지 로드 시작:', imageSrc);
    setImageLoaded(false);

    const loader = new THREE.TextureLoader();
    loader.load(
      imageSrc,
      (texture) => {
        console.log('[ImageDistortion] 이미지 로드 성공!', {
          width: texture.image.width,
          height: texture.image.height
        });
        textureRef.current = texture;
        setImageLoaded(true);
        if (sceneRef.current) {
          sceneRef.current.updateUniforms({
            u_texture: { value: texture },
          });
          sceneRef.current.render();
          console.log('[ImageDistortion] 텍스처 업데이트 및 렌더링 완료');
        }
      },
      (progress) => {
        console.log('[ImageDistortion] 이미지 로딩 중...',
          Math.round((progress.loaded / progress.total) * 100) + '%'
        );
      },
      (error) => {
        console.error('[ImageDistortion] 이미지 로드 실패:', error);
        setImageLoaded(false);
      }
    );

    return () => {
      if (textureRef.current) {
        textureRef.current.dispose();
        textureRef.current = null;
      }
    };
  }, [imageSrc, isReady]);

  // 셰이더 유니폼 업데이트
  useEffect(() => {
    if (!sceneRef.current || !isReady) return;

    // 현재 해상도 가져오기
    const resolution = sceneRef.current.getResolution();

    // 포인트 배열 생성
    // UI는 좌상단 (0,0), WebGL은 좌하단 (0,0)이므로 y 좌표를 반전
    const points = new Float32Array(SHADER_CONFIG.MAX_POINTS * 2);
    currentAreas.forEach((area, areaIndex) => {
      area.basePoints.forEach((point, pointIndex) => {
        const index = (areaIndex * 4 + pointIndex) * 2;
        points[index] = point.x;
        points[index + 1] = 1.0 - point.y; // y 좌표 반전
      });
    });

    // 드래그 벡터 배열 생성
    // dragVector도 y 좌표계를 맞춰야 하므로 y를 반전
    const dragVectors = new Float32Array(SHADER_CONFIG.MAX_DRAG_VECTORS * 2);
    currentAreas.forEach((area, index) => {
      const baseIndex = index * 2;
      dragVectors[baseIndex] = area.dragVector.x;
      dragVectors[baseIndex + 1] = -area.dragVector.y; // y 방향 반전
    });

    // 강도 배열 생성
    const strengths = new Float32Array(SHADER_CONFIG.MAX_STRENGTHS);
    currentAreas.forEach((area, index) => {
      strengths[index] = area.distortionStrength;
    });

    // 렌즈 효과 배열 생성
    const lensEffects = new Float32Array(SHADER_CONFIG.MAX_LENS_EFFECTS);
    currentAreas.forEach((area, index) => {
      lensEffects[index] = area.lensEffect?.strength ?? 0;
    });

    sceneRef.current.updateUniforms({
      u_numAreas: { value: currentAreas.length },
      u_points: { value: points },
      u_dragVectors: { value: dragVectors },
      u_distortionStrengths: { value: strengths },
      u_lensEffects: { value: lensEffects },
    });

    sceneRef.current.render();
  }, [currentAreas, isReady]);

  // 애니메이션 루프
  const animationCallback = useCallback((deltaTime: number) => {
    if (!isReady) return;

    setCurrentAreas((prevAreas) => {
      // 현재 인터랙션 중인 영역 인덱스 가져오기
      const interactingIndices = mouseInteractionHook.getInteractingAreaIndices?.() || new Set<number>();

      // 1. 자동 애니메이션 업데이트
      let updatedAreas = AnimationLoop.updateProgress(prevAreas, deltaTime);
      updatedAreas = AnimationLoop.updateAreaDragVectors(updatedAreas);

      // 인터랙션 중인 영역만 dragVector를 0으로 설정
      if (interactingIndices.size > 0) {
        updatedAreas = updatedAreas.map((area, index) => {
          if (interactingIndices.has(index)) {
            return {
              ...area,
              dragVector: { x: 0, y: 0 }
            };
          }
          return area;
        });
      }

      // 2. 마우스 인터랙션 적용 (기존 dragVector에 스프링 변위 추가)
      if (mouseInteraction?.enabled) {
        updatedAreas = mouseInteractionHook.updateInteraction(updatedAreas, deltaTime);
      }

      return updatedAreas;
    });

    // 스프라이트 이펙트 업데이트 (왜곡 영역과 독립적)
    if (spriteManagerRef.current) {
      const mouseState = mouseInteractionHook.getMouseState();
      const resolution = sceneRef.current?.getResolution() ?? { x: 1, y: 1 };
      spriteManagerRef.current.update(
        spriteEffectAreas,
        deltaTime,
        {
          position: mouseState.position ?? null,
          isDragging: mouseState.isDragging,
        },
        resolution,
      );

      // 스프라이트 메쉬 변경 후 렌더링 필요
      sceneRef.current?.render();
    }
  }, [isReady, mouseInteraction, mouseInteractionHook, spriteEffectAreas]);

  // 애니메이션 루프 실행
  useAnimationFrame(animationCallback, true);

  return (
    <div
      ref={containerRef}
      style={{
        width: '100%',
        height: '100%',
        position: 'relative',
        ...style,
      }}
      className={className}
    >
      {!imageLoaded && (
        <div
          style={{
            position: 'absolute',
            top: '50%',
            left: '50%',
            transform: 'translate(-50%, -50%)',
            background: 'rgba(0, 0, 0, 0.7)',
            color: 'white',
            padding: '20px',
            borderRadius: '8px',
            zIndex: 999,
          }}
        >
          이미지 로딩 중...
        </div>
      )}
    </div>
  );
};