import React, { useState, useCallback, useMemo, useRef, useEffect } from 'react';
import { createEditor, Descendant, Element as SlateElement, Transforms, Editor, BaseEditor, Node } from 'slate';
import { Slate, Editable, withReact, RenderElementProps, RenderLeafProps, ReactEditor } from 'slate-react';
import { withHistory, HistoryEditor } from 'slate-history';
import { Button } from '@/components/ui/button';
import { Bold, Italic, Underline, List, ListOrdered, AlignLeft, AlignCenter, AlignRight, Indent, Outdent, Palette } from 'lucide-react';
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover';

type RichTextEditorProps = {
  initialValue?: string;
  onChange: (value: string) => void;
  placeholder?: string;
  readOnly?: boolean;
  disabled?: boolean;
  minHeight?: string;
  className?: string;
};

// Define the type for text nodes
type CustomText = {
  text: string;
  bold?: boolean;
  italic?: boolean;
  underline?: boolean;
  color?: string;
};

// Define types for elements
type ParagraphElement = {
  type: 'paragraph';
  align?: 'left' | 'center' | 'right';
  indent?: number;
  children: CustomText[];
};

type ListItemElement = {
  type: 'list-item';
  align?: 'left' | 'center' | 'right';
  indent?: number;
  children: CustomText[];
};

type BulletedListElement = {
  type: 'bulleted-list';
  align?: 'left' | 'center' | 'right';
  indent?: number;
  children: ListItemElement[];
};

type NumberedListElement = {
  type: 'numbered-list';
  align?: 'left' | 'center' | 'right';
  indent?: number;
  children: ListItemElement[];
};

type CustomElement = ParagraphElement | ListItemElement | BulletedListElement | NumberedListElement;

// Fix type declarations for Slate
type CustomEditor = BaseEditor & ReactEditor & HistoryEditor;

declare module 'slate' {
  interface CustomTypes {
    Editor: BaseEditor & ReactEditor & HistoryEditor;
    Element: CustomElement;
    Text: CustomText;
  }
}

// Initial value for the editor
const initialValue: Descendant[] = [
  {
    type: 'paragraph',
    children: [{ text: '' }],
  },
];

// Helper to serialize editor content to HTML
const serializeToHtml = (nodes: Descendant[]): string => {
  return nodes
    .map(node => {
      if ('type' in node) {
        switch (node.type) {
          case 'paragraph':
            const textContent = node.children.map(child => {
              let text = child.text;
              if (child.bold) text = `<strong>${text}</strong>`;
              if (child.italic) text = `<em>${text}</em>`;
              if (child.underline) text = `<u>${text}</u>`;
              if (child.color) text = `<span style="color:${child.color}">${text}</span>`;
              return text;
            }).join('');
            const align = node.align ? ` style="text-align: ${node.align}` : '';
            const indent = node.indent ? `${align ? ';' : ' style="'}padding-left: ${node.indent * 24}px` : '';
            const style = (align || indent) ? `${align}${indent}"` : '';
            return `<p${style}>${textContent}</p>`;
          case 'bulleted-list':
            const ulAlign = node.align ? ` style="text-align: ${node.align}"` : '';
            const ulIndent = node.indent ? `${ulAlign ? ';' : ' style="'}padding-left: ${node.indent * 24}px"` : '';
            const ulStyle = (ulAlign || ulIndent) ? `${ulAlign}${ulIndent}"` : '';
            return `<ul${ulStyle}>${node.children.map(item => 
              `<li>${item.children.map(child => {
                let text = child.text;
                if (child.bold) text = `<strong>${text}</strong>`;
                if (child.italic) text = `<em>${text}</em>`;
                if (child.underline) text = `<u>${text}</u>`;
                if (child.color) text = `<span style="color:${child.color}">${text}</span>`;
                return text;
              }).join('')}</li>`
            ).join('')}</ul>`;
          case 'numbered-list':
            const olAlign = node.align ? ` style="text-align: ${node.align}"` : '';
            const olIndent = node.indent ? `${olAlign ? ';' : ' style="'}padding-left: ${node.indent * 24}px"` : '';
            const olStyle = (olAlign || olIndent) ? `${olAlign}${olIndent}"` : '';
            return `<ol${olStyle}>${node.children.map(item => 
              `<li>${item.children.map(child => {
                let text = child.text;
                if (child.bold) text = `<strong>${text}</strong>`;
                if (child.italic) text = `<em>${text}</em>`;
                if (child.underline) text = `<u>${text}</u>`;
                if (child.color) text = `<span style="color:${child.color}">${text}</span>`;
                return text;
              }).join('')}</li>`
            ).join('')}</ol>`;
          case 'list-item':
            const liAlign = node.align ? ` style="text-align: ${node.align}"` : '';
            const liIndent = node.indent ? `${liAlign ? ';' : ' style="'}padding-left: ${node.indent * 24}px"` : '';
            const liStyle = (liAlign || liIndent) ? `${liAlign}${liIndent}"` : '';
            return `<li${liStyle}>${node.children.map(child => {
              let text = child.text;
              if (child.bold) text = `<strong>${text}</strong>`;
              if (child.italic) text = `<em>${text}</em>`;
              if (child.underline) text = `<u>${text}</u>`;
              if (child.color) text = `<span style="color:${child.color}">${text}</span>`;
              return text;
            }).join('')}</li>`;
          default:
            return '';
        }
      } else {
        // It's a text node
        let text = node.text;
        if (node.bold) text = `<strong>${text}</strong>`;
        if (node.italic) text = `<em>${text}</em>`;
        if (node.underline) text = `<u>${text}</u>`;
        if (node.color) text = `<span style="color:${node.color}">${text}</span>`;
        return text;
      }
    })
    .join('');
};

