import { useEffect, useRef, type RefObject } from "react";
import Konva from "konva";
import { useEditorStore } from "../../store/editorStore";
import {
  getNodeTransformDimensions,
  nodeHasPendingTransform,
  resolveObjectFromNodeId,
} from "../../utils/transformCommit";

export const useTransformHandlers = (
  transformerRef: RefObject<Konva.Transformer | null>,
  layerRef: RefObject<Konva.Layer | null>
) => {
  const {
    objects,
    selectedObjectIds,
    updateObject,
    applyTableResize,
  } = useEditorStore();
  const commitTransformRef = useRef<(() => void) | null>(null);

  // Attach transformer to selected objects when they change
  useEffect(() => {
    if (
      !transformerRef.current ||
      selectedObjectIds.length === 0 ||
      !layerRef.current
    ) {
      if (transformerRef.current) {
        transformerRef.current.nodes([]);
        transformerRef.current.getLayer()?.batchDraw();
      }
      return;
    }

    // Use a small delay to ensure the nodes are mounted (especially for images that need to load)
    const timeoutId = setTimeout(() => {
      if (!layerRef.current || !transformerRef.current) return;

      const nodesToTransform: Konva.Node[] = [];

      selectedObjectIds.forEach((objId) => {
        const selectedObject = objects.find((obj) => obj.id === objId);
        if (!selectedObject) return;

        // For all objects, find by id (group, grid, or regular)
        if (selectedObject.type === "group" || selectedObject.type === "grid") {
          const node = layerRef.current?.findOne(`#${objId}`);
          if (node) {
            nodesToTransform.push(node);
          }
        } else {
          // اگر object با mask گروه شده، transformer را به Group متصل کن
          const maskedGroup = layerRef.current?.findOne(`#masked-${objId}`);
          const regularNode = layerRef.current?.findOne(`#${objId}`);
          const targetNode = maskedGroup || regularNode;
          if (targetNode) {
            nodesToTransform.push(targetNode);
          }
        }
      });

      if (nodesToTransform.length > 0) {
        transformerRef.current.nodes(nodesToTransform);
        transformerRef.current.getLayer()?.batchDraw();
      }
    }, 100);

    return () => {
      clearTimeout(timeoutId);
      const transformer = transformerRef.current;
      if (!transformer) return;
      const nodes = transformer.nodes();
      if (nodes.some(nodeHasPendingTransform)) {
        commitTransformRef.current?.();
      }
    };
  }, [selectedObjectIds, objects, transformerRef, layerRef]);

  useEffect(() => {
    if (!transformerRef.current || selectedObjectIds.length === 0) return;

    const transformer = transformerRef.current;

    const handleTransform = () => {
      const nodes = transformer.nodes();
      if (nodes.length === 0 || !layerRef.current) return;

      nodes.forEach((node) => {
        const nodeId = node.id();
        const selectedObject = objects.find((obj) => obj.id === nodeId);
        if (!selectedObject || selectedObject.type !== "group") return;

        const scaleX = node.scaleX();
        const scaleY = node.scaleY();
        const rotation = node.rotation();
        const newX = node.x();
        const newY = node.y();

        const groupMembers = objects.filter(
          (o) => o.groupId === selectedObject.id
        );
        const oldGroupX = selectedObject.x || 0;
        const oldGroupY = selectedObject.y || 0;

        // Update Konva nodes directly for live preview
        groupMembers.forEach((member) => {
          const relativeX = (member.x || 0) - oldGroupX;
          const relativeY = (member.y || 0) - oldGroupY;

          // Apply rotation
          const angle = (rotation * Math.PI) / 180;
          const rotatedX =
            relativeX * Math.cos(angle) - relativeY * Math.sin(angle);
          const rotatedY =
            relativeX * Math.sin(angle) + relativeY * Math.cos(angle);

          // Apply scale
          const scaledX = rotatedX * scaleX;
          const scaledY = rotatedY * scaleY;

          const finalX = newX + scaledX;
          const finalY = newY + scaledY;

          // Find the Konva node for this member
          const memberNode =
            layerRef.current?.findOne(`#${member.id}`) ||
            layerRef.current?.findOne(`#masked-${member.id}`);
          if (memberNode) {
            // برای AbstractShape و TriangleShape که از مرکز استفاده می‌کنند، باید موقعیت را تنظیم کنیم
            if (
              member.type === "rectangle" &&
              (member.shapeType === "triangle" ||
                member.shapeType === "abstract")
            ) {
              // موقعیت در store گوشه بالا-چپ است، اما در render از مرکز استفاده می‌شود
              const w = (member.width || 100) * scaleX;
              const h = (member.height || 100) * scaleY;
              memberNode.x(finalX + w / 2);
              memberNode.y(finalY + h / 2);
            } else {
              memberNode.x(finalX);
              memberNode.y(finalY);
            }

            memberNode.width((member.width || 100) * scaleX);
            memberNode.height((member.height || 100) * scaleY);
            memberNode.rotation((member.rotation || 0) + rotation);
            memberNode.scaleX(1);
            memberNode.scaleY(1);
          }
        });

        layerRef.current?.batchDraw();
      });
    };

    const handleTransformEnd = () => {
      useEditorStore.getState().commitObjectHistoryBeforeChange();
      const nodes = transformer.nodes();
      if (nodes.length === 0) return;

      nodes.forEach((node) => {
        const nodeId = node.id();
        const selectedObject = resolveObjectFromNodeId(nodeId, objects);
        if (!selectedObject) return;

        // Handle group objects
        if (selectedObject.type === "group") {
          const scaleX = node.scaleX();
          const scaleY = node.scaleY();
          const rotation = node.rotation();
          const newX = node.x();
          const newY = node.y();

          node.scaleX(1);
          node.scaleY(1);
          node.rotation(0);

          const groupMembers = objects.filter(
            (o) => o.groupId === selectedObject.id
          );
          const oldGroupX = selectedObject.x || 0;
          const oldGroupY = selectedObject.y || 0;

          // محاسبه bounds جدید بر اساا member های update شده
          const updatedMembers = groupMembers.map((member) => {
            const relativeX = (member.x || 0) - oldGroupX;
            const relativeY = (member.y || 0) - oldGroupY;

            // Apply rotation
            const angle = (rotation * Math.PI) / 180;
            const rotatedX =
              relativeX * Math.cos(angle) - relativeY * Math.sin(angle);
            const rotatedY =
              relativeX * Math.sin(angle) + relativeY * Math.cos(angle);

            // Apply scale
            const scaledX = rotatedX * scaleX;
            const scaledY = rotatedY * scaleY;

            return {
              id: member.id,
              x: newX + scaledX,
              y: newY + scaledY,
              rotation: (member.rotation || 0) + rotation,
              width: (member.width || 100) * scaleX,
              height: (member.height || 100) * scaleY,
            };
          });

          // Update all members
          updatedMembers.forEach((member) => {
            updateObject(member.id, {
              x: member.x,
              y: member.y,
              rotation: member.rotation,
              width: member.width,
              height: member.height,
            });
          });

          // محاسبه bounds گروه بر اساس member های update شده با در نظر گرفتن rotation
          let minX = Infinity;
          let minY = Infinity;
          let maxX = -Infinity;
          let maxY = -Infinity;

          updatedMembers.forEach((m) => {
            const originalMember = groupMembers.find((gm) => gm.id === m.id);
            if (!originalMember) return;

            const w = m.width || 0;
            const h = m.height || 0;

            // برای دایره، x و y مرکز دایره است و bounding box همیشه یک مربع است
            if (
              originalMember.type === "rectangle" &&
              originalMember.shapeType === "circle"
            ) {
              const radius = w / 2;
              const cx = m.x || 0;
              const cy = m.y || 0;
              // برای دایره، bounding box همیشه یک مربع با ضلع برابر با قطر است
              minX = Math.min(minX, cx - radius);
              minY = Math.min(minY, cy - radius);
              maxX = Math.max(maxX, cx + radius);
              maxY = Math.max(maxY, cy + radius);
              return;
            }

            // برای مثلث و abstract، x و y در store گوشه بالا-چپ است اما در render مرکز استفاده می‌شود
            if (
              originalMember.type === "rectangle" &&
              (originalMember.shapeType === "triangle" ||
                originalMember.shapeType === "abstract")
            ) {
              // محاسبه مرکز از گوشه بالا-چپ
              const cx = (m.x || 0) + w / 2;
              const cy = (m.y || 0) + h / 2;
              const rot = ((m.rotation || 0) * Math.PI) / 180;

              // برای abstract، از radius واقعی استفاده کن (0.85 * baseRadius)
              // برای triangle، از radius واقعی استفاده کن (min(width, height) / 2)
              let actualRadius: number;
              if (originalMember.shapeType === "abstract") {
                const baseRadius = Math.min(w / 2, h / 2);
                actualRadius = baseRadius * 0.85;
              } else {
                // triangle
                actualRadius = Math.min(w / 2, h / 2);
              }

              // محاسبه چهار گوشه با استفاده از radius واقعی
              const corners = [
                { x: -actualRadius, y: -actualRadius },
                { x: actualRadius, y: -actualRadius },
                { x: actualRadius, y: actualRadius },
                { x: -actualRadius, y: actualRadius },
              ];

              corners.forEach((corner) => {
                const rotatedX =
                  corner.x * Math.cos(rot) - corner.y * Math.sin(rot);
                const rotatedY =
                  corner.x * Math.sin(rot) + corner.y * Math.cos(rot);
                const finalX = cx + rotatedX;
                const finalY = cy + rotatedY;
                minX = Math.min(minX, finalX);
                minY = Math.min(minY, finalY);
                maxX = Math.max(maxX, finalX);
                maxY = Math.max(maxY, finalY);
              });
              return;
            }

            // برای arrow و line، x و y نقطه شروع است و width/height نقطه پایان است
            if (
              originalMember.type === "arrow" ||
              originalMember.type === "line"
            ) {
              const startX = m.x || 0;
              const startY = m.y || 0;
              const endX = m.width || 0;
              const endY = m.height || 0;

              // برای arrow و line، bounding box از نقطه شروع تا نقطه پایان است
              minX = Math.min(minX, startX, endX);
              minY = Math.min(minY, startY, endY);
              maxX = Math.max(maxX, startX, endX);
              maxY = Math.max(maxY, startY, endY);
              return;
            }

            // برای سایر اشکال، x و y گوشه بالا-چپ است
            const cx = (m.x || 0) + w / 2;
            const cy = (m.y || 0) + h / 2;
            const rot = ((m.rotation || 0) * Math.PI) / 180;

            // محاسبه چهار گوشه rectangle با rotation
            const corners = [
              { x: -w / 2, y: -h / 2 },
              { x: w / 2, y: -h / 2 },
              { x: w / 2, y: h / 2 },
              { x: -w / 2, y: h / 2 },
            ];

            corners.forEach((corner) => {
              const rotatedX =
                corner.x * Math.cos(rot) - corner.y * Math.sin(rot);
              const rotatedY =
                corner.x * Math.sin(rot) + corner.y * Math.cos(rot);
              const finalX = cx + rotatedX;
              const finalY = cy + rotatedY;
              minX = Math.min(minX, finalX);
              minY = Math.min(minY, finalY);
              maxX = Math.max(maxX, finalX);
              maxY = Math.max(maxY, finalY);
            });
          });

          const groupWidth = maxX - minX;
          const groupHeight = maxY - minY;

          // Update group node directly in Konva first to prevent transformer flicker
          if (layerRef.current) {
            const groupNode = layerRef.current.findOne(`#${selectedObject.id}`);
            if (groupNode) {
              groupNode.x(minX);
              groupNode.y(minY);
              groupNode.width(groupWidth);
              groupNode.height(groupHeight);
              groupNode.rotation(0);
            }
          }

          // Update group object with new bounds (rotation should remain 0)
          updateObject(selectedObject.id, {
            x: minX,
            y: minY,
            width: groupWidth,
            height: groupHeight,
            rotation: 0,
          });

          // Force transformer to update immediately
          if (transformerRef.current && layerRef.current) {
            const groupNode = layerRef.current.findOne(`#${selectedObject.id}`);
            if (groupNode) {
              transformerRef.current.nodes([groupNode]);
              transformerRef.current.getLayer()?.batchDraw();
            }
          }
        } else if (selectedObject.type === "grid") {
          // Handle grid objects separately
          const scaleX = node.scaleX();
          const scaleY = node.scaleY();

          node.scaleX(1);
          node.scaleY(1);

          const newWidth = (selectedObject.width || 300) * scaleX;
          const newHeight = (selectedObject.height || 200) * scaleY;

          applyTableResize(selectedObject.id, newWidth, newHeight);
          updateObject(selectedObject.id, {
            x: node.x(),
            y: node.y(),
          });
        } else {
          // Handle other objects
          const scaleX = node.scaleX();
          const scaleY = node.scaleY();

          node.scaleX(1);
          node.scaleY(1);

          // Handle special shapes that use radius (Circle, Triangle, Abstract)
          if (selectedObject.type === "rectangle") {
            if (selectedObject.shapeType === "circle") {
              // Circle: maintain aspect ratio and use average scale
              const avgScale = (scaleX + scaleY) / 2;
              const newRadius = Math.max(
                5,
                ((selectedObject.width || 50) / 2) * avgScale
              );
              const newSize = newRadius * 2;
              updateObject(selectedObject.id, {
                x: node.x(),
                y: node.y(),
                rotation: node.rotation(),
                width: newSize,
                height: newSize,
              });
            } else if (
              selectedObject.shapeType === "triangle" ||
              selectedObject.shapeType === "abstract"
            ) {
              // Triangle and Abstract: maintain aspect ratio and use average scale
              const avgScale = (scaleX + scaleY) / 2;
              const baseRadius = Math.min(
                (selectedObject.width || 100) / 2,
                (selectedObject.height || 100) / 2
              );
              const newRadius = Math.max(5, baseRadius * avgScale);
              const newSize = newRadius * 2;
              updateObject(selectedObject.id, {
                x: node.x() - newSize / 2,
                y: node.y() - newSize / 2,
                rotation: node.rotation(),
                width: newSize,
                height: newSize,
              });
            } else {
              // Regular rectangle
              updateObject(selectedObject.id, {
                x: node.x(),
                y: node.y(),
                rotation: node.rotation(),
                width: Math.max(5, (selectedObject.width || 100) * scaleX),
                height: Math.max(5, (selectedObject.height || 100) * scaleY),
              });
            }
          } else if (
            selectedObject.type === "line" ||
            selectedObject.type === "arrow"
          ) {
            // Line and Arrow: scale the end point
            const startX = selectedObject.x || 0;
            const startY = selectedObject.y || 0;
            const endX = selectedObject.width || 0;
            const endY = selectedObject.height || 0;
            const dx = (endX - startX) * scaleX;
            const dy = (endY - startY) * scaleY;
            updateObject(selectedObject.id, {
              x: node.x(),
              y: node.y(),
              rotation: node.rotation(),
              width: node.x() + dx,
              height: node.y() + dy,
            });
          } else if (
            selectedObject.type === "text" ||
            selectedObject.type === "link"
          ) {
            // Text and Link: use stored width/height from store, not getClientRect
            // because TextShape auto-calculates dimensions and we need to scale the stored values
            const storedWidth = selectedObject.width || 100;
            const storedHeight = selectedObject.height || 100;
            // Use average scale to maintain aspect ratio for text
            const avgScale = (scaleX + scaleY) / 2;
            const newWidth = Math.max(5, storedWidth * scaleX);
            const newHeight = Math.max(5, storedHeight * scaleY);

            if (selectedObject.type === "link") {
              // For link, also update fontSize
              updateObject(selectedObject.id, {
                x: node.x(),
                y: node.y(),
                rotation: node.rotation(),
                fontSize: selectedObject.fontSize
                  ? Math.max(5, selectedObject.fontSize * scaleX)
                  : undefined,
              });
            } else {
              // For text, update width, height, and fontSize
              updateObject(selectedObject.id, {
                x: node.x(),
                y: node.y(),
                rotation: node.rotation(),
                width: newWidth,
                height: newHeight,
                fontSize: selectedObject.fontSize
                  ? Math.max(5, selectedObject.fontSize * avgScale)
                  : undefined,
              });
            }
          } else if (selectedObject.type === "custom-shape" || selectedObject.type === "pencil") {
            // Scale each vertex in-place; no width/height anchor needed
            const oldPoints = selectedObject.points ?? [];
            const newPoints = oldPoints.map((val, i) =>
              i % 2 === 0 ? val * scaleX : val * scaleY,
            );

            // Recompute axis-aligned bounding box from the scaled points
            const xs = newPoints.filter((_, i) => i % 2 === 0);
            const ys = newPoints.filter((_, i) => i % 2 !== 0);
            const newWidth =
              xs.length > 0 ? Math.max(...xs) - Math.min(...xs) : 0;
            const newHeight =
              ys.length > 0 ? Math.max(...ys) - Math.min(...ys) : 0;

            updateObject(selectedObject.id, {
              x: node.x(),
              y: node.y(),
              rotation: node.rotation(),
              points: newPoints,
              width: Math.max(1, newWidth),
              height: Math.max(1, newHeight),
            });
          } else {
            // Default for raster objects (image, sticker, document, video, …)
            const { width: baseWidth, height: baseHeight } =
              getNodeTransformDimensions(node);
            updateObject(selectedObject.id, {
              x: node.x(),
              y: node.y(),
              rotation: node.rotation(),
              width: Math.max(5, baseWidth * scaleX),
              height: Math.max(5, baseHeight * scaleY),
            });
          }
        }
      });
    };

    commitTransformRef.current = handleTransformEnd;

    transformer.on("transform", handleTransform);
    transformer.on("transformend", handleTransformEnd);

    return () => {
      commitTransformRef.current = null;
      transformer.off("transform", handleTransform);
      transformer.off("transformend", handleTransformEnd);
    };
  }, [
    selectedObjectIds,
    objects,
    transformerRef,
    applyTableResize,
    updateObject,
    layerRef,
  ]);
};
