import React, {useRef, useEffect, useState, useCallback, useMemo} from 'react';
import {DistortionArea, Point} from '@/types';
import {ImageDistortion} from '@/components/ImageDistortion';
import {EditorCanvasStyle} from '../types';
import {DEFAULT_EDITOR_CANVAS_STYLE} from '@/editor';

interface EditorCanvasProps {
	areas: DistortionArea[];
	selectedAreaId: string | null;
	imageSrc: string;
	width: number;
	height: number;
	onUpdatePoint: (areaId: string, pointIndex: number, point: Point) => void;
	onUpdateArea: (areaId: string, updates: Partial<DistortionArea>) => void;
	draggingPointIndex: number | null;
	onStartDragging: (pointIndex: number) => void;
	onStopDragging: () => void;
	/** 에디터 캔버스 스타일 커스터마이징 */
	style?: EditorCanvasStyle;
	/** 에디터 UI 표시 여부 (기본값: true) */
	showEditor?: boolean;
}

export const EditorCanvas: React.FC<EditorCanvasProps> = ({
															  areas,
															  selectedAreaId,
															  imageSrc,
															  width,
															  height,
															  onUpdatePoint,
															  onUpdateArea,
															  draggingPointIndex,
															  onStartDragging,
															  onStopDragging,
															  style: customStyle,
															  showEditor = true,
														  }) => {
	const containerRef = useRef<HTMLDivElement>(null);
	const [canvasSize, setCanvasSize] = useState({width: 0, height: 0});
	const [isDraggingArea, setIsDraggingArea] = useState(false);
	const [dragStartPos, setDragStartPos] = useState<Point | null>(null);

	// 스타일 병합 (커스텀 스타일 우선)
	const editorStyle = useMemo(() => ({
		...DEFAULT_EDITOR_CANVAS_STYLE,
		...customStyle,
		circleLevels: customStyle?.circleLevels || DEFAULT_EDITOR_CANVAS_STYLE.circleLevels,
		centerPoint: {
			...DEFAULT_EDITOR_CANVAS_STYLE.centerPoint,
			...customStyle?.centerPoint,
		},
		pointHandle: {
			...DEFAULT_EDITOR_CANVAS_STYLE.pointHandle,
			...customStyle?.pointHandle,
		},
		areaOutline: {
			...DEFAULT_EDITOR_CANVAS_STYLE.areaOutline,
			...customStyle?.areaOutline,
		},
	}), [customStyle]);

	// 컨테이너 크기 측정
	useEffect(() => {
		if (!containerRef.current) return;
		const rect = containerRef.current.getBoundingClientRect();
		setCanvasSize({width: rect.width, height: rect.height});
	}, [width, height]);

	// 선택된 영역 찾기
	const selectedArea = areas.find((a) => a.id === selectedAreaId);

	// 점이 사각형 내부에 있는지 확인 (Point-in-Polygon test)
	const isPointInPolygon = useCallback((point: Point, polygon: Point[]): boolean => {
		let inside = false;
		for (let i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {
			const xi = polygon[i].x, yi = polygon[i].y;
			const xj = polygon[j].x, yj = polygon[j].y;

			const intersect = ((yi > point.y) !== (yj > point.y))
				&& (point.x < (xj - xi) * (point.y - yi) / (yj - yi) + xi);
			if (intersect) inside = !inside;
		}
		return inside;
	}, []);

	// 포인트 핸들 클릭/터치 핸들러
	const handlePointDown = useCallback(
		(pointIndex: number) => (e: React.MouseEvent | React.TouchEvent) => {
			e.preventDefault();
			e.stopPropagation();
			onStartDragging(pointIndex);
		},
		[onStartDragging]
	);

	// 캔버스 다운 (마우스/터치 공통)
	const handleCanvasDown = useCallback(
		(e: React.MouseEvent | React.TouchEvent) => {
			// 에디터가 숨겨진 상태면 동작하지 않음
			if (!showEditor || !selectedArea || !containerRef.current) return;

			const rect = containerRef.current.getBoundingClientRect();

			// 마우스 또는 터치 좌표 추출
			let clientX: number, clientY: number;
			if ('touches' in e) {
				if (e.touches.length === 0) return;
				clientX = e.touches[0].clientX;
				clientY = e.touches[0].clientY;
			} else {
				clientX = e.clientX;
				clientY = e.clientY;
			}

			const x = (clientX - rect.left) / rect.width;
			const y = (clientY - rect.top) / rect.height;
			const clickPoint = { x, y };

			// 사각형 내부를 클릭했는지 확인
			if (isPointInPolygon(clickPoint, selectedArea.basePoints)) {
				setIsDraggingArea(true);
				setDragStartPos(clickPoint);
				e.preventDefault();
			}
		},
		[showEditor, selectedArea, isPointInPolygon]
	);

	// 이동 (마우스/터치 공통)
	const handleMove = useCallback(
		(e: React.MouseEvent | React.TouchEvent) => {
			// 에디터가 숨겨진 상태면 동작하지 않음
			if (!showEditor || !selectedArea || !containerRef.current) return;

			// 터치 이벤트면 스크롤 방지
			if ('touches' in e && (draggingPointIndex !== null || isDraggingArea)) {
				e.preventDefault();
			}

			const rect = containerRef.current.getBoundingClientRect();

			// 마우스 또는 터치 좌표 추출
			let clientX: number, clientY: number;
			if ('touches' in e) {
				if (e.touches.length === 0) return;
				clientX = e.touches[0].clientX;
				clientY = e.touches[0].clientY;
			} else {
				clientX = e.clientX;
				clientY = e.clientY;
			}

			const x = (clientX - rect.left) / rect.width;
			const y = (clientY - rect.top) / rect.height;

			// 포인트 드래그 중
			if (draggingPointIndex !== null) {
				const clampedX = Math.max(0, Math.min(1, x));
				const clampedY = Math.max(0, Math.min(1, y));
				onUpdatePoint(selectedArea.id, draggingPointIndex, {x: clampedX, y: clampedY});
			}
			// 사각형 전체 드래그 중
			else if (isDraggingArea && dragStartPos) {
				const deltaX = x - dragStartPos.x;
				const deltaY = y - dragStartPos.y;

				// 모든 포인트를 delta만큼 이동
				const newPoints = selectedArea.basePoints.map((point) => ({
					x: Math.max(0, Math.min(1, point.x + deltaX)),
					y: Math.max(0, Math.min(1, point.y + deltaY)),
				})) as [Point, Point, Point, Point];

				onUpdateArea(selectedArea.id, { basePoints: newPoints });
				setDragStartPos({ x, y }); // 다음 프레임을 위해 시작 위치 업데이트
			}
		},
		[showEditor, draggingPointIndex, isDraggingArea, dragStartPos, selectedArea, onUpdatePoint, onUpdateArea]
	);

	// 업 (마우스/터치 공통)
	const handleUp = useCallback(() => {
		if (draggingPointIndex !== null) {
			onStopDragging();
		}
		if (isDraggingArea) {
			setIsDraggingArea(false);
			setDragStartPos(null);
		}
	}, [draggingPointIndex, isDraggingArea, onStopDragging]);

	// 전역 업 이벤트 (마우스/터치)
	useEffect(() => {
		if (draggingPointIndex !== null || isDraggingArea) {
			window.addEventListener('mouseup', handleUp);
			window.addEventListener('touchend', handleUp);
			window.addEventListener('touchcancel', handleUp);
			return () => {
				window.removeEventListener('mouseup', handleUp);
				window.removeEventListener('touchend', handleUp);
				window.removeEventListener('touchcancel', handleUp);
			};
		}
	}, [draggingPointIndex, isDraggingArea, handleUp]);

	// UV 좌표를 픽셀 좌표로 변환 (셰이더와 동일한 bilinear interpolation)
	const uvToPixel = (
		u: number,
		v: number,
		points: [Point, Point, Point, Point],
		canvasWidth: number,
		canvasHeight: number
	): { x: number; y: number } => {
		// p0=좌상, p1=우상, p2=우하, p3=좌하
		const [p0, p1, p2, p3] = points;

		// 셰이더 computeUV와 동일한 순서로 bilinear interpolation
		// left = mix(p0, p1, u)  -> 상단 가장자리
		// right = mix(p3, p2, u) -> 하단 가장자리
		// position = mix(left, right, v)
		const leftX = p0.x * (1 - u) + p1.x * u;
		const leftY = p0.y * (1 - u) + p1.y * u;

		const rightX = p3.x * (1 - u) + p2.x * u;
		const rightY = p3.y * (1 - u) + p2.y * u;

		const posX = leftX * (1 - v) + rightX * v;
		const posY = leftY * (1 - v) + rightY * v;

		return {
			x: posX * canvasWidth,
			y: posY * canvasHeight,
		};
	};

	// UV 좌표계의 원을 정확히 그리기 (찌그러진 원 형태)
	const drawDistortionCircle = useCallback((
		ctx: CanvasRenderingContext2D,
		points: [Point, Point, Point, Point],
		canvasWidth: number,
		canvasHeight: number
	) => {
		const segments = 128; // 원을 128개 세그먼트로 촘촘히 분할
		const centerU = 0.5;
		const centerV = 0.5;

		const circleLevels = editorStyle.circleLevels || [];

		// 원 레벨별로 그리기 (외부 -> 내부 순)
		circleLevels.forEach((level, index) => {
			const levelPoints: { x: number; y: number }[] = [];
			for (let i = 0; i <= segments; i++) {
				const theta = (i / segments) * 2 * Math.PI;
				const u = centerU - level.radius * Math.sin(theta);
				const v = centerV + level.radius * Math.cos(theta);
				const pixelPos = uvToPixel(u, v, points, canvasWidth, canvasHeight);
				levelPoints.push(pixelPos);
			}

			ctx.beginPath();
			ctx.moveTo(levelPoints[0].x, levelPoints[0].y);
			for (let i = 1; i < levelPoints.length; i++) {
				ctx.lineTo(levelPoints[i].x, levelPoints[i].y);
			}
			ctx.closePath();

			// 원 테두리
			const baseColor = level.color || 'rgba(255, 200, 0, 1)';
			// baseColor에서 RGB 추출하고 opacity 적용
			const colorWithOpacity = baseColor.replace(/rgba?\(([^)]+)\)/, (_, rgb) => {
				const parts = rgb.split(',').map((p: string) => p.trim());
				return `rgba(${parts[0]}, ${parts[1]}, ${parts[2]}, ${level.opacity})`;
			});
			ctx.strokeStyle = colorWithOpacity;
			ctx.lineWidth = level.lineWidth;
			if (level.dashPattern) {
				ctx.setLineDash(level.dashPattern);
			}
			ctx.stroke();
			ctx.setLineDash([]);

			// 가장 외부 원만 내부 채우기
			if (index === 0 && editorStyle.circleFillColor) {
				ctx.fillStyle = editorStyle.circleFillColor;
				ctx.fill();
			}
		});

		// 중심점 표시
		const centerPointStyle = editorStyle.centerPoint || {};
		const centerPixel = uvToPixel(centerU, centerV, points, canvasWidth, canvasHeight);
		ctx.beginPath();
		ctx.arc(centerPixel.x, centerPixel.y, centerPointStyle.radius || 5, 0, 2 * Math.PI);
		if (centerPointStyle.fillColor) {
			ctx.fillStyle = centerPointStyle.fillColor;
			ctx.fill();
		}
		if (centerPointStyle.strokeColor) {
			ctx.strokeStyle = centerPointStyle.strokeColor;
			ctx.lineWidth = centerPointStyle.strokeWidth || 2;
			ctx.stroke();
		}
	}, [editorStyle]);

	// 커서 스타일 결정
	const getCursorStyle = () => {
		if (draggingPointIndex !== null) return 'grabbing';
		if (isDraggingArea) return 'grabbing';
		return 'default';
	};

	return (
		<div
			ref={containerRef}
			className="editor-canvas"
			style={{
				width,
				height,
				position: 'relative',
				cursor: showEditor ? getCursorStyle() : 'default',
				pointerEvents: showEditor ? 'auto' : 'none',
				touchAction: 'none', // 터치 시 모든 브라우저 동작 비활성화 (스크롤, 줌 등)
			}}
			onMouseDown={showEditor ? handleCanvasDown : undefined}
			onMouseMove={showEditor ? handleMove : undefined}
			onTouchStart={showEditor ? handleCanvasDown : undefined}
			onTouchMove={showEditor ? handleMove : undefined}
		>
			{/* ImageDistortion 컴포넌트 */}
			<ImageDistortion imageSrc={imageSrc} areas={areas}/>

			{/* 오버레이 SVG - 에디터 모드일 때만 표시 */}
			{showEditor && (
				<svg
					style={{
						position: 'absolute',
						top: 0,
						left: 0,
						width: '100%',
						height: '100%',
						pointerEvents: 'none',
					}}
				>
					{/* 모든 영역의 사각형 표시 */}
					{areas.map((area) => {
					const isSelected = area.id === selectedAreaId;
					const points = area.basePoints;
					const outlineStyle = editorStyle.areaOutline || {};
					return (
						<g key={area.id}>
							{/* 사각형 배경 및 경계선 */}
							<polygon
								points={points
									.map((p) => `${p.x * canvasSize.width},${p.y * canvasSize.height}`)
									.join(' ')}
								fill={isSelected ? (outlineStyle.selectedFillColor || 'rgba(0, 170, 255, 0.08)') : (outlineStyle.unselectedFillColor || 'rgba(136, 136, 136, 0.03)')}
								stroke={isSelected ? (outlineStyle.selectedColor || '#00aaff') : (outlineStyle.unselectedColor || '#888')}
								strokeWidth={isSelected ? (outlineStyle.selectedWidth || 2) : (outlineStyle.unselectedWidth || 1)}
								strokeDasharray={isSelected ? '0' : (outlineStyle.unselectedDashPattern?.join(',') || '5,5')}
								opacity={isSelected ? 1 : 0.5}
							/>
						</g>
					);
					})}
				</svg>
			)}

			{/* 선택된 영역의 타원 가이드 (Canvas로 그리기) - 에디터 모드일 때만 표시 */}
			{showEditor && selectedArea && canvasSize.width > 0 && (
				<canvas
					style={{
						position: 'absolute',
						top: 0,
						left: 0,
						width: '100%',
						height: '100%',
						pointerEvents: 'none',
					}}
					width={canvasSize.width}
					height={canvasSize.height}
					ref={(canvas) => {
						if (canvas) {
							const ctx = canvas.getContext('2d');
							if (ctx) {
								ctx.clearRect(0, 0, canvasSize.width, canvasSize.height);
								drawDistortionCircle(ctx, selectedArea.basePoints, canvasSize.width, canvasSize.height);
							}
						}
					}}
				/>
			)}

			{/* 선택된 영역의 포인트 핸들 - 에디터 모드일 때만 표시 */}
			{showEditor && selectedArea &&
				selectedArea.basePoints.map((point, index) => {
					const handleStyle = editorStyle.pointHandle || {};
					return (
						<div
							key={index}
							className={`point-handle ${draggingPointIndex === index ? 'dragging' : ''}`}
							style={{
								position: 'absolute',
								left: `${point.x * 100}%`,
								top: `${point.y * 100}%`,
								transform: 'translate(-50%, -50%)',
								width: handleStyle.size || 16,
								height: handleStyle.size || 16,
								borderRadius: '50%',
								backgroundColor: handleStyle.fillColor || '#00aaff',
								border: `${handleStyle.strokeWidth || 2}px solid ${handleStyle.strokeColor || 'white'}`,
								cursor: 'grab',
								pointerEvents: 'auto',
								boxShadow: '0 2px 4px rgba(0,0,0,0.3)',
							}}
							onMouseDown={handlePointDown(index)}
							onTouchStart={handlePointDown(index)}
						>
							<div
								style={{
									position: 'absolute',
									top: -24,
									left: '50%',
									transform: 'translateX(-50%)',
									fontSize: handleStyle.labelFontSize || 11,
									color: handleStyle.labelColor || '#00aaff',
									fontWeight: 'bold',
									textShadow: '1px 1px 2px rgba(0,0,0,0.8)',
									whiteSpace: 'nowrap',
								}}
							>
								P{index + 1}
							</div>
						</div>
					);
				})}
		</div>
	);
};
