/**
 * Holy Editor
 * 
 * Main editor class that integrates all components
 * Extracted from Holy Habit holy-editor-pro.js
 */

import { 
  EditorConfig, 
  EditorSelection, 
  FormatAction, 
  FormatState,
  BibleVerseData,
  EditorError,
  BibleApiError,
  SlashCommandMatch
} from './types/Editor';

import { BibleVerseEngine } from './core/BibleVerseEngine';
import { TextFormatter } from './core/TextFormatter';
import { PWAKeyboardTracker } from './pwa/PWAKeyboardTracker';
import { ToastManager } from './ui/ToastManager';
import { ColorPicker } from './ui/ColorPicker';
import { AutoSaveManager } from './utils/AutoSaveManager';

export class HolyEditor {
  private editorElement: HTMLElement;
  private config: EditorConfig;
  private isInitialized = false;
  
  // Core components
  private bibleEngine: BibleVerseEngine;
  private textFormatter: TextFormatter;
  private keyboardTracker: PWAKeyboardTracker;
  private toastManager: ToastManager;
  private colorPicker: ColorPicker;
  private autoSaveManager: AutoSaveManager | null = null;
  
  // Event listeners for cleanup
  private eventListeners: Array<{ element: EventTarget; event: string; handler: EventListener }> = [];
  
  // State management
  private isProcessingSlashCommand = false;
  private lastInputTime = 0;
  private inputDebounceMs = 300;

  constructor(editorId: string, config?: Partial<EditorConfig>) {
    const editorElement = document.getElementById(editorId);
    if (!editorElement) {
      throw new EditorError(`Editor element with id "${editorId}" not found`);
    }
    
    this.editorElement = editorElement;
    this.config = {
      enableBibleVerses: true,
      enableTextFormatting: true,
      enablePWAKeyboard: true,
      enableColorPicker: true,
      enableAutoSave: true,
      apiEndpoint: '/api/bible_verse_full.php',
      debounceMs: 300,
      autoSaveInterval: 30000,
      autoSaveKey: undefined,
      keyboardSettings: {
        threshold: 10,
        keyboardMin: 150,
        debounceTime: 0
      },
      ...config
    };
    
    // Initialize components
    this.initializeComponents();
    
    console.log('📝 HolyEditor created for element:', editorId);
  }

  /**
   * Initialize all editor components
   */
  private initializeComponents(): void {
    try {
      // Initialize Bible verse engine
      if (this.config.enableBibleVerses) {
        this.bibleEngine = BibleVerseEngine.getInstance(
          this.config.apiEndpoint,
          this.config.debounceMs
        );
      }
      
      // Initialize text formatter
      if (this.config.enableTextFormatting) {
        this.textFormatter = new TextFormatter(this.editorElement.id);
      }
      
      // Initialize PWA keyboard tracker
      if (this.config.enablePWAKeyboard) {
        this.keyboardTracker = new PWAKeyboardTracker(this.config.keyboardSettings);
      }
      
      // Initialize UI components
      this.toastManager = ToastManager.getInstance();
      
      if (this.config.enableColorPicker) {
        this.colorPicker = ColorPicker.getInstance();
      }
      
      // Initialize auto-save manager
      if (this.config.enableAutoSave) {
        this.autoSaveManager = new AutoSaveManager(this.editorElement.id, {
          interval: this.config.autoSaveInterval,
          key: this.config.autoSaveKey,
          onSave: (data) => {
            this.toastManager.success('내용이 자동 저장되었습니다', 2000);
          },
          onError: (error) => {
            console.error('❌ Auto-save error:', error);
            this.toastManager.error('자동 저장 중 오류가 발생했습니다');
          }
        });
      }
      
      console.log('🔧 HolyEditor components initialized');
    } catch (error) {
      console.error('❌ Failed to initialize components:', error);
      throw new EditorError('Component initialization failed', 'INIT_ERROR', error as Error);
    }
  }

