import { useEffect, useLayoutEffect, useRef, useMemo, useState } from "react";
import { Text, Group } from "react-konva";
import Konva from "konva";
import type { TextShapeProps } from "./types";
import { getFontFamily } from "@/pages/editor/utils/fontFamily";
import {
  DEFAULT_TEXT_MAX_WIDTH_PX,
  getEffectiveTextWidth,
  measureTextBlock,
  resolveTextMaxWidth,
  usesWrappedLayout,
} from "@/pages/editor/utils/textStyle";

const getFontWeight = (fontWeight?: string): string => {
  if (!fontWeight) return "normal";
  
  // اگر عدد است، مستقیماً برگردان
  const numValue = parseInt(fontWeight);
  if (!isNaN(numValue)) {
    return numValue.toString();
  }
  
  // برای مقادیر string قدیمی
  const weightMap: Record<string, string> = {
    bold: "bold",
    normal: "normal",
    "300": "300",
  };
  return weightMap[fontWeight] || "normal";
};

/** Konva.Text فقط `fontStyle` دارد (نه fontWeight جداگانه)؛ مقدار باید normal|bold|italic باشد. */
const getKonvaFontStyle = (fontWeight?: string): string => {
  const w = getFontWeight(fontWeight);
  if (w === "bold" || w === "bolder") return "bold";
  const n = parseInt(w, 10);
  if (!Number.isNaN(n) && n >= 600) return "bold";
  return "normal";
};

const getColorWithOpacity = (fill?: string, opacity?: number): string => {
  if (!fill) return "#000000";
  if (opacity === undefined || opacity === 100) return fill;

  const hex = fill.replace("#", "");
  const r = parseInt(hex.substring(0, 2), 16);
  const g = parseInt(hex.substring(2, 4), 16);
  const b = parseInt(hex.substring(4, 6), 16);
  const alpha = opacity / 100;

  return `rgba(${r}, ${g}, ${b}, ${alpha})`;
};

