/**
 * Bible Verse Engine
 * 
 * Core engine for Bible verse slash commands and API integration
 * Extracted from Holy Habit holy-editor-pro.js
 */

import {
  BibleVerse,
  BibleVerseData,
  BibleApiResponse,
  BibleApiError,
  BibleBookMapping,
  VerseCache,
  SlashCommandMatch
} from '../types/Editor';

export class BibleVerseEngine {
  private static instance: BibleVerseEngine;
  private cache: VerseCache = {};
  private lastInsertedRef = '';
  private lastInsertedTime = 0;
  private debounceMs = 300;
  private apiEndpoint = '/api/bible_verse_full.php';

  // Bible book mappings (66 books total)
  private static readonly OLD_TESTAMENT_BOOKS: BibleBookMapping = {
    창: '창세기', 출: '출애굽기', 레: '레위기', 민: '민수기', 신: '신명기',
    수: '여호수아', 삿: '사사기', 룻: '룻기', 삼상: '사무엘상', 삼하: '사무엘하',
    왕상: '열왕기상', 왕하: '열왕기하', 대상: '역대상', 대하: '역대하',
    스: '에스라', 느: '느헤미야', 에: '에스더', 욥: '욥기', 시: '시편',
    잠: '잠언', 전: '전도서', 아: '아가', 사: '이사야', 렘: '예레미야',
    애: '예레미야애가', 겔: '에스겔', 단: '다니엘', 호: '호세아', 욜: '요엘',
    암: '아모스', 옵: '오바댜', 욘: '요나', 미: '미가', 나: '나훔',
    합: '하박국', 습: '스바냐', 학: '학개', 슥: '스가랴', 말: '말라기'
  };

  private static readonly NEW_TESTAMENT_BOOKS: BibleBookMapping = {
    마: '마태복음', 막: '마가복음', 눅: '누가복음', 요: '요한복음',
    행: '사도행전', 롬: '로마서', 고전: '고린도전서', 고후: '고린도후서',
    갈: '갈라디아서', 엡: '에베소서', 빌: '빌립보서', 골: '골로새서',
    살전: '데살로니가전서', 살후: '데살로니가후서', 딤전: '디모데전서',
    딤후: '디모데후서', 딛: '디도서', 몬: '빌레몬서', 히: '히브리서',
    약: '야고보서', 벧전: '베드로전서', 벧후: '베드로후서',
    요일: '요한일서', 요이: '요한이서', 요삼: '요한삼서', 유: '유다서', 계: '요한계시록'
  };

  private static readonly ALL_BOOKS: BibleBookMapping = {
    ...BibleVerseEngine.OLD_TESTAMENT_BOOKS,
    ...BibleVerseEngine.NEW_TESTAMENT_BOOKS
  };

  // Regular expressions
  private static readonly CMD_RE = /\/([^\s/]{1,24})/ug;
  private static readonly BIBLE_REF_RE = /^([가-힣A-Za-z]{1,6})(\d{0,3}):(\d{1,3})(?:-(\d{1,3}))?$/u;

  private constructor(apiEndpoint?: string, debounceMs?: number) {
    if (apiEndpoint) {
      this.apiEndpoint = apiEndpoint;
    }
    if (debounceMs !== undefined) {
      this.debounceMs = debounceMs;
    }
  }

  /**
   * Get singleton instance
   */
  public static getInstance(apiEndpoint?: string, debounceMs?: number): BibleVerseEngine {
    if (!BibleVerseEngine.instance) {
      BibleVerseEngine.instance = new BibleVerseEngine(apiEndpoint, debounceMs);
    }
    return BibleVerseEngine.instance;
  }

  /**
   * Parse slash commands from text
   */
  public parseSlashCommands(text: string): SlashCommandMatch[] {
    const matches: SlashCommandMatch[] = [];
    
    for (const match of text.matchAll(BibleVerseEngine.CMD_RE)) {
      const ref = match[1].replace(/\u00A0/g, ''); // Remove NBSP
      const position = match.index || 0;
      
      if (this.isValidBibleRef(ref)) {
        matches.push({
          ref,
          position,
          fullMatch: match[0]
        });
      }
    }
    
    return matches;
  }