// Improved HTML parser to handle more complex HTML content
const parseFromHtml = (html: string): Descendant[] => {
  if (!html) return initialValue;
  
  try {
    // Create a temporary DOM element to parse the HTML
    const parser = new DOMParser();
    const doc = parser.parseFromString(html, 'text/html');
    
    const result: Descendant[] = [];
    
    // Check if we have a plain text with bullet characters (•)
    if (doc.body.textContent?.includes('•')) {
      const textContent = doc.body.textContent;
      const lines = textContent.split('\n').filter(line => line.trim().length > 0);
      
      // If we have bullet characters in text, convert to proper list format
      if (lines.some(line => line.trim().startsWith('•'))) {
        const listItems: ListItemElement[] = [];
        let currentParagraph: ParagraphElement | null = null;
        
        lines.forEach(line => {
          const trimmedLine = line.trim();
          if (trimmedLine.startsWith('•')) {
            // If we had a paragraph in progress, add it to result
            if (currentParagraph) {
              result.push(currentParagraph);
              currentParagraph = null;
            }
            
            // Add as a list item
            listItems.push({
              type: 'list-item',
              children: [{ text: trimmedLine.substring(1).trim() }]
            });
          } else {
            // If we had list items in progress, add them as a bulleted list
            if (listItems.length > 0) {
              result.push({
                type: 'bulleted-list',
                children: listItems
              });
              // Reset list items
              listItems.length = 0;
            }
            
            // Add as a paragraph
            if (!currentParagraph) {
              currentParagraph = {
                type: 'paragraph',
                children: [{ text: trimmedLine }]
              };
            } else {
              // Append to existing paragraph with a space
              currentParagraph.children[0].text += ' ' + trimmedLine;
            }
          }
        });
        
        // Add any remaining list items or paragraphs
        if (listItems.length > 0) {
          result.push({
            type: 'bulleted-list',
            children: listItems
          });
        }
        
        if (currentParagraph) {
          result.push(currentParagraph);
        }
        
        return result.length > 0 ? result : initialValue;
      }
    }
    
    // Process each top-level element normally
    Array.from(doc.body.childNodes).forEach(node => {
      if (node.nodeType === 1) { // ELEMENT_NODE is 1
        const element = node as Element;
        result.push(...parseElement(element));
      } else if (node.nodeType === 3 && node.textContent?.trim()) { // TEXT_NODE is 3
        // Handle direct text nodes
        result.push({ 
          type: 'paragraph',
          children: [{ text: node.textContent || '' }]
        });
      }
    });
    
    return result.length > 0 ? result : initialValue;
  } catch (e) {
    console.error('Error parsing HTML:', e);
    return initialValue;
  }
};

