import React, { useRef, useState, useEffect, useCallback, useMemo, memo } from 'react';
import { Stage, Layer, Rect, Line, Text, Group, Path, Circle } from 'react-konva';
import type Konva from 'konva';
import { useCanvasStore, createCodeElement, createTextElement, createArrowElement } from '../store/canvasStore';
import CodeBlock from './elements/CodeBlock';
import TextBlock from './elements/TextBlock';
import Arrow from './elements/Arrow';
import { SOCIAL_ICON_PATHS, SOCIAL_PLATFORMS_CONFIG } from './elements/SocialIcons';
import type { CodeElement, TextElement, ArrowElement } from '../types';

interface CanvasProps {
  stageRef: React.RefObject<Konva.Stage | null>;
}

const Canvas: React.FC<CanvasProps> = ({ stageRef }) => {
  const containerRef = useRef<HTMLDivElement>(null);
  const [dimensions, setDimensions] = useState({ width: window.innerWidth, height: window.innerHeight - 120 });
  const [panOffset, setPanOffset] = useState({ x: 0, y: 0 });
  const { 
    snap, 
    zoom, 
    showGrid, 
    tool, 
    selectedElementId,
    selectElement, 
    addElement,
    updateElement,
    setZoom,
  } = useCanvasStore();

  const { width, height } = snap.meta;
  const { background } = snap;
  const [brandingAvatar, setBrandingAvatar] = useState<HTMLImageElement | null>(null);

  // Handle resize
  useEffect(() => {
    const updateDimensions = () => {
      if (containerRef.current) {
        setDimensions({
          width: containerRef.current.offsetWidth,
          height: containerRef.current.offsetHeight,
        });
      }
    };
    
    updateDimensions();
    window.addEventListener('resize', updateDimensions);
    return () => window.removeEventListener('resize', updateDimensions);
  }, []);

  useEffect(() => {
    const url = background.branding?.avatarUrl || '';
    if (!url) {
      setBrandingAvatar(null);
      return;
    }

    const img = new Image();
    img.crossOrigin = 'anonymous';
    img.onload = () => setBrandingAvatar(img);
    img.onerror = () => setBrandingAvatar(null);
    img.src = url;

    return () => {
      img.onload = null;
      img.onerror = null;
    };
  }, [background.branding?.avatarUrl]);

  // Calculate stage position to center the canvas
  const getStagePosition = useCallback(() => {
    const scaledWidth = width * zoom;
    const scaledHeight = height * zoom;
    return {
      x: Math.max(20, (dimensions.width - scaledWidth) / 2) + panOffset.x,
      y: Math.max(20, (dimensions.height - scaledHeight) / 2) + panOffset.y,
    };
  }, [width, height, zoom, dimensions, panOffset]);

  // Reset pan offset when zoom changes significantly or canvas is re-centered
  const resetPan = useCallback(() => {
    setPanOffset({ x: 0, y: 0 });
  }, []);

  const handleStageClick = (e: Konva.KonvaEventObject<MouseEvent>) => {
    const clickedOnEmpty = e.target === e.target.getStage() || e.target.name() === 'background';
    
    if (clickedOnEmpty) {
      const stage = e.target.getStage();
      if (!stage) return;
      
      const pos = stage.getPointerPosition();
      if (!pos) return;
      
      // Convert screen position to canvas position
      const stagePos = getStagePosition();
      const canvasX = (pos.x - stagePos.x) / zoom;
      const canvasY = (pos.y - stagePos.y) / zoom;
      
      if (tool === 'code') {
        addElement(createCodeElement(canvasX - 300, canvasY - 150));
      } else if (tool === 'text') {
        addElement(createTextElement(canvasX, canvasY));
      } else if (tool === 'arrow') {
        addElement(createArrowElement(canvasX, canvasY));
      } else {
        selectElement(null);
      }
    }
  };

  // Background gradient
  const renderBackground = () => {
    if (background.type === 'gradient') {
      return (
        <Rect
          name="background"
          x={0}
          y={0}
          width={width}
          height={height}
          fillLinearGradientStartPoint={{ x: 0, y: 0 }}
          fillLinearGradientEndPoint={{ 
            x: width * Math.cos((background.gradient.angle * Math.PI) / 180),
            y: height * Math.sin((background.gradient.angle * Math.PI) / 180)
          }}
          fillLinearGradientColorStops={[0, background.gradient.from, 1, background.gradient.to]}
        />
      );
    }
    return (
      <Rect
        name="background"
        x={0}
        y={0}
        width={width}
        height={height}
        fill={background.solid.color}
      />
    );
  };

  // Grid overlay - memoized for performance
  const gridLines = useMemo(() => {
    if (!showGrid) return null;
    const gridSize = 50;
    const lines = [];
    
    // Vertical lines
    for (let i = 0; i <= width; i += gridSize) {
      lines.push(
        <Line
          key={`v-${i}`}
          points={[i, 0, i, height]}
          stroke="rgba(255,255,255,0.1)"
          strokeWidth={1}
        />
      );
    }
    
    // Horizontal lines
    for (let i = 0; i <= height; i += gridSize) {
      lines.push(
        <Line
          key={`h-${i}`}
          points={[0, i, width, i]}
          stroke="rgba(255,255,255,0.1)"
          strokeWidth={1}
        />
      );
    }
    
    return <>{lines}</>;
  }, [showGrid, width, height]);

  // Brand strip - memoized
  const brandStripElement = useMemo(() => {
    const brandStrip = background.brandStrip;
    if (!brandStrip?.enabled) return null;

    const stripHeight = brandStrip.height || 60;
    const stripY = brandStrip.position === 'top' ? 0 : height - stripHeight;

    return (
      <>
        <Rect
          x={0}
          y={stripY}
          width={width}
          height={stripHeight}
          fill={brandStrip.color || '#000000'}
        />
        {brandStrip.text && (
          <Text
            x={0}
            y={stripY}
            width={width}
            height={stripHeight}
            text={brandStrip.text}
            fontSize={brandStrip.fontSize || 16}
            fontFamily={brandStrip.fontFamily || 'Inter'}
            fill={brandStrip.textColor || '#ffffff'}
            align="center"
            verticalAlign="middle"
          />
        )}
      </>
    );
  }, [background.brandStrip, width, height]);

  // Branding watermark - memoized
  const brandingElement = useMemo(() => {
    const branding = background.branding;
    if (!branding?.enabled) return null;

    const padding = branding.padding || 24;
    const fontSize = branding.fontSize || 14;
    const lineHeight = fontSize * 1.5;
    const iconSize = branding.socialIconSize || 20;
    const socialLayout = branding.socialLayout || 'horizontal';
    const iconGap = 16;
    const iconTextGap = 6; // Gap between icon and its text
    const avatarSize = branding.avatarSize || 56;
    const avatarGap = 14;
    const hasAvatar = Boolean(branding.showAvatar && branding.avatarUrl && brandingAvatar);

    // Build branding text lines
    const lines: string[] = [];
    if (branding.showName && branding.name) {
      lines.push(branding.name);
    }
    if (branding.showWebsite && branding.website) {
      lines.push(branding.website);
    }

    // Get active social platforms with their values
    const activeSocialPlatforms = branding.showSocial && branding.social
      ? SOCIAL_PLATFORMS_CONFIG.filter(p => branding.social[p.key as keyof typeof branding.social])
          .map(p => ({
            ...p,
            value: branding.social[p.key as keyof typeof branding.social] || ''
          }))
      : [];

    const hasTextContent = lines.length > 0;
    const hasSocialIcons = activeSocialPlatforms.length > 0;

    if (!hasTextContent && !hasSocialIcons && !hasAvatar) return null;

    const textHeight = lines.length * lineHeight;

    // Calculate social section dimensions (icon + text for each platform)
    const socialItemHeight = Math.max(iconSize, fontSize);
    const socialHeight = socialLayout === 'vertical'
      ? activeSocialPlatforms.length * socialItemHeight + (activeSocialPlatforms.length - 1) * (iconGap - 4)
      : socialItemHeight;

    // Calculate total content height
    const contentHeight = (hasTextContent || hasSocialIcons)
      ? textHeight + (hasTextContent && hasSocialIcons ? 16 : 0) + (hasSocialIcons ? socialHeight : 0)
      : 0;
    const blockHeight = Math.max(contentHeight, hasAvatar ? avatarSize : 0);

    // Calculate position based on setting
    let x = padding;
    let y = padding;
    let align: 'left' | 'right' = 'left';

    switch (branding.position) {
      case 'top-left':
        x = padding;
        y = padding;
        align = 'left';
        break;
      case 'top-right':
        x = width - padding;
        y = padding;
        align = 'right';
        break;
      case 'bottom-left':
        x = padding;
        y = height - padding - blockHeight;
        align = 'left';
        break;
      case 'bottom-right':
        x = width - padding;
        y = height - padding - blockHeight;
        align = 'right';
        break;
    }

    const totalHeight = blockHeight;
    const contentTop = contentHeight > 0 ? y + (totalHeight - contentHeight) / 2 : y;
    const avatarY = hasAvatar ? y + (totalHeight - avatarSize) / 2 : 0;
    const avatarCenterX = align === 'right' ? x - avatarSize / 2 : x + avatarSize / 2;
    const avatarCenterY = avatarY + avatarSize / 2;
    const avatarPatternScale = hasAvatar && brandingAvatar && brandingAvatar.width && brandingAvatar.height
      ? Math.max(avatarSize / brandingAvatar.width, avatarSize / brandingAvatar.height)
      : 1;

    const avatarOffset = hasAvatar ? avatarSize + avatarGap : 0;
    const textStartXBase = align === 'right' ? x - avatarOffset : x + avatarOffset;
    const textX = align === 'right' ? 0 : textStartXBase;
    const textWidth = align === 'right'
      ? Math.max(textStartXBase, 0)
      : Math.max(width - padding - textStartXBase, 0);

    // Calculate icon positions
    const iconScale = iconSize / 24; // SVG viewBox is 24x24
    const socialStartY = contentTop + textHeight + (hasTextContent ? 16 : 0);
    const anchorX = textStartXBase;

    return (
      <Group opacity={branding.opacity || 0.8}>
        {/* Avatar */}
        {hasAvatar && brandingAvatar && (
          <Circle
            x={avatarCenterX}
            y={avatarCenterY}
            radius={avatarSize / 2}
            fillPatternImage={brandingAvatar}
            fillPatternScaleX={avatarPatternScale}
            fillPatternScaleY={avatarPatternScale}
            fillPatternOffsetX={brandingAvatar.width / 2}
            fillPatternOffsetY={brandingAvatar.height / 2}
            listening={false}
          />
        )}

        {/* Text content */}
        {hasTextContent && (
          <Text
            x={textX}
            y={contentTop}
            width={textWidth}
            text={lines.join('\n')}
            fontSize={fontSize}
            fontFamily={branding.fontFamily || 'Inter'}
            fill={branding.color || '#ffffff'}
            align={align}
            lineHeight={1.5}
          />
        )}
        
        {/* Social icons with text */}
        {hasSocialIcons && activeSocialPlatforms.map((platform, index) => {
          const path = SOCIAL_ICON_PATHS[platform.key];
          if (!path) return null;
          
          // Calculate position for this social item
          let itemX: number;
          let itemY: number;
          
          if (socialLayout === 'vertical') {
            itemY = socialStartY + index * (socialItemHeight + iconGap - 4);
            itemX = anchorX;
          } else {
            itemY = socialStartY;
            // For horizontal layout, we need to calculate cumulative width
            // This is simplified - for perfect alignment we'd need to measure text
            const prevItemsWidth = activeSocialPlatforms.slice(0, index).reduce((acc, p) => {
              const textWidthEstimate = (p.value.length * fontSize * 0.5); // Approximate text width
              return acc + iconSize + iconTextGap + textWidthEstimate + iconGap;
            }, 0);
            itemX = align === 'right' ? anchorX - prevItemsWidth : anchorX + prevItemsWidth;
          }

          // Icon vertical centering within item
          const iconY = itemY + (socialItemHeight - iconSize) / 2;
          // Text vertical centering
          const textY = itemY + (socialItemHeight - fontSize) / 2;

          if (align === 'right') {
            // For right alignment: text first, then icon
            const textWidthEstimate = platform.value.length * fontSize * 0.5; // Approximate
            return (
              <Group key={platform.key}>
                <Path
                  x={itemX - iconSize}
                  y={iconY}
                  data={path}
                  fill={branding.color || '#ffffff'}
                  scaleX={iconScale}
                  scaleY={iconScale}
                />
                <Text
                  x={itemX - iconSize - iconTextGap - textWidthEstimate}
                  y={textY}
                  text={platform.value}
                  fontSize={fontSize}
                  fontFamily={branding.fontFamily || 'Inter'}
                  fill={branding.color || '#ffffff'}
                />
              </Group>
            );
          } else {
            // For left alignment: icon first, then text
            return (
              <Group key={platform.key}>
                <Path
                  x={itemX}
                  y={iconY}
                  data={path}
                  fill={branding.color || '#ffffff'}
                  scaleX={iconScale}
                  scaleY={iconScale}
                />
                <Text
                  x={itemX + iconSize + iconTextGap}
                  y={textY}
                  text={platform.value}
                  fontSize={fontSize}
                  fontFamily={branding.fontFamily || 'Inter'}
                  fill={branding.color || '#ffffff'}
                />
              </Group>
            );
          }
        })}
      </Group>
    );
  }, [background.branding, width, height, brandingAvatar]);

  const stagePosition = useMemo(() => getStagePosition(), [getStagePosition]);

  // Handle wheel/pinch zoom and pan on canvas
  const handleWheel = useCallback((e: React.WheelEvent<HTMLDivElement>) => {
    // Check if it's a pinch zoom gesture (ctrlKey is true for pinch-to-zoom)
    if (e.ctrlKey || e.metaKey) {
      e.preventDefault();
      e.stopPropagation();
      
      const scaleBy = 1.05;
      const minZoom = 0.1;
      const maxZoom = 3;
      
      // Determine zoom direction
      const direction = e.deltaY > 0 ? -1 : 1;
      const newZoom = direction > 0 ? zoom * scaleBy : zoom / scaleBy;
      
      // Clamp zoom between min and max
      const clampedZoom = Math.min(Math.max(newZoom, minZoom), maxZoom);
      setZoom(clampedZoom);
    } else {
      // Two-finger scroll for panning
      e.preventDefault();
      e.stopPropagation();
      
      setPanOffset(prev => ({
        x: prev.x - e.deltaX,
        y: prev.y - e.deltaY,
      }));
    }
  }, [zoom, setZoom]);

  // Prevent default browser zoom behavior on the container
  useEffect(() => {
    const container = containerRef.current;
    if (!container) return;

    const preventDefaultZoom = (e: WheelEvent) => {
      // Prevent default for both zoom (ctrl/meta) and pan (regular scroll)
      e.preventDefault();
    };

    // Use passive: false to allow preventDefault
    container.addEventListener('wheel', preventDefaultZoom, { passive: false });
    
    return () => {
      container.removeEventListener('wheel', preventDefaultZoom);
    };
  }, []);

  return (
    <div 
      ref={containerRef}
      className="flex-1 bg-neutral-900 overflow-hidden relative"
      style={{ cursor: tool !== 'select' ? 'crosshair' : 'default' }}
      onWheel={handleWheel}
      onDoubleClick={(e) => {
        // Double-click on empty area to reset pan
        if (e.target === containerRef.current) {
          resetPan();
        }
      }}
    >
      <Stage
        ref={stageRef}
        width={dimensions.width}
        height={dimensions.height}
        onClick={handleStageClick}
        x={stagePosition.x}
        y={stagePosition.y}
        scaleX={zoom}
        scaleY={zoom}
      >
        <Layer>
          {renderBackground()}
          {brandStripElement}
          {brandingElement}
          {gridLines}
          
          {snap.elements.map((element) => {
            if (!element.visible) return null;
            
            switch (element.type) {
              case 'code':
                return (
                  <CodeBlock
                    key={element.id}
                    element={element as CodeElement}
                    isSelected={selectedElementId === element.id}
                    onSelect={() => selectElement(element.id)}
                    onChange={(updates: Partial<CodeElement>) => updateElement(element.id, updates)}
                  />
                );
              case 'text':
                return (
                  <TextBlock
                    key={element.id}
                    element={element as TextElement}
                    isSelected={selectedElementId === element.id}
                    onSelect={() => selectElement(element.id)}
                    onChange={(updates: Partial<TextElement>) => updateElement(element.id, updates)}
                  />
                );
              case 'arrow':
                return (
                  <Arrow
                    key={element.id}
                    element={element as ArrowElement}
                    isSelected={selectedElementId === element.id}
                    onSelect={() => selectElement(element.id)}
                    onChange={(updates: Partial<ArrowElement>) => updateElement(element.id, updates)}
                  />
                );
              default:
                return null;
            }
          })}
        </Layer>
      </Stage>
    </div>
  );
};

export default memo(Canvas);