  /**
   * Initialize the editor
   */
  public initialize(): void {
    if (this.isInitialized) {
      console.warn('⚠️ HolyEditor already initialized');
      return;
    }
    
    try {
      this.setupEditor();
      this.setupEventListeners();
      this.initializePWAFeatures();
      this.initializeAutoSave();
      
      this.isInitialized = true;
      console.log('✅ HolyEditor initialized successfully');
      
      this.toastManager.success('에디터가 준비되었습니다');
    } catch (error) {
      console.error('❌ HolyEditor initialization failed:', error);
      throw new EditorError('Editor initialization failed', 'INIT_ERROR', error as Error);
    }
  }

  /**
   * Setup editor element
   */
  private setupEditor(): void {
    // Make contenteditable if not already
    if (!this.editorElement.hasAttribute('contenteditable')) {
      this.editorElement.setAttribute('contenteditable', 'true');
    }
    
    // Add editor class for styling
    this.editorElement.classList.add('holy-editor');
    
    // Set placeholder if empty
    if (!this.editorElement.textContent?.trim()) {
      this.editorElement.innerHTML = '<p>성경 구절을 입력하려면 /갈2:20 같은 형식으로 입력하세요...</p>';
    }
    
    // Ensure editor has focus capabilities
    if (!this.editorElement.hasAttribute('tabindex')) {
      this.editorElement.setAttribute('tabindex', '0');
    }
  }

  /**
   * Setup all event listeners
   */
  private setupEventListeners(): void {
    // Input events for slash command detection
    this.addEventListener(this.editorElement, 'input', this.handleInput.bind(this));
    this.addEventListener(this.editorElement, 'keydown', this.handleKeyDown.bind(this));
    this.addEventListener(this.editorElement, 'paste', this.handlePaste.bind(this));
    
    // Focus events for PWA keyboard tracking
    this.addEventListener(this.editorElement, 'focus', this.handleFocus.bind(this));
    this.addEventListener(this.editorElement, 'blur', this.handleBlur.bind(this));
    
    // Selection change for formatting state
    this.addEventListener(document, 'selectionchange', this.handleSelectionChange.bind(this));
    
    console.log('🎯 Event listeners setup complete');
  }

  /**
   * Initialize PWA features
   */
  private initializePWAFeatures(): void {
    if (this.config.enablePWAKeyboard && this.keyboardTracker) {
      this.keyboardTracker.initialize(this.editorElement);
    }
  }

  /**
   * Initialize auto-save features
   */
  private initializeAutoSave(): void {
    if (!this.autoSaveManager || !this.config.enableAutoSave) return;
    
    // Check for saved content
    const savedContent = this.autoSaveManager.restore();
    if (savedContent && savedContent.trim()) {
      // Ask user if they want to restore
      const saveInfo = this.autoSaveManager.getSaveInfo();
      if (saveInfo) {
        const ageMinutes = Math.floor((Date.now() - saveInfo.timestamp) / 60000);
        const shouldRestore = confirm(
          `이전에 작성하던 내용이 있습니다 (${ageMinutes}분 전).\n복원하시겠습니까?`
        );
        
        if (shouldRestore) {
          this.setContent(savedContent);
          this.toastManager.success('저장된 내용을 복원했습니다');
        } else {
          // Clear the saved content if user declines
          this.autoSaveManager.clear();
        }
      }
    }
    
    // Start auto-saving
    this.autoSaveManager.start(() => this.getContent());
  }

  /**
   * Handle input events
   */
  private handleInput(event: Event): void {
    if (this.isProcessingSlashCommand) return;
    
    const now = Date.now();
    this.lastInputTime = now;
    
    // Debounced slash command processing
    setTimeout(() => {
      if (this.lastInputTime === now && this.config.enableBibleVerses) {
        this.processSlashCommands();
      }
    }, this.inputDebounceMs);
    
    // Trigger auto-save on input (auto-save manager handles its own debouncing)
    if (this.autoSaveManager && this.autoSaveManager.isRunning()) {
      // Content will be saved at the next interval
    }
  }

