import React, { useState, useRef, useCallback, useEffect } from "react";
import { MarkdownToolbar } from "./MarkdownToolbar";
import { FloatingToolbar } from "./FloatingToolbar";
import { NotePreview } from "./NotePreview";
import { ImageUpload } from "./ImageUpload";
import { FileUpload } from "./FileUpload";
import { useAppSelector } from "../../store/hooks";
import { useNotification } from "../../hooks/useNotification";
import { offlineNotesApi } from "../../api/offlineNotesApi";
import { aiApi } from "../../api/aiApi";
import { Icon } from "@iconify/react";

interface NoteEditorProps {
  onSave: () => void;
}

export const NoteEditor: React.FC<NoteEditorProps> = ({ onSave }) => {
  const [content, setContent] = useState("");
  const [images, setImages] = useState<File[]>([]);
  const [files, setFiles] = useState<File[]>([]);
  const [isAiLoading, setIsAiLoading] = useState(false);
  const [showFloatingToolbar, setShowFloatingToolbar] = useState(false);
  const [toolbarPosition, setToolbarPosition] = useState({ top: 0, left: 0 });
  const [hasSelection, setHasSelection] = useState(false);
  const [activeFormats, setActiveFormats] = useState({
    bold: false,
    italic: false,
    strikethrough: false,
  });
  const textareaRef = useRef<HTMLTextAreaElement>(null);
  const isPreviewMode = useAppSelector((state) => state.ui.isPreviewMode);
  const { showNotification } = useNotification();
  const aiEnabled = useAppSelector((state) => state.profile.aiEnabled);
  const user = useAppSelector((state) => state.profile.user);

  // Проверяем, включена ли плавающая панель
  const floatingToolbarEnabled =
    user?.floating_toolbar_enabled !== undefined
      ? user.floating_toolbar_enabled === 1
      : true;

  const handleSave = async () => {
    if (!content.trim()) {
      showNotification("Введите текст заметки", "warning");
      return;
    }

    try {
      const now = new Date();
      const date = now.toLocaleDateString("ru-RU");
      const time = now.toLocaleTimeString("ru-RU", {
        hour: "2-digit",
        minute: "2-digit",
      });

      const note = await offlineNotesApi.create({ content, date, time });

      // Загружаем изображения
      if (images.length > 0) {
        await offlineNotesApi.uploadImages(note.id, images);
      }

      // Загружаем файлы
      if (files.length > 0) {
        await offlineNotesApi.uploadFiles(note.id, files);
      }

      showNotification("Заметка сохранена!", "success");
      setContent("");
      setImages([]);
      setFiles([]);
      onSave();
    } catch (error) {
      console.error("Ошибка сохранения заметки:", error);
      showNotification("Ошибка сохранения заметки", "error");
    }
  };

  const handleAiImprove = async () => {
    if (!content.trim()) {
      showNotification("Введите текст для улучшения", "warning");
      return;
    }

    setIsAiLoading(true);
    try {
      const improvedText = await aiApi.improveText(content);
      setContent(improvedText);
      showNotification("Текст улучшен!", "success");
    } catch (error) {
      console.error("Ошибка улучшения текста:", error);
      showNotification("Ошибка улучшения текста", "error");
    } finally {
      setIsAiLoading(false);
    }
  };

  // Функция для определения активных форматов в выделенном тексте
  const getActiveFormats = useCallback(() => {
    const textarea = textareaRef.current;
    if (!textarea) {
      return { bold: false, italic: false, strikethrough: false };
    }

    const start = textarea.selectionStart;
    const end = textarea.selectionEnd;

    // Если нет выделения, возвращаем все false
    if (start === end) {
      return { bold: false, italic: false, strikethrough: false };
    }

    const selectedText = content.substring(start, end);

    // Инициализируем форматы
    const formats = {
      bold: false,
      italic: false,
      strikethrough: false,
    };

    // Расширяем область проверки для захвата всех возможных тегов
    const checkRange = 10; // Проверяем до 10 символов перед и после
    const checkStart = Math.max(0, start - checkRange);
    const checkEnd = Math.min(content.length, end + checkRange);
    const contextText = content.substring(checkStart, checkEnd);
    const selectionInContext = start - checkStart;

    // Текст вокруг выделения
    const beforeContext = contextText.substring(0, selectionInContext);
    const afterContext = contextText.substring(
      selectionInContext + selectedText.length
    );

    // Функция для подсчета символов в конце строки
    const countTrailingChars = (text: string, char: string) => {
      let count = 0;
      for (let i = text.length - 1; i >= 0; i--) {
        if (text[i] === char) count++;
        else break;
      }
      return count;
    };

    // Функция для подсчета символов в начале строки
    const countLeadingChars = (text: string, char: string) => {
      let count = 0;
      for (let i = 0; i < text.length; i++) {
        if (text[i] === char) count++;
        else break;
      }
      return count;
    };

    // Проверяем зачеркнутый (~~) - проверяем первым, так как он не пересекается с другими
    const strikethroughBefore = beforeContext.slice(-2);
    const strikethroughAfter = afterContext.slice(0, 2);
    const hasStrikethroughAround =
      strikethroughBefore === "~~" && strikethroughAfter === "~~";
    const hasStrikethroughInside =
      selectedText.startsWith("~~") &&
      selectedText.endsWith("~~") &&
      selectedText.length >= 4;

    if (hasStrikethroughAround || hasStrikethroughInside) {
      formats.strikethrough = true;
    }

    // Проверяем звездочки для жирного и курсива
    // Подсчитываем количество звездочек в конце контекста перед выделением
    const trailingStars = countTrailingChars(beforeContext, "*");
    const leadingStars = countLeadingChars(afterContext, "*");
    const leadingStarsInSelection = countLeadingChars(selectedText, "*");
    const trailingStarsInSelection = countTrailingChars(selectedText, "*");

    // Проверяем жирный (**)
    // Жирный требует минимум 2 звездочки с каждой стороны
    const hasBoldStarsBefore = trailingStars >= 2;
    const hasBoldStarsAfter = leadingStars >= 2;
    const hasBoldStarsInSelection =
      leadingStarsInSelection >= 2 && trailingStarsInSelection >= 2;

    // Проверяем, что это действительно жирный
    if (hasBoldStarsBefore && hasBoldStarsAfter) {
      formats.bold = true;
    } else if (hasBoldStarsInSelection && selectedText.length >= 4) {
      formats.bold = true;
    }

    // Проверяем курсив (*)
    // Если есть 3+ звездочки с каждой стороны, это комбинация жирного и курсива
    // Если есть 1 звездочка с каждой стороны (и не 2), это курсив
    // Если есть 3+ звездочки, это жирный + курсив
    const exactItalicBefore =
      trailingStars === 1 || (trailingStars >= 3 && trailingStars % 2 === 1);
    const exactItalicAfter =
      leadingStars === 1 || (leadingStars >= 3 && leadingStars % 2 === 1);
    const exactItalicInSelection =
      (leadingStarsInSelection === 1 && trailingStarsInSelection === 1) ||
      (leadingStarsInSelection >= 3 &&
        trailingStarsInSelection >= 3 &&
        leadingStarsInSelection % 2 === 1 &&
        trailingStarsInSelection % 2 === 1);

    // Проверяем также внутри выделения
    if (exactItalicBefore && exactItalicAfter && !formats.bold) {
      // Если перед и после по 1 звездочке, это курсив
      formats.italic = true;
    } else if (trailingStars >= 3 && leadingStars >= 3) {
      // Если по 3+ звездочки, это комбинация жирного и курсива
      formats.italic = true;
      formats.bold = true;
    } else if (exactItalicInSelection && selectedText.length >= 2) {
      formats.italic = true;
    } else if (
      leadingStarsInSelection === 1 &&
      trailingStarsInSelection === 1 &&
      selectedText.length >= 2 &&
      !selectedText.startsWith("**") &&
      !selectedText.endsWith("**")
    ) {
      formats.italic = true;
    }

    // Если определен жирный, но не определен курсив, и есть 3+ звездочки, значит курсив тоже есть
    if (
      formats.bold &&
      (trailingStars >= 3 ||
        leadingStars >= 3 ||
        leadingStarsInSelection >= 3 ||
        trailingStarsInSelection >= 3)
    ) {
      formats.italic = true;
    }

    return formats;
  }, [content]);

  const insertMarkdown = useCallback(
    (before: string, after: string = "") => {
      const textarea = textareaRef.current;
      if (!textarea) return;

      const start = textarea.selectionStart;
      const end = textarea.selectionEnd;
      const selectedText = content.substring(start, end);

      const tagLength = before.length;

      // Проверяем область вокруг выделения (расширяем для проверки тегов)
      const checkStart = Math.max(0, start - tagLength);
      const checkEnd = Math.min(content.length, end + tagLength);
      const contextText = content.substring(checkStart, checkEnd);
      const selectionInContext = start - checkStart;

      // Текст перед и после выделения в контексте
      const beforeContext = contextText.substring(0, selectionInContext);
      const afterContext = contextText.substring(
        selectionInContext + selectedText.length
      );

      // Проверяем точное совпадение тегов
      const hasTagsBefore = beforeContext.endsWith(before);
      const hasTagsAfter = afterContext.startsWith(after);

      // Проверяем, есть ли теги внутри выделенного текста
      const startsWithTag = selectedText.startsWith(before);
      const endsWithTag = selectedText.endsWith(after);

      // Определяем, нужно ли удалять теги
      let shouldRemoveTags = false;

      if (before === "*" && after === "*") {
        // Для курсива нужно убедиться, что это не часть ** (жирного)
        const beforeBeforeChar = start > 1 ? content[start - 2] : "";
        const afterAfterChar = end + 1 < content.length ? content[end + 1] : "";

        // Проверяем, что перед * не стоит еще один *, и после * не стоит еще один *
        const isItalicBefore = hasTagsBefore && beforeBeforeChar !== "*";
        const isItalicAfter = hasTagsAfter && afterAfterChar !== "*";

        // Проверяем внутри выделения
        const hasItalicInside =
          startsWithTag &&
          endsWithTag &&
          selectedText.length >= 2 &&
          !selectedText.startsWith("**") &&
          !selectedText.endsWith("**");

        shouldRemoveTags = (isItalicBefore && isItalicAfter) || hasItalicInside;
      } else if (before === "**" && after === "**") {
        // Для жирного проверяем точное совпадение **
        shouldRemoveTags =
          (hasTagsBefore && hasTagsAfter) ||
          (startsWithTag && endsWithTag && selectedText.length >= 4);
      } else if (before === "~~" && after === "~~") {
        // Для зачеркнутого проверяем точное совпадение ~~
        shouldRemoveTags =
          (hasTagsBefore && hasTagsAfter) ||
          (startsWithTag && endsWithTag && selectedText.length >= 4);
      } else {
        // Для других тегов (например, ||)
        shouldRemoveTags =
          (hasTagsBefore && hasTagsAfter) ||
          (startsWithTag &&
            endsWithTag &&
            selectedText.length >= tagLength * 2);
      }

      let newText: string;
      let newStart: number;
      let newEnd: number;

      if (shouldRemoveTags) {
        // Удаляем существующие теги
        if (hasTagsBefore && hasTagsAfter) {
          // Теги находятся вокруг выделения (в контексте)
          newText =
            content.substring(0, start - tagLength) +
            selectedText +
            content.substring(end + tagLength);
          newStart = start - tagLength;
          newEnd = end - tagLength;
        } else {
          // Теги находятся внутри выделенного текста
          const innerText = selectedText.substring(
            tagLength,
            selectedText.length - tagLength
          );
          newText =
            content.substring(0, start) + innerText + content.substring(end);
          newStart = start;
          newEnd = start + innerText.length;
        }
      } else {
        // Проверяем, является ли это форматированием списка или цитаты
        const isListFormatting = /^[-*+]\s|^\d+\.\s|^- \[ \]\s|^>\s/.test(
          before
        );
        const isMultiline = selectedText.includes("\n");

        if (isListFormatting && isMultiline) {
          // Обрабатываем многострочное выделение для списков
          const lines = selectedText.split("\n");
          let processedLines: string[] = [];
          let currentNumber = 1;
          let isFirstNonEmptyLine = true;

          for (let i = 0; i < lines.length; i++) {
            const line = lines[i];
            const trimmedLine = line.trim();

            // Пропускаем пустые строки
            if (trimmedLine === "") {
              processedLines.push(line);
              continue;
            }

            // Определяем отступ текущей строки
            const indentMatch = line.match(/^(\s*)/);
            const indent = indentMatch ? indentMatch[1] : "";

            // Обрабатываем в зависимости от типа маркера
            if (before.startsWith("- [ ]")) {
              // Чекбокс
              processedLines.push(indent + "- [ ] " + trimmedLine);
            } else if (before.startsWith("- ")) {
              // Маркированный список
              processedLines.push(indent + "- " + trimmedLine);
            } else if (before.match(/^\d+\.\s/)) {
              // Нумерованный список - извлекаем начальный номер
              const numberMatch = before.match(/^(\d+)\.\s/);
              if (numberMatch && isFirstNonEmptyLine) {
                // Для первой непустой строки используем номер из маркера
                currentNumber = parseInt(numberMatch[1]);
                isFirstNonEmptyLine = false;
              } else if (isFirstNonEmptyLine) {
                // Если маркера нет, начинаем с 1
                currentNumber = 1;
                isFirstNonEmptyLine = false;
              }
              processedLines.push(indent + currentNumber + ". " + trimmedLine);
              currentNumber++;
            } else if (before.startsWith("> ")) {
              // Цитата
              processedLines.push(indent + "> " + trimmedLine);
            } else {
              // Для других форматов просто добавляем маркер
              processedLines.push(indent + before + trimmedLine);
            }
          }

          const processedText = processedLines.join("\n");
          newText =
            content.substring(0, start) +
            processedText +
            content.substring(end);
          newStart = start + before.length;
          newEnd = start + processedText.length;
        } else {
          // Добавляем теги обычным способом
          newText =
            content.substring(0, start) +
            before +
            selectedText +
            after +
            content.substring(end);
          newStart = start + before.length;
          newEnd = end + before.length;
        }
      }

      setContent(newText);

      // Восстанавливаем фокус и выделение, затем обновляем активные форматы
      setTimeout(() => {
        textarea.focus();
        textarea.setSelectionRange(newStart, newEnd);
        // Обновляем активные форматы после применения форматирования
        const formats = getActiveFormats();
        setActiveFormats(formats);
      }, 0);
    },
    [content, getActiveFormats]
  );

  const insertColorMarkdown = useCallback(() => {
    const colorDialog = document.createElement("input");
    colorDialog.type = "color";
    colorDialog.style.display = "none";
    document.body.appendChild(colorDialog);

    colorDialog.addEventListener("change", function () {
      const selectedColor = this.value;
      const textarea = textareaRef.current;
      if (!textarea) return;

      const start = textarea.selectionStart;
      const end = textarea.selectionEnd;
      const selected = content.substring(start, end);
      const before = content.substring(0, start);
      const after = content.substring(end);

      let replacement;
      if (selected.trim() === "") {
        replacement = `<span style="color: ${selectedColor}">Текст</span>`;
      } else {
        replacement = `<span style="color: ${selectedColor}">${selected}</span>`;
      }

      const newText = before + replacement + after;
      setContent(newText);

      setTimeout(() => {
        textarea.focus();
        const cursorPosition = start + replacement.length;
        textarea.setSelectionRange(cursorPosition, cursorPosition);
      }, 0);

      document.body.removeChild(this);
    });

    colorDialog.addEventListener("cancel", function () {
      document.body.removeChild(this);
    });

    colorDialog.click();
  }, [content]);

  // Ctrl/Alt + Enter для сохранения и автопродолжение списков
  const handleKeyDown = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {
    if ((e.altKey || e.ctrlKey) && e.key === "Enter") {
      e.preventDefault();
      handleSave();
    } else if (e.key === "Enter") {
      // Автоматическое продолжение списков
      const textarea = e.currentTarget;
      const start = textarea.selectionStart;
      const text = textarea.value;
      const lines = text.split("\n");

      // Определяем текущую строку
      // @ts-expect-error - переменная используется для определения текущей строки
      let _currentLineIndex = 0;
      let currentLineStart = 0;
      let currentLine = "";

      for (let i = 0; i < lines.length; i++) {
        const lineLength = lines[i].length;
        if (currentLineStart + lineLength >= start) {
          _currentLineIndex = i;
          currentLine = lines[i];
          break;
        }
        currentLineStart += lineLength + 1; // +1 для символа новой строки
      }

      // Проверяем, является ли текущая строка списком
      const listPatterns = [
        /^(\s*)- \[ \] /, // Чекбокс (не отмечен): - [ ]
        /^(\s*)- \[x\] /i, // Чекбокс (отмечен): - [x]
        /^(\s*)- /, // Неупорядоченный список: -
        /^(\s*)\* /, // Неупорядоченный список: *
        /^(\s*)\+ /, // Неупорядоченный список: +
        /^(\s*)(\d+)\. /, // Упорядоченный список: 1. 2. 3.
        /^(\s*)(\w+)\. /, // Буквенный список: a. b. c.
        /^(\s*)1\. /, // Нумерованный список (начинается с 1.)
      ];

      let listMatch = null;
      let listType = null;

      for (const pattern of listPatterns) {
        const match = currentLine.match(pattern);
        if (match) {
          listMatch = match;
          if (pattern === listPatterns[0] || pattern === listPatterns[1]) {
            listType = "checkbox";
          } else if (
            pattern === listPatterns[2] ||
            pattern === listPatterns[3] ||
            pattern === listPatterns[4]
          ) {
            listType = "unordered";
          } else if (pattern === listPatterns[7]) {
            // Нумерованный список всегда начинается с 1.
            listType = "numbered";
          } else {
            listType = "ordered";
          }
          break;
        }
      }

      if (listMatch) {
        e.preventDefault();

        const indent = listMatch[1] || ""; // Отступы перед маркером
        const marker = listMatch[0].slice(indent.length); // Маркер списка без отступов

        // Получаем текст после маркера
        const afterMarker = currentLine.slice(listMatch[0].length);

        if (afterMarker.trim() === "") {
          // Если строка пустая после маркера, выходим из списка
          const beforeCursor = text.substring(0, start);
          const afterCursor = text.substring(start);

          // Удаляем маркер и отступы текущей строки
          const newBefore = beforeCursor.replace(
            /\n\s*- \[ \] \s*$|\n\s*- \[x\] \s*$|\n\s*[-*+]\s*$|\n\s*\d+\.\s*$|\n\s*\w+\.\s*$/i,
            "\n"
          );
          const newContent = newBefore + afterCursor;
          setContent(newContent);

          // Устанавливаем курсор после удаленного маркера
          setTimeout(() => {
            const newCursorPos = newBefore.length;
            textarea.setSelectionRange(newCursorPos, newCursorPos);
          }, 0);
        } else {
          // Продолжаем список
          const beforeCursor = text.substring(0, start);
          const afterCursor = text.substring(start);

          let newMarker = "";
          if (listType === "checkbox") {
            // Для чекбоксов всегда создаем новый пустой чекбокс
            newMarker = indent + "- [ ] ";
          } else if (listType === "unordered") {
            newMarker = indent + marker;
          } else if (listType === "ordered") {
            // Для упорядоченных списков увеличиваем номер
            const number = parseInt(listMatch[2]);
            const nextNumber = number + 1;
            const numberStr = listMatch[2].replace(
              /\d+/,
              nextNumber.toString()
            );
            newMarker = indent + numberStr + ". ";
          } else if (listType === "numbered") {
            // Для нумерованного списка всегда начинаем с 1.
            newMarker = indent + "1. ";
          }

          const newContent = beforeCursor + "\n" + newMarker + afterCursor;
          setContent(newContent);

          // Устанавливаем курсор после нового маркера
          setTimeout(() => {
            const newCursorPos = start + 1 + newMarker.length;
            textarea.setSelectionRange(newCursorPos, newCursorPos);
          }, 0);
        }
      }
    }
  };

  // Функция для вычисления позиции курсора в textarea
  const getCursorPosition = useCallback(() => {
    const textarea = textareaRef.current;
    if (!textarea) return null;

    const start = textarea.selectionStart;
    const end = textarea.selectionEnd;
    const hasSelection = start !== end;

    // Получаем размеры textarea
    const rect = textarea.getBoundingClientRect();
    const styles = window.getComputedStyle(textarea);
    const lineHeight = parseInt(styles.lineHeight) || 20;
    const paddingTop = parseInt(styles.paddingTop) || 0;
    const paddingLeft = parseInt(styles.paddingLeft) || 0;
    // @ts-expect-error - переменная может использоваться в будущем
    const _fontSize = parseInt(styles.fontSize) || 14;
    const scrollTop = textarea.scrollTop;

    // Вычисляем координаты начала выделения
    const textBeforeStart = textarea.value.substring(0, start);
    const linesBeforeStart = textBeforeStart.split("\n");
    const startLineNumber = linesBeforeStart.length - 1;
    const startLineText = linesBeforeStart[startLineNumber];

    // Создаем временный элемент для измерения ширины текста
    const measureEl = document.createElement("span");
    measureEl.style.position = "absolute";
    measureEl.style.visibility = "hidden";
    measureEl.style.whiteSpace = "pre";
    measureEl.style.font = styles.font;
    document.body.appendChild(measureEl);

    measureEl.textContent = startLineText;
    const startTextWidth = measureEl.offsetWidth;

    // Вычисляем координаты конца выделения
    const textBeforeEnd = textarea.value.substring(0, end);
    const linesBeforeEnd = textBeforeEnd.split("\n");
    const endLineNumber = linesBeforeEnd.length - 1;
    const endLineText = linesBeforeEnd[endLineNumber];

    measureEl.textContent = endLineText;
    const endTextWidth = measureEl.offsetWidth;

    document.body.removeChild(measureEl);

    // Вычисляем вертикальные координаты
    const startTop =
      rect.top + paddingTop + startLineNumber * lineHeight - scrollTop;
    const endTop =
      rect.top + paddingTop + endLineNumber * lineHeight - scrollTop;

    // Горизонтальные координаты
    const startLeft = rect.left + paddingLeft + startTextWidth;
    const endLeft = rect.left + paddingLeft + endTextWidth;

    // Если есть выделение, используем его границы
    if (hasSelection) {
      // Вычисляем середину выделения по горизонтали
      const left = Math.min(startLeft, endLeft);
      const right = Math.max(startLeft, endLeft);
      const centerLeft = (left + right) / 2;

      // Вертикальная позиция - середина выделения
      const top = (startTop + endTop) / 2;

      return {
        top,
        left: centerLeft,
        hasSelection,
        selectionTop: Math.min(startTop, endTop),
        selectionBottom: Math.max(startTop, endTop) + lineHeight,
        selectionLeft: left,
        selectionRight: right,
      };
    } else {
      // Для курсора без выделения
      const top = startTop;
      const left = startLeft;

      return {
        top,
        left,
        hasSelection,
        selectionTop: top,
        selectionBottom: top + lineHeight,
        selectionLeft: left,
        selectionRight: left,
      };
    }
  }, []);

  // Обработчик выделения текста
  const handleSelection = useCallback(() => {
    if (isPreviewMode || !floatingToolbarEnabled) {
      setShowFloatingToolbar(false);
      return;
    }

    // Проверяем, есть ли текст в редакторе
    const hasText = content.trim().length > 0;

    const position = getCursorPosition();
    if (position && hasText) {
      setToolbarPosition({ top: position.top, left: position.left });
      setHasSelection(position.hasSelection);
      setShowFloatingToolbar(true);
      // Определяем активные форматы только если есть выделение
      if (position.hasSelection) {
        const formats = getActiveFormats();
        setActiveFormats(formats);
      } else {
        setActiveFormats({ bold: false, italic: false, strikethrough: false });
      }
    } else {
      setShowFloatingToolbar(false);
      setHasSelection(false);
      setActiveFormats({ bold: false, italic: false, strikethrough: false });
    }
  }, [
    isPreviewMode,
    content,
    getCursorPosition,
    getActiveFormats,
    floatingToolbarEnabled,
  ]);

  // Отслеживание выделения текста
  useEffect(() => {
    const textarea = textareaRef.current;
    if (!textarea || isPreviewMode) return;

    const handleMouseUp = () => {
      setTimeout(handleSelection, 0);
    };

    const handleMouseMove = (e: MouseEvent) => {
      if (e.buttons === 1) {
        // Если зажата левая кнопка мыши (выделение)
        setTimeout(handleSelection, 0);
      }
    };

    const handleKeyUp = () => {
      setTimeout(handleSelection, 0);
    };

    // Предотвращаем появление контекстного меню браузера при выделении текста
    // Но разрешаем его, если редактор пустой (чтобы можно было вставить текст)
    const handleContextMenu = (e: MouseEvent) => {
      const target = e.target as HTMLElement;
      // Проверяем, что событие происходит в textarea
      if (target === textarea || textarea.contains(target)) {
        const hasText = textarea.value.trim().length > 0;
        const hasSelection = textarea.selectionStart !== textarea.selectionEnd;
        // Блокируем браузерное меню только если есть текст И есть выделение
        if (hasText && hasSelection) {
          e.preventDefault();
          e.stopPropagation();
        }
      }
    };

    textarea.addEventListener("mouseup", handleMouseUp);
    textarea.addEventListener("mousemove", handleMouseMove);
    textarea.addEventListener("keyup", handleKeyUp);
    textarea.addEventListener("contextmenu", handleContextMenu);
    document.addEventListener("selectionchange", handleSelection);
    document.addEventListener("contextmenu", handleContextMenu, true);

    return () => {
      textarea.removeEventListener("mouseup", handleMouseUp);
      textarea.removeEventListener("mousemove", handleMouseMove);
      textarea.removeEventListener("keyup", handleKeyUp);
      textarea.removeEventListener("contextmenu", handleContextMenu);
      document.removeEventListener("selectionchange", handleSelection);
      document.removeEventListener("contextmenu", handleContextMenu, true);
    };
  }, [isPreviewMode, handleSelection]);

  // Скрываем toolbar при клике вне textarea и toolbar
  useEffect(() => {
    const handleClickOutside = (e: MouseEvent) => {
      const textarea = textareaRef.current;
      const target = e.target as Node;

      // Проверяем, не кликнули ли на toolbar или его кнопки
      const floatingToolbar = document.querySelector(".floating-toolbar");
      if (floatingToolbar && floatingToolbar.contains(target)) {
        // Кликнули на toolbar - не скрываем его
        return;
      }

      if (textarea && !textarea.contains(target)) {
        // Кликнули вне textarea и toolbar - скрываем только если нет выделения
        setTimeout(() => {
          if (textarea.selectionStart === textarea.selectionEnd) {
            setShowFloatingToolbar(false);
          }
        }, 0);
      }
    };

    document.addEventListener("mousedown", handleClickOutside);
    return () => {
      document.removeEventListener("mousedown", handleClickOutside);
    };
  }, []);

  // Обновляем позицию toolbar при прокрутке
  useEffect(() => {
    if (!showFloatingToolbar) return;

    const handleScroll = () => {
      const position = getCursorPosition();
      if (position) {
        setToolbarPosition({ top: position.top, left: position.left });
        setHasSelection(position.hasSelection);
        // Обновляем активные форматы при прокрутке только если есть выделение
        if (position.hasSelection) {
          const formats = getActiveFormats();
          setActiveFormats(formats);
        }
      }
    };

    const textarea = textareaRef.current;
    if (textarea) {
      textarea.addEventListener("scroll", handleScroll);
      window.addEventListener("scroll", handleScroll, true);
    }

    return () => {
      if (textarea) {
        textarea.removeEventListener("scroll", handleScroll);
      }
      window.removeEventListener("scroll", handleScroll, true);
    };
  }, [showFloatingToolbar, getCursorPosition, getActiveFormats]);

  // Авторасширение textarea
  React.useEffect(() => {
    const textarea = textareaRef.current;
    if (!textarea) return;

    const autoExpand = () => {
      textarea.style.height = "auto";
      textarea.style.height = textarea.scrollHeight + "px";
    };

    textarea.addEventListener("input", autoExpand);
    autoExpand();

    return () => {
      textarea.removeEventListener("input", autoExpand);
    };
  }, [content]);

  const imageInputRef = useRef<HTMLInputElement>(null);
  const fileInputRef = useRef<HTMLInputElement>(null);

  const handleImageButtonClick = () => {
    imageInputRef.current?.click();
  };

  const handleFileButtonClick = () => {
    fileInputRef.current?.click();
  };

  const handleImageSelect = (e: React.ChangeEvent<HTMLInputElement>) => {
    const files = Array.from(e.target.files || []);
    const newImages = files.filter(
      (file) => file.type.startsWith("image/") && file.size <= 10 * 1024 * 1024
    );

    if (newImages.length + images.length > 10) {
      showNotification("Можно загрузить максимум 10 изображений", "warning");
      return;
    }

    setImages([...images, ...newImages]);
    if (imageInputRef.current) {
      imageInputRef.current.value = "";
    }
  };

  const handleFileSelect = (e: React.ChangeEvent<HTMLInputElement>) => {
    const selectedFiles = Array.from(e.target.files || []);
    const allowedExtensions = /pdf|doc|docx|xls|xlsx|txt|zip|rar|7z/;
    const allowedMimes = [
      "application/pdf",
      "application/msword",
      "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
      "application/vnd.ms-excel",
      "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
      "text/plain",
      "application/zip",
      "application/x-zip-compressed",
      "application/x-rar-compressed",
      "application/x-7z-compressed",
    ];

    const newFiles = selectedFiles.filter(
      (file) =>
        (allowedMimes.includes(file.type) ||
          allowedExtensions.test(
            file.name.split(".").pop()?.toLowerCase() || ""
          )) &&
        file.size <= 50 * 1024 * 1024
    );

    setFiles([...files, ...newFiles]);
    if (fileInputRef.current) {
      fileInputRef.current.value = "";
    }
  };

  return (
    <div className="main">
      <MarkdownToolbar
        onInsert={insertMarkdown}
        onImageClick={handleImageButtonClick}
        onFileClick={handleFileButtonClick}
        onInsertColor={insertColorMarkdown}
      />

      <input
        ref={imageInputRef}
        type="file"
        id="imageInput"
        accept="image/*"
        multiple
        style={{ display: "none" }}
        onChange={handleImageSelect}
      />

      <input
        ref={fileInputRef}
        type="file"
        id="fileInput"
        accept=".pdf,.doc,.docx,.xls,.xlsx,.txt,.zip,.rar,.7z"
        multiple
        style={{ display: "none" }}
        onChange={handleFileSelect}
      />

      {!isPreviewMode && (
        <>
          <textarea
            ref={textareaRef}
            className="textInput"
            id="noteInput"
            placeholder="Ваша заметка..."
            value={content}
            onChange={(e) => setContent(e.target.value)}
            onKeyDown={handleKeyDown}
            onContextMenu={(e) => {
              // Предотвращаем появление контекстного меню браузера при выделении текста
              // Но разрешаем его, если редактор пустой (чтобы можно было вставить текст)
              const textarea = textareaRef.current;
              if (textarea) {
                const hasText = textarea.value.trim().length > 0;
                const hasSelection =
                  textarea.selectionStart !== textarea.selectionEnd;
                // Блокируем браузерное меню только если есть текст И есть выделение
                if (hasText && hasSelection) {
                  e.preventDefault();
                }
              }
            }}
          />
          {floatingToolbarEnabled && (
            <FloatingToolbar
              textareaRef={textareaRef}
              onFormat={insertMarkdown}
              visible={showFloatingToolbar}
              position={toolbarPosition}
              onHide={() => setShowFloatingToolbar(false)}
              onInsertColor={insertColorMarkdown}
              activeFormats={activeFormats}
              hasSelection={hasSelection}
            />
          )}
        </>
      )}

      {isPreviewMode && <NotePreview content={content} />}

      <ImageUpload images={images} onChange={setImages} />
      <FileUpload files={files} onChange={setFiles} />

      <div className="save-button-container">
        <div className="action-buttons">
          {aiEnabled && (
            <button
              className="btnSave btnAI"
              onClick={handleAiImprove}
              disabled={isAiLoading}
              title="Улучшить или создать текст через ИИ"
            >
              <Icon icon="mdi:robot" />
              {isAiLoading ? "Обработка..." : "Помощь ИИ"}
            </button>
          )}
          <button className="btnSave" onClick={handleSave}>
            Сохранить
          </button>
        </div>
        <span className="save-hint">или нажмите Alt + Enter</span>
      </div>
    </div>
  );
};