const TextShape = ({
  obj,
  onSelect,
  onUpdate,
  draggable,
}: TextShapeProps) => {
  const shapeRef = useRef<Konva.Text>(null);
  const groupRef = useRef<Konva.Group>(null);
  const [isEditing, setIsEditing] = useState(false);
  const [maxTextWidth, setMaxTextWidth] = useState<number>(DEFAULT_TEXT_MAX_WIDTH_PX);
  const fontSize = obj.fontSize || 24;
  const allowWrap = usesWrappedLayout(
    obj.text,
    obj.height,
    fontSize,
    obj.lineHeight ?? 1.2,
  );

  // Transformer is managed in EditorCanvas for multi-select support
  // Set offset for text node
  useEffect(() => {
    if (shapeRef.current) {
      shapeRef.current.offsetX(0);
      shapeRef.current.offsetY(0);
    }
  }, []);

  // هم‌تراز کردن width/height با Konva؛ بعد از لود وب‌فونت باید `_setTextData` دوباره اجرا شود
  // وگرنه Konva هنوز عرض خطوط را با متریک فونت جایگزین نگه می‌دارد و باکس از متن کوچک می‌ماند.
  useLayoutEffect(() => {
    let cancelled = false;

    const syncFromNode = () => {
      if (cancelled) return;
      const textNode = shapeRef.current;
      const groupNode = groupRef.current;
      if (!textNode || !groupNode) return;
      if (groupNode.scaleX() !== 1 || groupNode.scaleY() !== 1) return;
      const stage = textNode.getStage();

      textNode._setTextData();

      // اندازه‌گیری طبیعی متن (بدون width تحمیلی) تا باکس واقعاً دور متن فیت شود.
      const measureNode = textNode.clone({
        width: undefined,
        x: 0,
        y: 0,
      });
      measureNode._setTextData();
      const { width: rw, height: rh } = measureNode.getClientRect({
        skipTransform: true,
      });
      measureNode.destroy();

      const fontSize = obj.fontSize || 24;
      const cssMeasured = measureTextBlock(obj.text || "", {
        fontSize,
        fontFamily: obj.fontFamily,
        fontWeight: obj.fontWeight,
        letterSpacing: obj.letterSpacing ?? 0,
        lineHeight: obj.lineHeight ?? 1.2,
      });
      const konvaWidth = Math.max(1, Math.ceil(rw));
      const resolvedMaxWidth = resolveTextMaxWidth({
        anchorX: obj.x || 0,
        pageWidth: stage?.width(),
        defaultMaxWidth: obj.textMaxWidth ?? DEFAULT_TEXT_MAX_WIDTH_PX,
      });
      if (Math.abs(resolvedMaxWidth - maxTextWidth) > 1) {
        setMaxTextWidth(resolvedMaxWidth);
      }
      const nextWidth = getEffectiveTextWidth(
        konvaWidth,
        obj.text,
        {
          fontSize,
          fontFamily: obj.fontFamily,
          fontWeight: obj.fontWeight,
          letterSpacing: obj.letterSpacing ?? 0,
          lineHeight: obj.lineHeight ?? 1.2,
        },
        !allowWrap,
      ) ?? konvaWidth;
      const clampedWidth = Math.min(nextWidth, resolvedMaxWidth);
      const forcedWrapByWidth = clampedWidth < nextWidth - 1;
      let measuredHeight = rh;
      if (forcedWrapByWidth) {
        const wrappedMeasureNode = textNode.clone({
          width: clampedWidth,
          wrap: "word",
          x: 0,
          y: 0,
        });
        wrappedMeasureNode._setTextData();
        const { height: wrappedHeight } = wrappedMeasureNode.getClientRect({
          skipTransform: true,
        });
        wrappedMeasureNode.destroy();
        measuredHeight = Math.max(measuredHeight, wrappedHeight);
      }
      const nextHeight = Math.max(
        1,
        Math.ceil(measuredHeight),
        cssMeasured.height,
      );
      const widthChanged = Math.abs((obj.width || 0) - clampedWidth) > 1;
      const heightChanged = Math.abs((obj.height || 0) - nextHeight) > 1;

      if (widthChanged || heightChanged) {
        onUpdate(obj.id, { width: clampedWidth, height: nextHeight });
      }
      textNode.getLayer()?.batchDraw();
    };

    const scheduleSync = () => {
      requestAnimationFrame(() => {
        if (!cancelled) syncFromNode();
      });
    };

    const resolvedFamily = getFontFamily(obj.fontFamily).split(",")[0].trim();
    const fontSize = obj.fontSize || 24;
    const konvaStyle = getKonvaFontStyle(obj.fontWeight);

    const fontsApi = document.fonts;

    const waitFontsThenSync = () => {
      if (!fontsApi || typeof fontsApi.load !== "function") {
        scheduleSync();
        return;
      }

      const specs = [
        `${fontSize}px ${resolvedFamily}`,
        `${konvaStyle} normal ${fontSize}px ${resolvedFamily}`,
        `bold ${fontSize}px ${resolvedFamily}`,
        `300 ${fontSize}px ${resolvedFamily}`,
        `200 ${fontSize}px ${resolvedFamily}`,
      ];

      void Promise.all(
        specs.map((s) => fontsApi.load(s).catch(() => [])),
      ).finally(() => {
        if (!cancelled) scheduleSync();
      });
    };

    scheduleSync();
    waitFontsThenSync();

    const onLoadingDone = () => {
      if (!cancelled) scheduleSync();
    };
    fontsApi?.addEventListener?.("loadingdone", onLoadingDone);

    return () => {
      cancelled = true;
      fontsApi?.removeEventListener?.("loadingdone", onLoadingDone);
    };
  }, [
    obj.id,
    obj.text,
    obj.fontSize,
    obj.fontFamily,
    obj.fontWeight,
    obj.letterSpacing,
    obj.lineHeight,
    obj.width,
    obj.height,
    obj.x,
    obj.textMaxWidth,
    allowWrap,
    maxTextWidth,
    onUpdate,
  ]);

  const fontFamily = useMemo(() => getFontFamily(obj.fontFamily), [obj.fontFamily]);
  const konvaFontStyle = useMemo(() => getKonvaFontStyle(obj.fontWeight), [obj.fontWeight]);
  const fillColor = useMemo(() => getColorWithOpacity(obj.fill, obj.opacity), [obj.fill, obj.opacity]);
  const textAlign = obj.textAlign ?? "right";
  const wrapByMaxWidth = (obj.width ?? 0) >= maxTextWidth - 1;
  const shouldWrap = allowWrap || wrapByMaxWidth;

  const handleDblClick = () => {
    if (!shapeRef.current || !groupRef.current) return;

    setIsEditing(true);

    const textNode = shapeRef.current;
    const groupNode = groupRef.current;
    const stage = textNode.getStage();
    if (!stage) return;

    // مخفی کردن متن اصلی در حین ویرایش
    textNode.hide();
    textNode.getLayer()?.batchDraw();

    // گرفتن موقعیت مطلق text node روی صفحه با استفاده از getClientRect
    // که همه transformها (scale, rotation, position) را در نظر می‌گیرد
    const stageBox = stage.container().getBoundingClientRect();
    const box = textNode.getClientRect();
    
    // محاسبه موقعیت textarea روی صفحه
    const areaPosition = {
      x: stageBox.left + box.x,
      y: stageBox.top + box.y,
    };

    // ایجاد textarea
    const textarea = document.createElement("textarea");
    document.body.appendChild(textarea);

    // تنظیم مقدار
    textarea.value = textNode.text();

    // استایل‌دهی دقیق
    const stageScale = stage.scaleX();
    Object.assign(textarea.style, {
      position: "absolute",
      top: `${areaPosition.y}px`,
      left: `${areaPosition.x}px`,
      width: `${Math.min(box.width, maxTextWidth * stageScale)}px`,
      maxWidth: `${maxTextWidth * stageScale}px`,
      minHeight: `${box.height}px`,
      fontSize: `${(obj.fontSize || 24) * stageScale}px`,
      fontFamily: fontFamily,
      fontWeight: getFontWeight(obj.fontWeight),
      color: obj.fill || "#000000",
      letterSpacing: `${(obj.letterSpacing || 0) * stageScale}px`,
      lineHeight: textNode.lineHeight().toString(),
      textAlign,
      direction: "rtl",
      padding: "0",
      margin: "0",
      border: "none",
      outline: "2px solid #3b82f6",
      background: "transparent",
      resize: "none",
      overflow: "auto",
      zIndex: "10000",
      transformOrigin: "left top",
      whiteSpace: "pre-wrap",
      wordWrap: "break-word",
    });

    // اعمال rotation
    const rotation = groupNode.rotation();
    if (rotation) {
      textarea.style.transform = `rotate(${rotation}deg)`;
      // تنظیم transform origin برای rotation صحیح
      textarea.style.transformOrigin = "left top";
    }

    // Focus و Select
    textarea.focus();
    
    // Select all text after a small delay
    setTimeout(() => {
      textarea.select();
    }, 0);

    const removeTextarea = () => {
      if (textarea.parentNode) {
        textarea.parentNode.removeChild(textarea);
      }
      window.removeEventListener("click", handleOutsideClick);
      setIsEditing(false);
      textNode.show();
      textNode.getLayer()?.batchDraw();
    };

    const saveText = () => {
      const newText = textarea.value;
      if (newText !== textNode.text()) {
        onUpdate(obj.id, { text: newText });
      }
      removeTextarea();
    };

    const handleOutsideClick = (e: MouseEvent) => {
      if (e.target !== textarea) {
        saveText();
      }
    };

    textarea.addEventListener("keydown", (e) => {
      // فقط با Escape خارج بشیم بدون ذخیره
      if (e.key === "Escape") {
        removeTextarea();
        e.preventDefault();
      }
      // Enter عادی برای خط جدید
      // Ctrl+Enter یا Cmd+Enter برای ذخیره و خروج
      else if (e.key === "Enter" && (e.ctrlKey || e.metaKey)) {
        saveText();
        e.preventDefault();
      }
    });

    textarea.addEventListener("blur", () => {
      saveText();
    });

    setTimeout(() => {
      window.addEventListener("click", handleOutsideClick);
    }, 10);
  };

  return (
    <Group
      ref={groupRef}
      id={obj.id}
      name="text-object"
      x={obj.x}
      y={obj.y}
      rotation={obj.rotation || 0}
      draggable={draggable && !isEditing}
      onClick={(e) => {
        if (groupRef.current) {
          onSelect(obj.id, groupRef.current, e);
        }
      }}
      onDblClick={handleDblClick}
      onDragEnd={(e) => {
        const node = e.target;
        onUpdate(obj.id, {
          x: node.x(),
          y: node.y(),
        });
      }}
    >
      <Text
        ref={shapeRef}
        x={-(obj.width || 0)}
        y={0}
        text={obj.text || ""}
        fontSize={obj.fontSize || 24}
        fill={fillColor}
        fontFamily={fontFamily}
        fontStyle={konvaFontStyle}
        letterSpacing={obj.letterSpacing ?? 0}
        lineHeight={obj.lineHeight ?? 1.2}
        width={shouldWrap ? obj.width || maxTextWidth : undefined}
        align={textAlign}
        wrap={shouldWrap ? "word" : "none"}
      />
    </Group>
  );
};

export default TextShape;