  /**
   * Handle keydown events
   */
  private handleKeyDown(event: KeyboardEvent): void {
    // Handle formatting shortcuts
    if (event.ctrlKey || event.metaKey) {
      switch (event.key.toLowerCase()) {
        case 'b':
          event.preventDefault();
          this.toggleFormat('bold');
          break;
        case 'u':
          event.preventDefault();
          this.toggleFormat('underline');
          break;
        case 'h':
          event.preventDefault();
          this.toggleFormat('heading1');
          break;
        case 'q':
          event.preventDefault();
          this.toggleFormat('quote');
          break;
      }
    }
    
    // Handle Enter key in quotes
    if (event.key === 'Enter') {
      const selection = window.getSelection();
      if (selection && selection.anchorNode) {
        const quoteParent = this.findParentQuote(selection.anchorNode);
        if (quoteParent) {
          event.preventDefault();
          this.handleEnterInQuote();
        }
      }
    }
  }

  /**
   * Handle paste events
   */
  private handlePaste(event: ClipboardEvent): void {
    event.preventDefault();
    
    const text = event.clipboardData?.getData('text/plain') || '';
    if (text) {
      // Insert as plain text
      document.execCommand('insertText', false, text);
      
      // Process any slash commands in pasted text
      setTimeout(() => {
        if (this.config.enableBibleVerses) {
          this.processSlashCommands();
        }
      }, 100);
    }
  }

  /**
   * Handle focus events
   */
  private handleFocus(): void {
    console.log('📝 Editor focused');
    this.editorElement.classList.add('holy-editor-focused');
  }

  /**
   * Handle blur events
   */
  private handleBlur(): void {
    console.log('📝 Editor blurred');
    this.editorElement.classList.remove('holy-editor-focused');
  }

  /**
   * Handle selection change
   */
  private handleSelectionChange(): void {
    // Update formatting state indicators if needed
    if (this.config.enableTextFormatting && this.textFormatter) {
      const formatState = this.textFormatter.getFormatState();
      this.updateFormatButtons(formatState);
    }
  }

  /**
   * Process slash commands in editor content
   */
  private async processSlashCommands(): Promise<void> {
    if (!this.bibleEngine || this.isProcessingSlashCommand) return;
    
    this.isProcessingSlashCommand = true;
    
    try {
      const content = this.editorElement.textContent || '';
      const matches = this.bibleEngine.parseSlashCommands(content);
      
      for (const match of matches) {
        await this.processSlashCommand(match);
      }
    } catch (error) {
      console.error('❌ Error processing slash commands:', error);
      if (error instanceof BibleApiError) {
        this.toastManager.handleApiError(error);
      } else {
        this.toastManager.error('슬래시 명령어 처리 중 오류가 발생했습니다');
      }
    } finally {
      this.isProcessingSlashCommand = false;
    }
  }

  /**
   * Process individual slash command
   */
  private async processSlashCommand(match: SlashCommandMatch): Promise<void> {
    const { ref, position, fullMatch } = match;
    
    console.log('📖 Processing slash command:', ref);
    
    // Show loading toast
    const hideLoading = this.toastManager.showLoading(`${ref} 구절 검색 중...`);
    
    try {
      const verseData = await this.bibleEngine.loadVerse(ref);
      hideLoading();
      
      if (verseData) {
        this.insertVerseAtPosition(verseData, position, fullMatch.length);
        this.bibleEngine.updateInsertionState(ref);
        this.toastManager.success(`${ref} 구절이 삽입되었습니다`);
      } else {
        this.toastManager.error(`${ref} 구절을 찾을 수 없습니다`);
      }
    } catch (error) {
      hideLoading();
      console.error('❌ Failed to load verse:', ref, error);
      
      if (error instanceof BibleApiError) {
        this.toastManager.handleApiError(error, ref);
      } else {
        this.toastManager.error(`${ref} 구절 로드 중 오류가 발생했습니다`);
      }
    }
  }