// Helper function to parse HTML elements recursively
const parseElement = (element: Element): Descendant[] => {
  const result: Descendant[] = [];
  
  // Handle different element types
  switch (element.tagName.toLowerCase()) {
    case 'p':
      // Handle paragraphs with formatting
      const paragraph: ParagraphElement = {
        type: 'paragraph',
        children: parseTextWithFormatting(element),
      };
      
      // Extract alignment and indentation if available
      const style = element.getAttribute('style');
      if (style) {
        if (style.includes('text-align: center')) {
          paragraph.align = 'center';
        } else if (style.includes('text-align: right')) {
          paragraph.align = 'right';
        } else if (style.includes('text-align: left')) {
          paragraph.align = 'left';
        }
        
        // Extract indentation
        const indentMatch = style.match(/padding-left:\s*(\d+)px/i);
        if (indentMatch && indentMatch[1]) {
          const indentPx = parseInt(indentMatch[1], 10);
          paragraph.indent = Math.round(indentPx / 24); // Convert px to our indent level
        }
      }
      
      result.push(paragraph);
      break;
      
    case 'div':
      // Special case for divs that might be containing bulleted lists with specific styling
      if (element.innerHTML.includes('•') || 
          element.innerHTML.includes('&#8226;') ||
          element.innerHTML.includes('&bull;')) {
        // Try to extract bullet points
        const children = Array.from(element.childNodes);
        const listItems: ListItemElement[] = [];
        
        children.forEach(child => {
          if (child.nodeType === 3) { // TEXT_NODE
            const text = child.textContent || '';
            if (text.trim().startsWith('•') || text.trim().startsWith('●')) {
              listItems.push({
                type: 'list-item',
                children: [{ text: text.replace(/^[•●]\s*/, '') }]
              });
            }
          } else if (child.nodeType === 1) { // ELEMENT_NODE
            const childElement = child as Element;
            const text = childElement.textContent || '';
            if (text.trim().startsWith('•') || text.trim().startsWith('●')) {
              listItems.push({
                type: 'list-item',
                children: parseTextWithFormatting(childElement).map(node => {
                  // Remove bullet character
                  if (typeof node.text === 'string') {
                    return { ...node, text: node.text.replace(/^[•●]\s*/, '') };
                  }
                  return node;
                })
              });
            }
          }
        });
        
        if (listItems.length > 0) {
          result.push({
            type: 'bulleted-list',
            children: listItems
          });
          break;
        }
      }
      
      // For regular divs, process children and create a paragraph
      const children = parseTextWithFormatting(element);
      const divStyle = element.getAttribute('style');
      const divParagraph: ParagraphElement = {
        type: 'paragraph',
        children,
      };
      
      if (divStyle) {
        if (divStyle.includes('text-align: center')) {
          divParagraph.align = 'center';
        } else if (divStyle.includes('text-align: right')) {
          divParagraph.align = 'right';
        } else if (divStyle.includes('text-align: left')) {
          divParagraph.align = 'left';
        }
        
        // Extract indentation
        const divIndentMatch = divStyle.match(/padding-left:\s*(\d+)px/i);
        if (divIndentMatch && divIndentMatch[1]) {
          const indentPx = parseInt(divIndentMatch[1], 10);
          divParagraph.indent = Math.round(indentPx / 24);
        }
      }
      
      result.push(divParagraph);
      break;
      
    case 'h1':
    case 'h2':
    case 'h3':
    case 'h4':
    case 'h5':
    case 'h6':
      // For headings, create a paragraph with formatting
      const headingStyle = element.getAttribute('style');
      const headingParagraph: ParagraphElement = {
        type: 'paragraph',
        children: parseTextWithFormatting(element),
      };
      
      if (headingStyle) {
        if (headingStyle.includes('text-align: center')) {
          headingParagraph.align = 'center';
        } else if (headingStyle.includes('text-align: right')) {
          headingParagraph.align = 'right';
        } else if (headingStyle.includes('text-align: left')) {
          headingParagraph.align = 'left';
        }
        
        // Extract indentation
        const headingIndentMatch = headingStyle.match(/padding-left:\s*(\d+)px/i);
        if (headingIndentMatch && headingIndentMatch[1]) {
          const indentPx = parseInt(headingIndentMatch[1], 10);
          headingParagraph.indent = Math.round(indentPx / 24);
        }
      }
      
      result.push(headingParagraph);
      break;
      
    case 'ul':
      // Handle unordered lists - first check if it's empty
      const listItems = Array.from(element.querySelectorAll('li'));
      if (listItems.length > 0) {
        const ulStyle = element.getAttribute('style');
        const list: BulletedListElement = {
          type: 'bulleted-list',
          children: listItems.map(li => {
            const liStyle = li.getAttribute('style');
            const listItem: ListItemElement = {
              type: 'list-item',
              children: parseTextWithFormatting(li),
            };
            
            if (liStyle) {
              if (liStyle.includes('text-align: center')) {
                listItem.align = 'center';
              } else if (liStyle.includes('text-align: right')) {
                listItem.align = 'right';
              } else if (liStyle.includes('text-align: left')) {
                listItem.align = 'left';
              }
              
              // Extract indentation for list item
              const liIndentMatch = liStyle.match(/padding-left:\s*(\d+)px/i);
              if (liIndentMatch && liIndentMatch[1]) {
                const indentPx = parseInt(liIndentMatch[1], 10);
                listItem.indent = Math.round(indentPx / 24);
              }
            }
            
            return listItem;
          }),
        };
        
        if (ulStyle) {
          if (ulStyle.includes('text-align: center')) {
            list.align = 'center';
          } else if (ulStyle.includes('text-align: right')) {
            list.align = 'right';
          } else if (ulStyle.includes('text-align: left')) {
            list.align = 'left';
          }
          
          // Extract indentation for the list
          const ulIndentMatch = ulStyle.match(/padding-left:\s*(\d+)px/i);
          if (ulIndentMatch && ulIndentMatch[1]) {
            const indentPx = parseInt(ulIndentMatch[1], 10);
            list.indent = Math.round(indentPx / 24);
          }
        }
        
        result.push(list);
      }
      break;
      
    case 'ol':
      // Handle ordered lists - first check if it's empty
      const orderedListItems = Array.from(element.querySelectorAll('li'));
      if (orderedListItems.length > 0) {
        const olStyle = element.getAttribute('style');
        const orderedList: NumberedListElement = {
          type: 'numbered-list',
          children: orderedListItems.map(li => {
            const liStyle = li.getAttribute('style');
            const listItem: ListItemElement = {
              type: 'list-item',
              children: parseTextWithFormatting(li),
            };
            
            if (liStyle) {
              if (liStyle.includes('text-align: center')) {
                listItem.align = 'center';
              } else if (liStyle.includes('text-align: right')) {
                listItem.align = 'right';
              } else if (liStyle.includes('text-align: left')) {
                listItem.align = 'left';
              }
              
              // Extract indentation for list item
              const liIndentMatch = liStyle.match(/padding-left:\s*(\d+)px/i);
              if (liIndentMatch && liIndentMatch[1]) {
                const indentPx = parseInt(liIndentMatch[1], 10);
                listItem.indent = Math.round(indentPx / 24);
              }
            }
            
            return listItem;
          }),
        };
        
        if (olStyle) {
          if (olStyle.includes('text-align: center')) {
            orderedList.align = 'center';
          } else if (olStyle.includes('text-align: right')) {
            orderedList.align = 'right';
          } else if (olStyle.includes('text-align: left')) {
            orderedList.align = 'left';
          }
          
          // Extract indentation for the list
          const olIndentMatch = olStyle.match(/padding-left:\s*(\d+)px/i);
          if (olIndentMatch && olIndentMatch[1]) {
            const indentPx = parseInt(olIndentMatch[1], 10);
            orderedList.indent = Math.round(indentPx / 24);
          }
        }
        
        result.push(orderedList);
      }
      break;
      
    case 'li':
      // Create standalone list item if not in a list context
      const liItemStyle = element.getAttribute('style');
      const listItem: ListItemElement = {
        type: 'list-item',
        children: parseTextWithFormatting(element),
      };
      
      if (liItemStyle) {
        if (liItemStyle.includes('text-align: center')) {
          listItem.align = 'center';
        } else if (liItemStyle.includes('text-align: right')) {
          listItem.align = 'right';
        } else if (liItemStyle.includes('text-align: left')) {
          listItem.align = 'left';
        }
        
        // Extract indentation
        const liItemIndentMatch = liItemStyle.match(/padding-left:\s*(\d+)px/i);
        if (liItemIndentMatch && liItemIndentMatch[1]) {
          const indentPx = parseInt(liItemIndentMatch[1], 10);
          listItem.indent = Math.round(indentPx / 24);
        }
      }
      
      result.push(listItem);
      break;
      
    case 'br':
      // Handle line breaks by creating a new paragraph
      result.push({
        type: 'paragraph',
        children: [{ text: '' }],
      });
      break;
      
    default:
      // For other elements, recursively process children
      let hasAddedContent = false;
      
      Array.from(element.childNodes).forEach(childNode => {
        if (childNode.nodeType === 1) { // ELEMENT_NODE
          const childResults = parseElement(childNode as Element);
          if (childResults.length > 0) {
            result.push(...childResults);
            hasAddedContent = true;
          }
        } else if (childNode.nodeType === 3 && childNode.textContent?.trim()) { // TEXT_NODE is 3
          result.push({
            type: 'paragraph',
            children: [{ text: childNode.textContent || '' }],
          });
          hasAddedContent = true;
        }
      });
      
      // If no content was added but the element has text, add it as a paragraph
      if (!hasAddedContent && element.textContent?.trim()) {
        result.push({
          type: 'paragraph',
          children: [{ text: element.textContent || '' }],
        });
      }
  }
  
  return result;
};

