import React, { useEffect, useRef, forwardRef, useImperativeHandle, useState } from 'react';
import { fabric } from 'fabric';

const CADCanvas = forwardRef(({ activeTool, setActiveTool, onCanvasReady }, ref) => {
  const canvasEl = useRef(null);
  const fabricRef = useRef(null);
  const [zoom, setZoom] = useState(1);
  const isDrawing = useRef(false);
  const startPoint = useRef(null);
  const tempShape = useRef(null);

  useImperativeHandle(ref, () => ({
    getCanvas: () => fabricRef.current,
    toJSON: () => fabricRef.current?.toJSON(),
    loadFromJSON: (json) => {
      if (fabricRef.current) {
        fabricRef.current.loadFromJSON(json, fabricRef.current.renderAll.bind(fabricRef.current));
      }
    },
    addSvgObject: (svgStr) => {
      if (!fabricRef.current) return;
      fabric.loadSVGFromString(svgStr, (objects, options) => {
        const group = fabric.util.groupSVGElements(objects, options);
        group.set({ left: 100, top: 100, scaleX: 0.5, scaleY: 0.5 });
        fabricRef.current.add(group);
        fabricRef.current.setActiveObject(group);
        fabricRef.current.renderAll();
      });
    },
    addObjects: (objects) => {
      if (!fabricRef.current) return;
      objects.forEach(obj => {
        let shape;
        if (obj.type === 'line') {
          shape = new fabric.Line([obj.x1, obj.y1, obj.x2, obj.y2], { stroke: obj.stroke || '#000', strokeWidth: obj.strokeWidth || 1 });
        } else if (obj.type === 'circle') {
          shape = new fabric.Circle({ left: obj.left, top: obj.top, radius: obj.radius, fill: obj.fill || 'transparent', stroke: obj.stroke || '#000', strokeWidth: obj.strokeWidth || 1 });
        } else if (obj.type === 'polygon') {
          shape = new fabric.Polygon(obj.points.map(p => ({ x: p.x, y: p.y })), { fill: obj.fill || 'transparent', stroke: obj.stroke || '#000', strokeWidth: obj.strokeWidth || 1 });
        } else if (obj.type === 'rect') {
          shape = new fabric.Rect({ left: obj.left, top: obj.top, width: obj.width, height: obj.height, fill: obj.fill || 'transparent', stroke: obj.stroke || '#000', strokeWidth: obj.strokeWidth || 1 });
        }
        if (shape) fabricRef.current.add(shape);
      });
      fabricRef.current.renderAll();
    },
    // Get selected elements for block creation
    getSelectedElements: () => {
      if (!fabricRef.current) return [];
      const activeObject = fabricRef.current.getActiveObject();
      if (!activeObject) return [];
      
      // If it's a group, return all objects in the group
      if (activeObject.type === 'group') {
        return activeObject.getObjects().map(obj => ({
          id: obj.id || Date.now() + Math.random(),
          type: obj.type,
          ...obj.toObject(['id', 'type', 'left', 'top', 'width', 'height', 'radius', 'x1', 'y1', 'x2', 'y2', 'points', 'fill', 'stroke', 'strokeWidth'])
        }));
      }
      
      // If it's a single object, return it
      return [{
        id: activeObject.id || Date.now() + Math.random(),
        type: activeObject.type,
        ...activeObject.toObject(['id', 'type', 'left', 'top', 'width', 'height', 'radius', 'x1', 'y1', 'x2', 'y2', 'points', 'fill', 'stroke', 'strokeWidth'])
      }];
    },
    // Generate SVG data for selected elements
    generateSvgData: () => {
      if (!fabricRef.current) return '';
      const activeObject = fabricRef.current.getActiveObject();
      if (!activeObject) return '';
      
      // Clone the object to avoid modifying the original
      return activeObject.toSVG();
    }
  }));

  // Initialize fabric canvas
  useEffect(() => {
    if (canvasEl.current && !fabricRef.current) {
      fabricRef.current = new fabric.Canvas(canvasEl.current, {
        width: canvasEl.current.parentElement.clientWidth,
        height: canvasEl.current.parentElement.clientHeight,
        backgroundColor: '#fff',
        selection: true,
      });

      if (onCanvasReady) onCanvasReady(fabricRef.current);

      const handleResize = () => {
        if (canvasEl.current && fabricRef.current) {
          fabricRef.current.setWidth(canvasEl.current.parentElement.clientWidth);
          fabricRef.current.setHeight(canvasEl.current.parentElement.clientHeight);
          fabricRef.current.renderAll();
        }
      };
      window.addEventListener('resize', handleResize);

      return () => {
        window.removeEventListener('resize', handleResize);
        if (fabricRef.current) {
          fabricRef.current.dispose();
          fabricRef.current = null;
        }
      };
    }
  }, []);

  // Zoom with mouse wheel
  useEffect(() => {
    if (!fabricRef.current) return;
    const canvas = fabricRef.current;
    const handleWheel = (opt) => {
      const delta = opt.e.deltaY;
      let zoom = canvas.getZoom();
      zoom *= 0.999 ** delta;
      if (zoom > 20) zoom = 20;
      if (zoom < 0.01) zoom = 0.01;
      canvas.zoomToPoint({ x: opt.e.offsetX, y: opt.e.offsetY }, zoom);
      opt.e.preventDefault();
      opt.e.stopPropagation();
      setZoom(Math.round(zoom * 100) / 100);
    };
    canvas.on('mouse:wheel', handleWheel);
    return () => canvas.off('mouse:wheel', handleWheel);
  }, []);

  // Drawing tool behavior
  useEffect(() => {
    if (!fabricRef.current) return;
    const canvas = fabricRef.current;

    canvas.off('mouse:down');
    canvas.off('mouse:move');
    canvas.off('mouse:up');

    if (activeTool === 'select') {
      canvas.isDrawingMode = false;
      canvas.selection = true;
      canvas.forEachObject(obj => obj.selectable = true);
      return;
    }

    canvas.selection = false;
    canvas.forEachObject(obj => obj.selectable = false);

    if (activeTool === 'freehand') {
      canvas.isDrawingMode = true;
      canvas.freeDrawingBrush.width = 2;
      canvas.freeDrawingBrush.color = '#000';
      return;
    }

    canvas.isDrawingMode = false;

    canvas.on('mouse:down', (opt) => {
      isDrawing.current = true;
      const pointer = canvas.getPointer(opt.e);
      startPoint.current = { x: pointer.x, y: pointer.y };

      if (activeTool === 'line') {
        tempShape.current = new fabric.Line(
          [pointer.x, pointer.y, pointer.x, pointer.y],
          { stroke: '#000', strokeWidth: 2 }
        );
      } else if (activeTool === 'rect') {
        tempShape.current = new fabric.Rect({
          left: pointer.x,
          top: pointer.y,
          width: 0,
          height: 0,
          fill: 'transparent',
          stroke: '#000',
          strokeWidth: 2,
        });
      } else if (activeTool === 'circle') {
        tempShape.current = new fabric.Circle({
          left: pointer.x,
          top: pointer.y,
          radius: 0,
          fill: 'transparent',
          stroke: '#000',
          strokeWidth: 2,
        });
      } else if (activeTool === 'text') {
        const text = new fabric.IText('Text', {
          left: pointer.x,
          top: pointer.y,
          fontSize: 20,
          fill: '#000',
        });
        canvas.add(text);
        canvas.setActiveObject(text);
        isDrawing.current = false;
        return;
      } else if (activeTool === 'dimension') {
        const line = new fabric.Line([pointer.x, pointer.y, pointer.x, pointer.y], {
          stroke: '#e74c3c', strokeWidth: 1, strokeDashArray: [5, 5]
        });
        const tick1 = new fabric.Line([pointer.x, pointer.y, pointer.x+10, pointer.y], { stroke: '#e74c3c', strokeWidth: 1 });
        const tick2 = new fabric.Line([pointer.x+10, pointer.y, pointer.x+10, pointer.y+10], { stroke: '#e74c3c', strokeWidth: 1 });
        const text = new fabric.Text('0', {
          left: pointer.x, top: pointer.y - 20, fontSize: 12, fill: '#e74c3c',
        });
        const group = new fabric.Group([line, tick1, tick2, text], {
          selectable: false, hasControls: false, hasBorders: false,
        });
        tempShape.current = { group, line, text, tick1, tick2, start: {x: pointer.x, y: pointer.y} };
        canvas.add(group);
      }
      if (tempShape.current && !(activeTool === 'dimension')) {
        canvas.add(tempShape.current);
      }
    });

    canvas.on('mouse:move', (opt) => {
      if (!isDrawing.current || !tempShape.current) return;
      const pointer = canvas.getPointer(opt.e);

      if (activeTool === 'line') {
        tempShape.current.set({ x2: pointer.x, y2: pointer.y });
      } else if (activeTool === 'rect') {
        const start = startPoint.current;
        let left = Math.min(start.x, pointer.x);
        let top = Math.min(start.y, pointer.y);
        let width = Math.abs(start.x - pointer.x);
        let height = Math.abs(start.y - pointer.y);
        tempShape.current.set({ left, top, width, height });
      } else if (activeTool === 'circle') {
        const start = startPoint.current;
        const radius = Math.sqrt(
          (pointer.x - start.x) ** 2 + (pointer.y - start.y) ** 2
        ) / 2;
        tempShape.current.set({
          left: start.x - radius,
          top: start.y - radius,
          radius: radius,
        });
      } else if (activeTool === 'dimension') {
        const { group, line, text, tick1, tick2, start } = tempShape.current;
        // Update line
        line.set({ x2: pointer.x, y2: pointer.y });
        // Compute distance
        const dx = pointer.x - start.x;
        const dy = pointer.y - start.y;
        const dist = Math.sqrt(dx*dx + dy*dy).toFixed(1);
        text.set({ text: dist });
        // Update text position to middle of line
        const midX = (start.x + pointer.x) / 2;
        const midY = (start.y + pointer.y) / 2;
        text.set({ left: midX - 15, top: midY - 20 });
        // Update tick positions (simplified: put at start and end)
        tick1.set({ x1: start.x, y1: start.y, x2: start.x+10, y2: start.y });
        tick2.set({ x1: pointer.x, y1: pointer.y, x2: pointer.x-10, y2: pointer.y });
        // Add corner tick lines (just simple markers)
        // Refresh group
        group.addWithUpdate();
      }
      canvas.renderAll();
    });

    canvas.on('mouse:up', () => {
      if (isDrawing.current && activeTool === 'dimension' && tempShape.current) {
        // Make dimension group selectable after placement
        tempShape.current.group.set({ selectable: true, hasControls: false, hasBorders: true });
      }
      isDrawing.current = false;
      tempShape.current = null;
    });
  }, [activeTool]);

  return (
    <div style={{ width: '100%', height: '100%' }}>
      <canvas ref={canvasEl} />
      <div style={{ position: 'absolute', bottom: 10, right: 10, background: 'rgba(255,255,255,0.8)', padding: '4px 8px', borderRadius: 4, fontSize: 12 }}>
        Zoom: {Math.round(zoom * 100)}%
      </div>
    </div>
  );
});

export default CADCanvas;