  /**
   * Insert verse at specific position
   */
  private insertVerseAtPosition(verseData: BibleVerseData, position: number, commandLength: number): void {
    const content = this.editorElement.textContent || '';
    const beforeText = content.substring(0, position);
    const afterText = content.substring(position + commandLength);
    
    // Create verse HTML
    const verseHtml = this.createVerseHtml(verseData);
    
    // Replace content
    const newContent = beforeText + verseHtml + afterText;
    this.editorElement.innerHTML = newContent;
    
    // Position cursor after inserted verse
    this.positionCursorAfterVerse(position + verseHtml.length);
  }

  /**
   * Create HTML for verse display
   */
  private createVerseHtml(verseData: BibleVerseData): string {
    if (verseData.isRange && verseData.verses.length > 1) {
      // Multiple verses (range)
      const versesHtml = verseData.verses.map(verse => 
        `<span class="verse-text">${verse.text}</span>`
      ).join(' ');
      
      const firstVerse = verseData.verses[0];
      const lastVerse = verseData.verses[verseData.verses.length - 1];
      const reference = `${firstVerse.book} ${firstVerse.chapter}:${firstVerse.verse}-${lastVerse.verse}`;
      
      return `<blockquote class="bible-verse-range" data-reference="${reference}">
        ${versesHtml}
        <cite class="verse-reference">${reference}</cite>
      </blockquote>`;
    } else {
      // Single verse
      const verse = verseData.verses[0];
      const reference = `${verse.book} ${verse.chapter}:${verse.verse}`;
      
      return `<blockquote class="bible-verse" data-reference="${reference}">
        <span class="verse-text">${verse.text}</span>
        <cite class="verse-reference">${reference}</cite>
      </blockquote>`;
    }
  }

  /**
   * Position cursor after inserted content
   */
  private positionCursorAfterVerse(position: number): void {
    const range = document.createRange();
    const selection = window.getSelection();
    
    if (selection) {
      try {
        const textNode = this.findTextNodeAtPosition(position);
        if (textNode) {
          range.setStart(textNode, Math.min(position, textNode.textContent?.length || 0));
          range.collapse(true);
          selection.removeAllRanges();
          selection.addRange(range);
        }
      } catch (error) {
        console.warn('⚠️ Could not position cursor:', error);
      }
    }
  }

  /**
   * Find text node at specific position
   */
  private findTextNodeAtPosition(position: number): Text | null {
    const walker = document.createTreeWalker(
      this.editorElement,
      NodeFilter.SHOW_TEXT,
      null
    );
    
    let currentPosition = 0;
    let node = walker.nextNode() as Text;
    
    while (node) {
      const nodeLength = node.textContent?.length || 0;
      if (currentPosition + nodeLength >= position) {
        return node;
      }
      currentPosition += nodeLength;
      node = walker.nextNode() as Text;
    }
    
    return null;
  }

  /**
   * Toggle text formatting
   */
  public toggleFormat(action: FormatAction): void {
    if (!this.config.enableTextFormatting || !this.textFormatter) {
      console.warn('⚠️ Text formatting is disabled');
      return;
    }
    
    try {
      this.textFormatter.toggleStyle(action);
      
      // Update button states
      const formatState = this.textFormatter.getFormatState();
      this.updateFormatButtons(formatState);
    } catch (error) {
      console.error('❌ Format toggle failed:', error);
      this.toastManager.error('텍스트 포맷팅 중 오류가 발생했습니다');
    }
  }

  /**
   * Apply text color
   */
  public applyTextColor(color: string): void {
    if (!this.config.enableTextFormatting || !this.textFormatter) {
      console.warn('⚠️ Text formatting is disabled');
      return;
    }
    
    try {
      this.textFormatter.applyTextColor(color);
    } catch (error) {
      console.error('❌ Color application failed:', error);
      this.toastManager.error('색상 적용 중 오류가 발생했습니다');
    }
  }

