"use client";

import { useCallback, useEffect, useMemo, useRef } from "react";
import { Layer, Rect, Stage, Transformer } from "react-konva";
import type Konva from "konva";

import { CanvasLayerNode } from "@/components/studio/canvas/CanvasLayerNode";
import { useCanvasKeyboard } from "@/hooks/useCanvasKeyboard";
import { useCanvasPreviewPlayback } from "@/hooks/useCanvasPreviewPlayback";
import { useContainerSize } from "@/hooks/useContainerSize";
import { registerStudioStage, getStudioStage } from "@/lib/studio-canvas-stage";
import {
  nodeTransformToLayer,
  resetNodeScale,
} from "@/lib/canvas-transform";
import { getShapeProps } from "@/lib/studio-layer-props";
import { getActiveScene, isFlexStoryProject, useStudioStore } from "@/lib/studio-store";
import type { Layer as StudioLayer } from "@/lib/studio-types";

export const STAGE_WIDTH = 1280;
export const STAGE_HEIGHT = 720;

export function CanvasEditor() {
  const { ref: containerRef, width: containerWidth } = useContainerSize();
  const nodeRefs = useRef<Map<string, Konva.Node>>(new Map());
  const transformerRef = useRef<Konva.Transformer>(null);
  const canvasWrapperRef = useRef<HTMLDivElement>(null);

  const scenes = useStudioStore((state) => state.scenes);
  const activeSceneId = useStudioStore((state) => state.activeSceneId);
  const selectedLayerId = useStudioStore((state) => state.selectedLayerId);
  const isPlaying = useStudioStore((state) => state.isPlaying);
  const sceneBackgroundColor = useStudioStore(
    (state) => state.sceneBackgroundColor
  );
  const setSelectedLayer = useStudioStore((state) => state.setSelectedLayer);
  const updateLayer = useStudioStore((state) => state.updateLayer);
  const updateScene = useStudioStore((state) => state.updateScene);
  // Scene-engine (FlexStory) templates render in Remotion at fixed positions —
  // dragging/resizing layers on the canvas does nothing, so the canvas becomes a
  // read-only preview; editing happens only via the field form.
  const lockedGeometry = useStudioStore((state) =>
    isFlexStoryProject(state.chooseMode)
  );

  const thumbTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);

  useCanvasKeyboard();
  useCanvasPreviewPlayback(canvasWrapperRef);

  const activeScene = useMemo(
    () => getActiveScene({ scenes, activeSceneId }),
    [scenes, activeSceneId]
  );

  const sortedLayers = useMemo(
    () =>
      [...(activeScene?.layers ?? [])].sort((a, b) => a.zIndex - b.zIndex),
    [activeScene?.layers]
  );

  const scale =
    containerWidth > 0 ? containerWidth / STAGE_WIDTH : 1;
  const stageHeight = STAGE_HEIGHT * scale;

  const registerNode = useCallback((id: string, node: Konva.Node | null) => {
    if (node) {
      nodeRefs.current.set(id, node);
    } else {
      nodeRefs.current.delete(id);
    }
  }, []);

  useEffect(() => {
    const transformer = transformerRef.current;
    if (!transformer || isPlaying) return;

    if (!selectedLayerId) {
      transformer.nodes([]);
      transformer.getLayer()?.batchDraw();
      return;
    }

    // Text layers are fixed — no transform handles
    const selectedLayer = sortedLayers.find((l) => l.id === selectedLayerId);
    if (selectedLayer?.type === "text") {
      transformer.nodes([]);
      transformer.getLayer()?.batchDraw();
      return;
    }

    const node = nodeRefs.current.get(selectedLayerId);
    if (node) {
      transformer.nodes([node]);
      transformer.getLayer()?.batchDraw();
    }
  }, [selectedLayerId, sortedLayers, isPlaying]);

  // Auto-capture scene thumbnail whenever layers or background change. Skipped for
  // scene-engine templates so the flat Konva snapshot doesn't overwrite the real
  // rendered per-scene image.
  useEffect(() => {
    if (isPlaying || !activeSceneId || lockedGeometry) return;

    if (thumbTimerRef.current) clearTimeout(thumbTimerRef.current);
    thumbTimerRef.current = setTimeout(() => {
      const stage = getStudioStage();
      if (!stage) return;

      // Temporarily clear transformer so handles don't appear in thumbnail
      const transformer = transformerRef.current;
      const prevNodes = transformer?.nodes() ?? [];
      transformer?.nodes([]);
      transformer?.getLayer()?.batchDraw();

      stage.toDataURL({
        pixelRatio: 0.25,
        callback: (dataUrl: string) => {
          updateScene(activeSceneId, { thumbnailUrl: dataUrl });
          // Restore transformer
          transformer?.nodes(prevNodes);
          transformer?.getLayer()?.batchDraw();
        },
      });
    }, 700);

    return () => {
      if (thumbTimerRef.current) clearTimeout(thumbTimerRef.current);
    };
  // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [sortedLayers, sceneBackgroundColor, activeSceneId, isPlaying]);

  const applyTransform = useCallback(
    (layer: StudioLayer, node: Konva.Node) => {
      if (layer.type === "shape" && getShapeProps(layer.props).shape === "circle") {
        const circle = node as Konva.Circle;
        const scaledRadius = circle.radius() * circle.scaleX();
        resetNodeScale(circle);
        updateLayer(layer.id, {
          x: circle.x() - scaledRadius,
          y: circle.y() - scaledRadius,
          width: scaledRadius * 2,
          height: scaledRadius * 2,
          rotation: circle.rotation(),
        });
        return;
      }

      resetNodeScale(node);
      updateLayer(layer.id, nodeTransformToLayer(node));
    },
    [updateLayer]
  );

  const applyDrag = useCallback(
    (layer: StudioLayer, x: number, y: number) => {
      if (layer.type === "shape" && getShapeProps(layer.props).shape === "circle") {
        const radius = Math.min(layer.width, layer.height) / 2;
        updateLayer(layer.id, { x: x - radius, y: y - radius });
        return;
      }
      updateLayer(layer.id, { x, y });
    },
    [updateLayer]
  );

  const handleStagePointerDown = (event: Konva.KonvaEventObject<MouseEvent>) => {
    const target = event.target;
    const clickedOnEmpty =
      target === target.getStage() || target.name() === "background";
    if (clickedOnEmpty) {
      setSelectedLayer(null);
    }
  };

  if (containerWidth <= 0) {
    return <div ref={containerRef} className="h-full w-full" />;
  }

  return (
    <div
      ref={containerRef}
      className="flex h-full w-full items-center justify-center"
    >
      <div className="overflow-hidden rounded-lg shadow-2xl ring-1 ring-gray-700/80">
        <div ref={canvasWrapperRef} className="origin-center will-change-transform">
      <Stage
        ref={(node) => registerStudioStage(node)}
        width={containerWidth}
        height={stageHeight}
        scaleX={scale}
        scaleY={scale}
        onMouseDown={isPlaying || lockedGeometry ? undefined : handleStagePointerDown}
      >
        <Layer listening={!lockedGeometry}>
          <Rect
            name="background"
            x={0}
            y={0}
            width={STAGE_WIDTH}
            height={STAGE_HEIGHT}
            fill={sceneBackgroundColor}
          />
          {sortedLayers.map((layer) => (
            <CanvasLayerNode
              key={layer.id}
              layer={layer}
              onSelect={() => setSelectedLayer(layer.id)}
              onDragEnd={(x, y) => applyDrag(layer, x, y)}
              onTransformEnd={(node) => applyTransform(layer, node)}
              registerNode={registerNode}
            />
          ))}
          {!isPlaying && !lockedGeometry ? (
            <Transformer
              ref={transformerRef}
              rotateEnabled
              borderStroke="#2563EB"
              anchorStroke="#2563EB"
              anchorFill="#ffffff"
              anchorSize={8}
              boundBoxFunc={(oldBox, newBox) => {
                if (newBox.width < 8 || newBox.height < 8) {
                  return oldBox;
                }
                return newBox;
              }}
            />
          ) : null}
        </Layer>
      </Stage>
        </div>
      </div>
    </div>
  );
}
