import { type IBlock } from './wysiwyg.types.js';

export class WysiwygConverters {
  static escapeHtml(text: string): string {
    const div = document.createElement('div');
    div.textContent = text;
    return div.innerHTML;
  }

  static formatFileSize(bytes: number): string {
    if (bytes === 0) return '0 Bytes';
    const k = 1024;
    const sizes = ['Bytes', 'KB', 'MB', 'GB'];
    const i = Math.floor(Math.log(bytes) / Math.log(k));
    return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
  }

  static getHtmlOutput(blocks: IBlock[]): string {
    return blocks.map(block => {
      // Check if content already contains HTML formatting
      const content = block.content.includes('<') && block.content.includes('>') 
        ? block.content // Already contains HTML formatting
        : this.escapeHtml(block.content);
      
      switch (block.type) {
        case 'paragraph':
          return block.content ? `<p>${content}</p>` : '';
        case 'heading-1':
          return `<h1>${content}</h1>`;
        case 'heading-2':
          return `<h2>${content}</h2>`;
        case 'heading-3':
          return `<h3>${content}</h3>`;
        case 'quote':
          return `<blockquote>${content}</blockquote>`;
        case 'code':
          return `<pre><code>${this.escapeHtml(block.content)}</code></pre>`;
        case 'list':
          const items = block.content.split('\n').filter(item => item.trim());
          if (items.length > 0) {
            const listTag = block.metadata?.listType === 'ordered' ? 'ol' : 'ul';
            // Don't escape HTML in list items to preserve formatting
            return `<${listTag}>${items.map(item => `<li>${item}</li>`).join('')}</${listTag}>`;
          }
          return '';
        case 'divider':
          return '<hr>';
        case 'image':
          const imageUrl = block.metadata?.url;
          if (imageUrl) {
            const altText = this.escapeHtml(block.content || 'Image');
            return `<img src="${imageUrl}" alt="${altText}" />`;
          }
          return '';
        case 'youtube':
          const videoId = block.metadata?.videoId;
          if (videoId) {
            return `<iframe width="560" height="315" src="https://www.youtube.com/embed/${videoId}" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>`;
          }
          return '';
        case 'markdown':
          // Return the raw markdown content wrapped in a div
          return `<div class="markdown-content">${this.escapeHtml(block.content)}</div>`;
        case 'html':
          // Return the raw HTML content (already HTML)
          return block.content;
        case 'attachment':
          const files = block.metadata?.files || [];
          if (files.length > 0) {
            return `<div class="attachments">${files.map((file: any) => 
              `<div class="attachment-item" data-file-id="${file.id}">
                <a href="${file.data}" download="${file.name}">${this.escapeHtml(file.name)}</a>
                <span class="file-size">(${this.formatFileSize(file.size)})</span>
              </div>`
            ).join('')}</div>`;
          }
          return '';
        default:
          return `<p>${content}</p>`;
      }
    }).filter(html => html !== '').join('\n');
  }

  static getMarkdownOutput(blocks: IBlock[]): string {
    return blocks.map(block => {
      switch (block.type) {
        case 'paragraph':
          return block.content;
        case 'heading-1':
          return `# ${block.content}`;
        case 'heading-2':
          return `## ${block.content}`;
        case 'heading-3':
          return `### ${block.content}`;
        case 'quote':
          return `> ${block.content}`;
        case 'code':
          return `\`\`\`\n${block.content}\n\`\`\``;
        case 'list':
          const items = block.content.split('\n').filter(item => item.trim());
          if (block.metadata?.listType === 'ordered') {
            return items.map((item, index) => `${index + 1}. ${item}`).join('\n');
          } else {
            return items.map(item => `- ${item}`).join('\n');
          }
        case 'divider':
          return '---';
        case 'image':
          const imageUrl = block.metadata?.url;
          const altText = block.content || 'Image';
          return imageUrl ? `![${altText}](${imageUrl})` : '';
        case 'youtube':
          const videoId = block.metadata?.videoId;
          const url = block.metadata?.url || (videoId ? `https://youtube.com/watch?v=${videoId}` : '');
          return url ? `[YouTube Video](${url})` : '';
        case 'markdown':
          // Return the raw markdown content
          return block.content;
        case 'html':
          // Return as HTML comment in markdown
          return `<!-- HTML Block\n${block.content}\n-->`;
        case 'attachment':
          const files = block.metadata?.files || [];
          if (files.length > 0) {
            return files.map((file: any) => `- [${file.name}](${file.data})`).join('\n');
          }
          return '';
        default:
          return block.content;
      }
    }).filter(md => md !== '').join('\n\n');
  }