  /**
   * Show color picker
   */
  public showColorPicker(): void {
    if (!this.config.enableColorPicker || !this.colorPicker) {
      console.warn('⚠️ Color picker is disabled');
      return;
    }
    
    this.colorPicker.show((color: string) => {
      this.applyTextColor(color);
    });
  }

  /**
   * Get current editor content
   */
  public getContent(): string {
    return this.editorElement.innerHTML;
  }

  /**
   * Set editor content
   */
  public setContent(html: string): void {
    this.editorElement.innerHTML = html;
  }

  /**
   * Get plain text content
   */
  public getTextContent(): string {
    return this.editorElement.textContent || '';
  }

  /**
   * Clear editor content
   */
  public clear(): void {
    this.editorElement.innerHTML = '';
  }

  /**
   * Focus the editor
   */
  public focus(): void {
    this.editorElement.focus();
  }

  /**
   * Check if editor has focus
   */
  public isFocused(): boolean {
    return document.activeElement === this.editorElement;
  }

  /**
   * Get current format state
   */
  public getFormatState(): FormatState | null {
    if (!this.config.enableTextFormatting || !this.textFormatter) {
      return null;
    }
    
    return this.textFormatter.getFormatState();
  }

  /**
   * Insert verse programmatically
   */
  public async insertVerse(ref: string): Promise<boolean> {
    if (!this.config.enableBibleVerses || !this.bibleEngine) {
      console.warn('⚠️ Bible verses are disabled');
      return false;
    }
    
    try {
      if (!this.bibleEngine.isValidBibleRef(ref)) {
        this.toastManager.error(`올바르지 않은 성경 참조: ${ref}`);
        return false;
      }
      
      const hideLoading = this.toastManager.showLoading(`${ref} 구절 검색 중...`);
      const verseData = await this.bibleEngine.loadVerse(ref);
      hideLoading();
      
      if (verseData) {
        const verseHtml = this.createVerseHtml(verseData);
        
        // Insert at current cursor position
        const selection = window.getSelection();
        if (selection && selection.rangeCount > 0) {
          const range = selection.getRangeAt(0);
          range.deleteContents();
          
          const tempDiv = document.createElement('div');
          tempDiv.innerHTML = verseHtml;
          const fragment = document.createDocumentFragment();
          
          while (tempDiv.firstChild) {
            fragment.appendChild(tempDiv.firstChild);
          }
          
          range.insertNode(fragment);
          range.collapse(false);
          selection.removeAllRanges();
          selection.addRange(range);
        } else {
          // No selection, append to end
          this.editorElement.insertAdjacentHTML('beforeend', verseHtml);
        }
        
        this.toastManager.success(`${ref} 구절이 삽입되었습니다`);
        return true;
      } else {
        this.toastManager.error(`${ref} 구절을 찾을 수 없습니다`);
        return false;
      }
    } catch (error) {
      console.error('❌ Failed to insert verse:', error);
      if (error instanceof BibleApiError) {
        this.toastManager.handleApiError(error, ref);
      } else {
        this.toastManager.error('구절 삽입 중 오류가 발생했습니다');
      }
      return false;
    }
  }

  /**
   * Destroy the editor and cleanup
   */
  public destroy(): void {
    if (!this.isInitialized) return;
    
    try {
      // Remove all event listeners
      this.eventListeners.forEach(({ element, event, handler }) => {
        element.removeEventListener(event, handler);
      });
      this.eventListeners = [];
      
      // Destroy PWA keyboard tracker
      if (this.keyboardTracker) {
        this.keyboardTracker.destroy();
      }
      
      // Hide color picker if open
      if (this.colorPicker && this.colorPicker.isOpen()) {
        this.colorPicker.hide();
      }
      
      // Stop auto-save
      if (this.autoSaveManager) {
        this.autoSaveManager.stop();
      }
      
      // Clear editor classes
      this.editorElement.classList.remove('holy-editor', 'holy-editor-focused');
      
      this.isInitialized = false;
      console.log('🗑️ HolyEditor destroyed');
    } catch (error) {
      console.error('❌ Error during editor destruction:', error);
    }
  }