  /**
   * Validate Bible reference format (supports range verses)
   */
  public isValidBibleRef(ref: string): boolean {
    // Format check
    const match = ref.match(BibleVerseEngine.BIBLE_REF_RE);
    if (!match) return false;

    const [, , , fromVerse, toVerse] = match;
    
    // Range verse validation
    if (toVerse) {
      const from = parseInt(fromVerse);
      const to = parseInt(toVerse);
      
      // End verse must be greater than start verse
      if (to < from) {
        return false;
      }
      
      // Limit range to 10 verses maximum
      if (to - from > 10) {
        console.warn('📖 Range too large (max 10 verses):', ref);
        return false;
      }
    }
    
    // Book name validation
    const bookAbbr = ref.replace(/\s*\d.*$/, '').trim();
    if (!BibleVerseEngine.ALL_BOOKS[bookAbbr]) {
      console.warn('📖 Unsupported Bible book:', bookAbbr);
      return false;
    }
    
    // Duplicate prevention (debouncing)
    const now = Date.now();
    if (ref === this.lastInsertedRef && now - this.lastInsertedTime < this.debounceMs) {
      console.log('📖 Duplicate insertion prevented:', ref);
      return false;
    }
    
    console.log('📖 Valid Bible reference:', ref);
    return true;
  }

  /**
   * Load verse from API with caching and error handling
   */
  public async loadVerse(ref: string): Promise<BibleVerseData | null> {
    // Check memory cache first
    const cachedVerse = this.cache[ref];
    if (cachedVerse) {
      console.log('📖 Loading verse from cache:', ref, cachedVerse);
      return cachedVerse;
    }

    // API call if not cached
    try {
      const url = `${this.apiEndpoint}?query=${encodeURIComponent(ref)}`;
      const response = await fetch(url, { cache: 'force-cache' });
      
      if (!response.ok) {
        // Handle different error status codes
        await response.json().catch(() => ({}));
        
        switch (response.status) {
          case 404:
            throw new BibleApiError('Verse not found', 404);
          case 422:
            throw new BibleApiError('Invalid verse format', 422);
          case 500:
            throw new BibleApiError('Server error', 500);
          default:
            throw new BibleApiError('Network error', response.status);
        }
      }
      
      const data: BibleApiResponse = await response.json();
      
      // Handle new API response format (supports range verses)
      if (data.success && data.verses && data.verses.length > 0) {
        const verseData: BibleVerseData = {
          verses: data.verses,
          isRange: data.verses.length > 1
        };
        
        // Cache the result
        this.cache[ref] = verseData;
        console.log('📖 Verse loaded successfully:', ref, verseData);
        return verseData;
      } else {
        console.warn('📖 Verse not found:', ref);
        return null;
      }
      
    } catch (error) {
      if (error instanceof BibleApiError) {
        throw error;
      }
      console.error('📖 Network connection error:', ref, error);
      throw new BibleApiError('Network connection failed', undefined, error as Error);
    }
  }

  /**
   * Get book name from abbreviation
   */
  public getBookName(abbr: string): string | undefined {
    return BibleVerseEngine.ALL_BOOKS[abbr];
  }

  /**
   * Get all supported book abbreviations
   */
  public getSupportedBooks(): string[] {
    return Object.keys(BibleVerseEngine.ALL_BOOKS);
  }

  /**
   * Update duplicate prevention state
   */
  public updateInsertionState(ref: string): void {
    this.lastInsertedRef = ref;
    this.lastInsertedTime = Date.now();
  }

  /**
   * Clear cache
   */
  public clearCache(): void {
    this.cache = {};
    console.log('📖 Bible verse cache cleared');
  }

  /**
   * Get cache stats
   */
  public getCacheStats(): { size: number; keys: string[] } {
    const keys = Object.keys(this.cache);
    return {
      size: keys.length,
      keys
    };
  }

  /**
   * Set API endpoint
   */
  public setApiEndpoint(endpoint: string): void {
    this.apiEndpoint = endpoint;
  }

  /**
   * Set debounce time
   */
  public setDebounceMs(ms: number): void {
    this.debounceMs = ms;
  }

  /**
   * Extract book abbreviation from reference
   */
  public extractBookAbbr(ref: string): string {
    return ref.replace(/\s*\d.*$/, '').trim();
  }

  /**
   * Check if reference is a range verse
   */
  public isRangeVerse(ref: string): boolean {
    const match = ref.match(BibleVerseEngine.BIBLE_REF_RE);
    return match ? !!match[4] : false;
  }

  /**
   * Parse verse numbers from reference
   */
  public parseVerseNumbers(ref: string): { chapter: number; startVerse: number; endVerse?: number } | null {
    const match = ref.match(BibleVerseEngine.BIBLE_REF_RE);
    if (!match) return null;

    const [, , chapter, startVerse, endVerse] = match;
    return {
      chapter: parseInt(chapter) || 1,
      startVerse: parseInt(startVerse),
      endVerse: endVerse ? parseInt(endVerse) : undefined
    };
  }
}