  static parseHtmlToBlocks(html: string): IBlock[] {
    const parser = new DOMParser();
    const doc = parser.parseFromString(html, 'text/html');
    const blocks: IBlock[] = [];
    
    const processNode = (node: Node) => {
      if (node.nodeType === Node.TEXT_NODE && node.textContent?.trim()) {
        blocks.push({
          id: `block-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`,
          type: 'paragraph',
          content: node.textContent.trim(),
        });
      } else if (node.nodeType === Node.ELEMENT_NODE) {
        const element = node as Element;
        const tagName = element.tagName.toLowerCase();
        
        switch (tagName) {
          case 'p':
            blocks.push({
              id: `block-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`,
              type: 'paragraph',
              content: element.innerHTML || '',
            });
            break;
          case 'h1':
            blocks.push({
              id: `block-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`,
              type: 'heading-1',
              content: element.innerHTML || '',
            });
            break;
          case 'h2':
            blocks.push({
              id: `block-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`,
              type: 'heading-2',
              content: element.innerHTML || '',
            });
            break;
          case 'h3':
            blocks.push({
              id: `block-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`,
              type: 'heading-3',
              content: element.innerHTML || '',
            });
            break;
          case 'blockquote':
            blocks.push({
              id: `block-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`,
              type: 'quote',
              content: element.innerHTML || '',
            });
            break;
          case 'pre':
          case 'code':
            blocks.push({
              id: `block-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`,
              type: 'code',
              content: element.textContent || '',
            });
            break;
          case 'ul':
          case 'ol':
            const listItems = Array.from(element.querySelectorAll('li'));
            // Use innerHTML to preserve formatting
            const content = listItems.map(li => li.innerHTML || '').join('\n');
            blocks.push({
              id: `block-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`,
              type: 'list',
              content: content,
              metadata: { listType: tagName === 'ol' ? 'ordered' : 'bullet' }
            });
            break;
          case 'hr':
            blocks.push({
              id: `block-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`,
              type: 'divider',
              content: ' ',
            });
            break;
          case 'img':
            const imgElement = element as HTMLImageElement;
            blocks.push({
              id: `block-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`,
              type: 'image',
              content: imgElement.alt || '',
              metadata: { url: imgElement.src }
            });
            break;
          default:
            // Process children for other elements
            element.childNodes.forEach(child => processNode(child));
        }
      }
    };
    
    doc.body.childNodes.forEach(node => processNode(node));
    return blocks;
  }

  static parseMarkdownToBlocks(markdown: string): IBlock[] {
    const lines = markdown.split('\n');
    const blocks: IBlock[] = [];
    let currentListItems: string[] = [];
    
    for (let i = 0; i < lines.length; i++) {
      const line = lines[i];
      
      if (line.startsWith('# ')) {
        blocks.push({
          id: `block-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`,
          type: 'heading-1',
          content: line.substring(2),
        });
      } else if (line.startsWith('## ')) {
        blocks.push({
          id: `block-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`,
          type: 'heading-2',
          content: line.substring(3),
        });
      } else if (line.startsWith('### ')) {
        blocks.push({
          id: `block-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`,
          type: 'heading-3',
          content: line.substring(4),
        });
      } else if (line.startsWith('> ')) {
        blocks.push({
          id: `block-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`,
          type: 'quote',
          content: line.substring(2),
        });
      } else if (line.startsWith('```')) {
        const codeLines: string[] = [];
        i++;
        while (i < lines.length && !lines[i].startsWith('```')) {
          codeLines.push(lines[i]);
          i++;
        }
        blocks.push({
          id: `block-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`,
          type: 'code',
          content: codeLines.join('\n'),
        });
      } else if (line.match(/^(\*|-) /)) {
        currentListItems.push(line.substring(2));
        // Check if next line is not a list item
        if (i === lines.length - 1 || (!lines[i + 1].match(/^(\*|-) /))) {
          blocks.push({
            id: `block-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`,
            type: 'list',
            content: currentListItems.join('\n'),
            metadata: { listType: 'bullet' }
          });
          currentListItems = [];
        }
      } else if (line.match(/^\d+\. /)) {
        currentListItems.push(line.replace(/^\d+\. /, ''));
        // Check if next line is not a numbered list item
        if (i === lines.length - 1 || (!lines[i + 1].match(/^\d+\. /))) {
          blocks.push({
            id: `block-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`,
            type: 'list',
            content: currentListItems.join('\n'),
            metadata: { listType: 'ordered' }
          });
          currentListItems = [];
        }
      } else if (line === '---' || line === '***' || line === '___') {
        blocks.push({
          id: `block-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`,
          type: 'divider',
          content: ' ',
        });
      } else if (line.match(/^!\[([^\]]*)\]\(([^\)]+)\)$/)) {
        // Parse markdown image syntax ![alt](url)
        const match = line.match(/^!\[([^\]]*)\]\(([^\)]+)\)$/);
        if (match) {
          blocks.push({
            id: `block-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`,
            type: 'image',
            content: match[1] || '',
            metadata: { url: match[2] }
          });
        }
      } else if (line.trim()) {
        blocks.push({
          id: `block-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`,
          type: 'paragraph',
          content: line,
        });
      }
    }
    
    return blocks;
  }
}