  // Private utility methods
  private addEventListener(element: EventTarget, event: string, handler: EventListener): void {
    element.addEventListener(event, handler);
    this.eventListeners.push({ element, event, handler });
  }

  private findParentQuote(node: Node): Element | null {
    let current = node.nodeType === Node.TEXT_NODE ? node.parentNode : node;
    
    while (current && current !== this.editorElement) {
      if (current instanceof Element && 
          (current.tagName === 'BLOCKQUOTE' || current.classList.contains('inline-quote'))) {
        return current;
      }
      current = current.parentNode;
    }
    
    return null;
  }

  private handleEnterInQuote(): void {
    // Create new paragraph after quote
    const p = document.createElement('p');
    p.innerHTML = '&#8203;'; // Zero-width space
    
    const selection = window.getSelection();
    if (selection && selection.rangeCount > 0) {
      const range = selection.getRangeAt(0);
      const quote = this.findParentQuote(range.startContainer);
      
      if (quote && quote.parentNode) {
        quote.parentNode.insertBefore(p, quote.nextSibling);
        
        // Move cursor to new paragraph
        range.selectNodeContents(p);
        range.collapse(false);
        selection.removeAllRanges();
        selection.addRange(range);
      }
    }
  }

  private updateFormatButtons(formatState: FormatState): void {
    // This would update external format buttons if they exist
    // Can be overridden by implementing applications
    const event = new CustomEvent('holyeditor:formatstatechange', {
      detail: formatState
    });
    this.editorElement.dispatchEvent(event);
  }

  /**
   * Manually save content (auto-save)
   */
  public saveContent(): boolean {
    if (!this.autoSaveManager || !this.config.enableAutoSave) {
      console.warn('⚠️ Auto-save is disabled');
      return false;
    }
    
    return this.autoSaveManager.save(this.getContent());
  }

  /**
   * Clear saved content
   */
  public clearSavedContent(): boolean {
    if (!this.autoSaveManager) return false;
    
    return this.autoSaveManager.clear();
  }

  /**
   * Check if there's saved content
   */
  public hasSavedContent(): boolean {
    if (!this.autoSaveManager) return false;
    
    return this.autoSaveManager.hasSavedContent();
  }

  /**
   * Get auto-save info
   */
  public getAutoSaveInfo(): { isRunning: boolean; lastSave?: number; hasContent: boolean } {
    if (!this.autoSaveManager) {
      return { isRunning: false, hasContent: false };
    }
    
    const saveInfo = this.autoSaveManager.getSaveInfo();
    
    return {
      isRunning: this.autoSaveManager.isRunning(),
      lastSave: saveInfo?.timestamp,
      hasContent: this.autoSaveManager.hasSavedContent()
    };
  }

  /**
   * Update auto-save interval
   */
  public updateAutoSaveInterval(intervalMs: number): void {
    if (!this.autoSaveManager) return;
    
    this.autoSaveManager.updateInterval(intervalMs, () => this.getContent());
    this.config.autoSaveInterval = intervalMs;
  }

  /**
   * Toggle auto-save
   */
  public toggleAutoSave(enable?: boolean): void {
    const shouldEnable = enable !== undefined ? enable : !this.config.enableAutoSave;
    this.config.enableAutoSave = shouldEnable;
    
    if (!this.autoSaveManager) return;
    
    if (shouldEnable) {
      this.autoSaveManager.start(() => this.getContent());
      this.toastManager.success('자동 저장이 활성화되었습니다');
    } else {
      this.autoSaveManager.stop();
      this.toastManager.info('자동 저장이 비활성화되었습니다');
    }
  }
}