// Parse text with inline formatting
const parseTextWithFormatting = (element: Element): CustomText[] => {
  const result: CustomText[] = [];
  
  // If there's only text content and no children with formatting, return a simple text node
  if (!element.childNodes.length || 
      (element.childNodes.length === 1 && element.childNodes[0].nodeType === 3)) { // TEXT_NODE is 3
    return [{ text: element.textContent || '' }];
  }
  
  // Process each child node to handle formatting
  Array.from(element.childNodes).forEach(node => {
    if (node.nodeType === 3) { // TEXT_NODE
      // Handle text nodes
      if (node.textContent?.trim()) {
        result.push({ text: node.textContent || '' });
      }
    } else if (node.nodeType === 1) { // ELEMENT_NODE
      const childElement = node as Element;
      const tagName = childElement.tagName.toLowerCase();
      
      // Handle formatting elements
      switch (tagName) {
        case 'strong':
        case 'b':
          result.push({ text: childElement.textContent || '', bold: true });
          break;
          
        case 'em':
        case 'i':
          result.push({ text: childElement.textContent || '', italic: true });
          break;
          
        case 'u':
          result.push({ text: childElement.textContent || '', underline: true });
          break;
          
        case 'span':
          // Process span with potential inline styling
          const spanStyle = childElement.getAttribute('style');
          const text = childElement.textContent || '';
          const formatting: Partial<CustomText> = { text };
          
          if (spanStyle) {
            if (spanStyle.includes('font-weight: bold') || spanStyle.includes('font-weight:bold')) {
              formatting.bold = true;
            }
            if (spanStyle.includes('font-style: italic') || spanStyle.includes('font-style:italic')) {
              formatting.italic = true;
            }
            if (spanStyle.includes('text-decoration: underline') || spanStyle.includes('text-decoration:underline')) {
              formatting.underline = true;
            }
            
            // Extract color if present
            const colorMatch = spanStyle.match(/color:\s*(#[0-9a-f]{3,6}|rgb\([^)]+\)|[a-z]+)/i);
            if (colorMatch && colorMatch[1]) {
              formatting.color = colorMatch[1];
            }
          }
          
          result.push(formatting as CustomText);
          break;
          
        default:
          // Recursively handle other elements
          result.push(...parseTextWithFormatting(childElement));
      }
    }
  });
  
  return result;
};

// Format button component
type FormatButtonProps = {
  format: string;
  icon: React.ReactNode;
  isActive?: boolean;
  onMouseDown: (e: React.MouseEvent) => void;
};

const FormatButton: React.FC<FormatButtonProps> = ({ 
  format, 
  icon, 
  isActive = false, 
  onMouseDown 
}) => {
  return (
    <Button
      type="button"
      variant={isActive ? "default" : "ghost"}
      size="sm"
      onMouseDown={onMouseDown}
      className="h-8 w-8 p-0"
      title={format.charAt(0).toUpperCase() + format.slice(1)}
    >
      {icon}
    </Button>
  );
};

// Custom type for Slate Element props with align support
interface CustomRenderElementProps extends Omit<RenderElementProps, 'element'> {
  element: CustomElement;
}

// Element renderer
const Element = ({ attributes, children, element }: CustomRenderElementProps) => {
  const style: React.CSSProperties = { 
    textAlign: element.align as React.CSSProperties['textAlign'] || undefined
  };
  
  // Apply indentation with more visible styling
  if (element.indent) {
    style.paddingLeft = `${element.indent * 24}px`;
    style.borderLeft = '2px solid #e2e8f0';
    style.marginLeft = '8px';
  }
  
  switch (element.type) {
    case 'bulleted-list':
      return <ul {...attributes} className="list-disc ml-6" style={style}>{children}</ul>;
    case 'numbered-list':
      return <ol {...attributes} className="list-decimal ml-6" style={style}>{children}</ol>;
    case 'list-item':
      return <li {...attributes} style={style}>{children}</li>;
    default:
      return <p {...attributes} style={style}>{children}</p>;
  }
};

// Leaf renderer
const Leaf = ({ attributes, children, leaf }: RenderLeafProps) => {
  let style: React.CSSProperties = {};
  
  // Apply color if specified
  if (leaf.color) {
    style.color = leaf.color;
  }
  
  let textElement = <span {...attributes} style={style}>{children}</span>;
  
  if (leaf.bold) {
    textElement = <strong>{textElement}</strong>;
  }
  
  if (leaf.italic) {
    textElement = <em>{textElement}</em>;
  }
  
  if (leaf.underline) {
    textElement = <u>{textElement}</u>;
  }
  
  return textElement;
};

// Custom editor commands
const CustomEditor = {
  isMarkActive(editor: CustomEditor, format: string) {
    const marks = Editor.marks(editor);
    return marks ? marks[format] === true : false;
  },

  isBlockActive(editor: CustomEditor, format: string, attributeName = 'type') {
    const { selection } = editor;
    if (!selection) return false;

    try {
      const [match] = Array.from(
        Editor.nodes(editor, {
          at: Editor.unhangRange(editor, selection),
          match: n => 
            !Editor.isEditor(n) && 
            SlateElement.isElement(n) && 
            (n as any)[attributeName] === format,
        })
      );
      
      return !!match;
    } catch (error) {
      console.error('Error checking block active state:', error);
      return false;
    }
  },

  toggleMark(editor: CustomEditor, format: string) {
    const isActive = CustomEditor.isMarkActive(editor, format);
    
    if (isActive) {
      Editor.removeMark(editor, format);
    } else {
      Editor.addMark(editor, format, true);
    }
  },

  toggleBlock(editor: CustomEditor, format: string) {
    const isActive = CustomEditor.isBlockActive(editor, format);
    
    Transforms.unwrapNodes(editor, {
      match: n => 
        !Editor.isEditor(n) && 
        SlateElement.isElement(n) && 
        ['bulleted-list', 'numbered-list'].includes((n as any).type),
      split: true,
    });
    
    const newProperties: Partial<CustomElement> = {
      type: isActive ? 'paragraph' : format === 'bulleted-list' || format === 'numbered-list' 
        ? 'list-item' 
        : format as any
    };
    
    Transforms.setNodes(editor, newProperties, {
      match: n => !Editor.isEditor(n) && SlateElement.isElement(n),
    });
    
    if (!isActive && (format === 'bulleted-list' || format === 'numbered-list')) {
      const block = { type: format, children: [] };
      Transforms.wrapNodes(editor, block as any);
    }
  },

  toggleAlign(editor: CustomEditor, alignment: 'left' | 'center' | 'right') {
    // Check if the current alignment is already active
    const isActive = CustomEditor.isBlockActive(editor, alignment, 'align');
    
    // Set or unset the alignment
    const newProperties: Partial<CustomElement> = { 
      align: isActive ? undefined : alignment 
    };
    
    Transforms.setNodes(editor, newProperties, {
      match: n => !Editor.isEditor(n) && SlateElement.isElement(n),
    });
  },

  setColor(editor: CustomEditor, color: string) {
    Editor.addMark(editor, 'color', color);
  },

  increaseIndent(editor: CustomEditor) {
    const { selection } = editor;
    if (!selection) return;

    try {
      const nodeEntries = Editor.nodes(editor, {
        at: selection,
        match: n => !Editor.isEditor(n) && SlateElement.isElement(n),
      });

      for (const [node, path] of nodeEntries) {
        const element = node as CustomElement;
        const currentIndent = element.indent || 0;
        
        if (currentIndent < 5) {
          Transforms.setNodes(
            editor,
            { indent: currentIndent + 1 } as Partial<CustomElement>,
            { at: path }
          );
        }
      }
    } catch (error) {
      console.error('Error increasing indent:', error);
    }
  },

  decreaseIndent(editor: CustomEditor) {
    const { selection } = editor;
    if (!selection) return;

    try {
      const nodeEntries = Editor.nodes(editor, {
        at: selection,
        match: n => !Editor.isEditor(n) && SlateElement.isElement(n),
      });

      for (const [node, path] of nodeEntries) {
        const element = node as CustomElement;
        const currentIndent = element.indent || 0;
        
        if (currentIndent > 0) {
          Transforms.setNodes(
            editor,
            { indent: currentIndent - 1 } as Partial<CustomElement>,
            { at: path }
          );
        }
      }
    } catch (error) {
      console.error('Error decreasing indent:', error);
    }
  }
};

const colorOptions = [
  { color: '#000000', label: 'Black' },
  { color: '#1C7ED6', label: 'Blue' },
  { color: '#2B8A3E', label: 'Green' },
  { color: '#E03131', label: 'Red' },
  { color: '#F59F00', label: 'Orange' },
  { color: '#7048E8', label: 'Purple' },
  { color: '#868E96', label: 'Gray' },
];

// Custom color picker with custom popover
const ColorButton: React.FC<{   
  onSelectColor: (color: string) => void,  
  activeColor?: string
}> = ({ onSelectColor, activeColor = "#000000" }) => {
  // State to track if the color picker is open
  const [isOpen, setIsOpen] = useState(false);
  // Reference to the button element
  const buttonRef = useRef<HTMLButtonElement>(null);
  // Reference to the dropdown element
  const dropdownRef = useRef<HTMLDivElement>(null);

  // Close the dropdown when clicking outside
  useEffect(() => {
    const handleClickOutside = (event: MouseEvent) => {
      if (
        isOpen &&        
        dropdownRef.current &&        
        buttonRef.current &&        
        !dropdownRef.current.contains(event.target as Element) &&        
        !buttonRef.current.contains(event.target as Element)
      ) {
        setIsOpen(false);
      }
    };
    document.addEventListener("mousedown", handleClickOutside);
    return () => {
      document.removeEventListener("mousedown", handleClickOutside);
    };
  }, [isOpen]);

  const handleButtonClick = (e: React.MouseEvent) => {
    e.preventDefault();
    e.stopPropagation();
    setIsOpen(!isOpen);
  };

  return (
    <div className="relative inline-block">
      <Button
        ref={buttonRef}
        type="button"
        variant="ghost"
        size="sm"
        className="h-8 w-8 p-0 relative"
        title="Text Color"
        onMouseDown={handleButtonClick}
      >
        <Palette className="h-4 w-4" />
        <div 
          className="absolute bottom-1 right-1 w-2 h-2 rounded-full border border-white"
          style={{ backgroundColor: activeColor }}
        />
      </Button>

      {isOpen && (
        <div
          ref={dropdownRef}
          className="absolute z-50 mt-1 w-40 p-2 bg-popover shadow-md rounded-md border border-border"
          style={{ top: "100%", left: "50%", transform: "translateX(-50%)" }}
        >
          <div className="flex flex-wrap gap-1">{colorOptions.map((colorOption) => (
            <Button
              key={colorOption.color}
              type="button"
              variant="ghost"
              size="sm"
              className="h-6 w-6 p-0 rounded-sm"
              style={{ backgroundColor: colorOption.color }}
              title={colorOption.label}
              onMouseDown={(e) => {
                e.preventDefault();
                e.stopPropagation();
                onSelectColor(colorOption.color);
                setIsOpen(false);
              }}
            />
          ))}</div>
        </div>
      )}
    </div>
  );
};

export const SlateRichTextEditor: React.FC<RichTextEditorProps> = ({
  initialValue: initialContent = '',
  onChange,
  placeholder = 'Enter text...',
  readOnly = false,
  disabled = false,
  minHeight = '100px',
  className = '',
}) => {
  // Create a Slate editor object that won't change across renders
  const editor = useMemo(() => withHistory(withReact(createEditor())), []);
  
  // Keep track of state for the formatting buttons
  const [formats, setFormats] = useState({
    bold: false,
    italic: false,
    underline: false,
    'bulleted-list': false,
    'numbered-list': false,
    'align-left': false,
    'align-center': false,
    'align-right': false,
  });
  
  // Track the current text color
  const [currentColor, setCurrentColor] = useState('#000000');
  
  // Initialize content from props
  const [editorValue, setEditorValue] = useState<Descendant[]>(() => 
    parseFromHtml(initialContent)
  );
  
  // Use a key to force remount when initialContent changes
  const [editorKey, setEditorKey] = useState(0);
  
  useEffect(() => {
    const newValue = parseFromHtml(initialContent);
    setEditorValue(newValue);
    setEditorKey(prev => prev + 1);
  }, [initialContent]);
  
  // Update content and trigger onChange
  const handleChange = (value: Descendant[]) => {
    setEditorValue(value);
    
    // Update format states based on current selection
    const selection = editor.selection;
    if (selection) {
      // Check text formatting
      setFormats(prevFormats => ({
        ...prevFormats,
        bold: CustomEditor.isMarkActive(editor, 'bold'),
        italic: CustomEditor.isMarkActive(editor, 'italic'),
        underline: CustomEditor.isMarkActive(editor, 'underline'),
        'bulleted-list': CustomEditor.isBlockActive(editor, 'bulleted-list'),
        'numbered-list': CustomEditor.isBlockActive(editor, 'numbered-list'),
      }));
      
      // Check current color
      const marks = Editor.marks(editor);
      if (marks && marks.color) {
        setCurrentColor(marks.color as string);
      }
    }
    
    // Convert to HTML and trigger the onChange
    const htmlContent = serializeToHtml(value);
    onChange(htmlContent);
  };
  
  // Define a rendering function for custom elements
  const renderElement = useCallback((props: RenderElementProps) => {
    return <Element {...props as CustomRenderElementProps} />;
  }, []);
  
  // Define a rendering function for custom text nodes
  const renderLeaf = useCallback((props: RenderLeafProps) => <Leaf {...props} />, []);
  
  // Toggle mark function
  const toggleMark = (e: React.MouseEvent, format: string) => {
    e.preventDefault();
    e.stopPropagation(); // Prevent event bubbling
    
    if (format === 'bold' || format === 'italic' || format === 'underline') {
      // For text formatting
      CustomEditor.toggleMark(editor, format);
      
      // Update format state
      setFormats(prev => ({
        ...prev,
        [format]: !CustomEditor.isMarkActive(editor, format),
      }));
    } else if (format.startsWith('align-')) {
      // For alignment
      const align = format.replace('align-', '') as 'left' | 'center' | 'right';
      
      // Check if this alignment is already active
      const isActive = CustomEditor.isBlockActive(editor, align, 'align');
      
      // Clear other alignment formats
      setFormats(prev => ({
        ...prev,
        'align-left': format === 'align-left' && !isActive,
        'align-center': format === 'align-center' && !isActive,
        'align-right': format === 'align-right' && !isActive,
      }));
      
      // Set alignment on the current block
      CustomEditor.toggleAlign(editor, align);
    } else if (format === 'bulleted-list' || format === 'numbered-list') {
      // For lists
      CustomEditor.toggleBlock(editor, format);
      
      // Update format state
      setFormats(prev => ({
        ...prev,
        'bulleted-list': format === 'bulleted-list' && !prev['bulleted-list'],
        'numbered-list': format === 'numbered-list' && !prev['numbered-list'],
      }));
    }
  };
  
  // Handle paste to preserve formatting
  const handlePaste = useCallback(
    (event: React.ClipboardEvent) => {
      event.preventDefault();
      
      // Get clipboard data
      const clipboardData = event.clipboardData;
      
      // Try to get HTML content first
      let html = clipboardData.getData('text/html');
      const plainText = clipboardData.getData('text/plain');
      
      // Check if plain text has bullet points
      const hasBulletPoints = plainText.includes('•') || plainText.includes('●') || 
                              (/^\s*[-*]\s+/m).test(plainText);
      
      // If no HTML or we detect bullet points in plain text, handle specially
      if (!html.trim() || hasBulletPoints) {
        // If we detect markdown-style lists or bullet characters
        if (hasBulletPoints || (/^\s*[-*]\s+/m).test(plainText)) {
          const lines = plainText.split('\n').filter(line => line.trim().length > 0);
          const bulletedItems: ListItemElement[] = [];
          const paragraphs: ParagraphElement[] = [];
          
          lines.forEach(line => {
            const trimmedLine = line.trim();
            // Match various bullet styles: •, ●, -, *
            if (trimmedLine.startsWith('•') || trimmedLine.startsWith('●') || 
                trimmedLine.match(/^\s*[-*]\s+/)) {
              // Add as list item, stripping the bullet character
              bulletedItems.push({
                type: 'list-item',
                children: [{ 
                  text: trimmedLine.replace(/^[•●]|\s*[-*]\s+/, '').trim() 
                }]
              });
            } else {
              // Regular paragraph
              paragraphs.push({
                type: 'paragraph',
                children: [{ text: trimmedLine }]
              });
            }
          });
          
          // Insert paragraphs and list items
          if (paragraphs.length > 0) {
            editor.insertFragment(paragraphs as any);
          }
          
          if (bulletedItems.length > 0) {
            editor.insertFragment([{
              type: 'bulleted-list',
              children: bulletedItems
            }] as any);
          }
          
          return;
        }
        
        // If no special formatting detected, insert as plain text
        if (plainText) {
          editor.insertText(plainText);
        }
        return;
      }
      
      // Create valid HTML if it seems like a fragment
      if (!html.includes('<html') && !html.includes('<body')) {
        html = `<html><body>${html}</body></html>`;
      }
      
      // Parse HTML content to Slate format
      const parsed = parseFromHtml(html);
      
      // Insert the parsed content
      editor.insertFragment(parsed);
    },
    [editor]
  );
  
  // Add debug logging for input events
  const handleKeyDown = useCallback((event: React.KeyboardEvent<HTMLDivElement>) => {
    console.log('Key down event:', event.key);
  }, [editor]);

  // Ensure editor focuses on click
  const handleClick = useCallback((event: React.MouseEvent<HTMLDivElement>) => {
    console.log('Editor clicked, focusing');
    ReactEditor.focus(editor);
  }, [editor]);
  
  // Handle indent/outdent
  const handleIndent = (e: React.MouseEvent, increase: boolean) => {
    e.preventDefault();
    e.stopPropagation();
    
    // Get the current selection
    const { selection } = editor;
    if (!selection) {
      console.warn('No selection to indent');
      return;
    }
    
    // Create a reusable function to help with indentation
    const modifyIndent = (element: CustomElement) => {
      if (increase) {
        const currentIndent = element.indent || 0;
        if (currentIndent < 5) { // Limit max indent
          return { ...element, indent: currentIndent + 1 };
        }
      } else {
        const currentIndent = element.indent || 0;
        if (currentIndent > 0) {
          return { ...element, indent: currentIndent - 1 };
        }
      }
      return element;
    };
    
    // Apply the indentation to all selected blocks
    try {
      const startPoint = selection.anchor.path[0];
      const endPoint = selection.focus.path[0];
      
      // Determine the range of blocks to indent
      const start = Math.min(startPoint, endPoint);
      const end = Math.max(startPoint, endPoint);
      
      console.log(`Indenting blocks from ${start} to ${end}`);
      
      // Modify each block in the selection range
      for (let i = start; i <= end; i++) {
        const path = [i];
        const node = Node.get(editor, path) as CustomElement;
        
        if (SlateElement.isElement(node)) {
          // Get current indent value
          const currentIndent = node.indent || 0;
          const newIndent = increase 
            ? Math.min(currentIndent + 1, 5) // Increase with max limit of 5
            : Math.max(currentIndent - 1, 0); // Decrease with min limit of 0
          
          console.log(`Block ${i}: Changing indent from ${currentIndent} to ${newIndent}`);
          
          // Apply the change
          if (newIndent !== currentIndent) {
            Transforms.setNodes(
              editor,
              { indent: newIndent },
              { at: path }
            );
          }
        }
      }
      
      // Force update to ensure changes are reflected
      const html = serializeToHtml(editor.children as Descendant[]);
      console.log('Updated HTML:', html);
      onChange(html);
      
    } catch (error) {
      console.error('Error applying indentation:', error);
    }
  };
  
  // Handle color selection
  const handleColorSelect = (color: string) => {
    setCurrentColor(color);
    CustomEditor.setColor(editor, color);
  };
  
  return (
    <div 
      className={`border rounded-md ${className}`} 
      style={{ minHeight }}
      onClick={e => e.stopPropagation()}
    >
      <Slate
        key={editorKey}
        editor={editor}
        initialValue={editorValue}
        onChange={handleChange}
      >
        {!readOnly && !disabled && (
          <div 
            className="p-1 border-b flex flex-wrap gap-1 bg-muted/20"
            onMouseDown={e => e.stopPropagation()}
            onClick={e => e.stopPropagation()}
          >
            <FormatButton
              format="bold"
              icon={<Bold className="h-4 w-4" />}
              isActive={formats.bold}
              onMouseDown={(e) => toggleMark(e, 'bold')}
            />
            <FormatButton
              format="italic"
              icon={<Italic className="h-4 w-4" />}
              isActive={formats.italic}
              onMouseDown={(e) => toggleMark(e, 'italic')}
            />
            <FormatButton
              format="underline"
              icon={<Underline className="h-4 w-4" />}
              isActive={formats.underline}
              onMouseDown={(e) => toggleMark(e, 'underline')}
            />
            
            <ColorButton 
              onSelectColor={handleColorSelect} 
              activeColor={currentColor}
            />
            
            <div className="h-8 w-px bg-border mx-1" />
            
            <FormatButton
              format="bulleted-list"
              icon={<List className="h-4 w-4" />}
              isActive={formats['bulleted-list']}
              onMouseDown={(e) => toggleMark(e, 'bulleted-list')}
            />
            <FormatButton
              format="numbered-list"
              icon={<ListOrdered className="h-4 w-4" />}
              isActive={formats['numbered-list']}
              onMouseDown={(e) => toggleMark(e, 'numbered-list')}
            />
            
            <div className="h-8 w-px bg-border mx-1" />
            
            <FormatButton
              format="indent"
              icon={<Indent className="h-4 w-4" />}
              onMouseDown={(e) => handleIndent(e, true)}
            />
            <FormatButton
              format="outdent"
              icon={<Outdent className="h-4 w-4" />}
              onMouseDown={(e) => handleIndent(e, false)}
            />
            
            <div className="h-8 w-px bg-border mx-1" />
            
            <FormatButton
              format="align-left"
              icon={<AlignLeft className="h-4 w-4" />}
              isActive={formats['align-left']}
              onMouseDown={(e) => toggleMark(e, 'align-left')}
            />
            <FormatButton
              format="align-center"
              icon={<AlignCenter className="h-4 w-4" />}
              isActive={formats['align-center']}
              onMouseDown={(e) => toggleMark(e, 'align-center')}
            />
            <FormatButton
              format="align-right"
              icon={<AlignRight className="h-4 w-4" />}
              isActive={formats['align-right']}
              onMouseDown={(e) => toggleMark(e, 'align-right')}
            />
          </div>
        )}
        <Editable
          renderElement={renderElement}
          renderLeaf={renderLeaf}
          placeholder={placeholder || 'Enter some text...'}
          readOnly={readOnly || disabled}
          onKeyDown={handleKeyDown}
          onClick={handleClick}
          className={`outline-none p-3 ${minHeight || 'min-h-[100px]'}`}
          onPaste={handlePaste}
        />
      </Slate>
    </div>
  );
};

export default SlateRichTextEditor; 