/**
 * Convert EditorJS JSON data to HTML
 * Supports: header, paragraph, list, image, quote, marker, embed, code, table, delimiter,
 * checklist, link, inlineCode, warning, alert, raw, personality, and more
 */

interface EditorJSBlockData {
  text?: string;
  level?: number;
  items?: string[] | Array<{ text?: string; checked?: boolean }>;
  style?: 'ordered' | 'unordered';
  file?: { url?: string };
  url?: string;
  caption?: string;
  withBorder?: boolean;
  withBackground?: boolean;
  stretched?: boolean;
  alignment?: 'left' | 'center' | 'right';
  service?: string;
  source?: string;
  embed?: string;
  width?: number;
  height?: number;
  code?: string;
  language?: string;
  content?: string[][];
  link?: string;
  meta?: { url?: string; title?: string; description?: string; image?: string };
  title?: string;
  message?: string;
  html?: string;
  htmlCode?: string;
  name?: string;
  description?: string;
  photo?: string;
  linkText?: string;
  linkUrl?: string;
  type?: string;
}

interface EditorJSBlock {
  id?: string;
  type: string;
  data: EditorJSBlockData;
}

interface EditorJSData {
  time?: number;
  blocks: EditorJSBlock[];
  version?: string;
}

/**
 * Convert EditorJS block to HTML
 */
function blockToHtml(block: EditorJSBlock, baseUrl?: string): string {
  const { type, data } = block;

  switch (type) {
    case 'header': {
      const level = data.level || 2;
      const text = escapeHtml(data.text || '');
      return `<h${level} style="margin:0 0 14px 0;">${text}</h${level}>`;
    }

    case 'paragraph': {
      let text = data.text || '';
      // Convert markdown-style links to HTML
      text = text.replace(
        /\[([^\]]+)\]\(([^)]+)\)/g,
        '<a href="$2">$1</a>'
      );
      // Convert **bold** to <strong>
      text = text.replace(/\*\*([^*]+)\*\*/g, '<strong>$1</strong>');
      // Convert *italic* to <em>
      text = text.replace(/\*([^*]+)\*/g, '<em>$1</em>');
      // Convert `inline code` to <code>
      text = text.replace(/`([^`]+)`/g, '<code>$1</code>');
      // Convert line breaks
      text = text.replace(/\n/g, '<br>');
      return `<p style="margin:0 0 14px 0;">${text}</p>`;
    }

    case 'list': {
      const items = data.items || [];
      const style = data.style || 'unordered';
      const tag = style === 'ordered' ? 'ol' : 'ul';
      const itemsHtml = items
        .map((item: { text?: string; checked?: boolean }) => {
          const escapedItem = escapeHtml(item.text || '');
          return `<li>${escapedItem}</li>`;
        })
        .join('');
      return `<${tag}>${itemsHtml}</${tag}>`;
    }

    case 'image': {
      const url = data.file?.url || data.url || '';
      const caption = data.caption || '';
      const withBorder = data.withBorder || false;
      const withBackground = data.withBackground || false;
      const stretched = data.stretched || false;

      let imageUrl = url;
      if (baseUrl && imageUrl && !imageUrl.startsWith('http')) {
        if (imageUrl.startsWith('/')) {
          imageUrl = `${baseUrl}${imageUrl}`;
        } else {
          imageUrl = `${baseUrl}/${imageUrl}`;
        }
      }

      const classes: string[] = [];
      if (withBorder) classes.push('with-border');
      if (withBackground) classes.push('with-background');
      if (stretched) classes.push('stretched');

      const classAttr =
        classes.length > 0 ? ` class="${classes.join(' ')} editorjs-image"` : ' class="editorjs-image"';

      const captionHtml = caption
        ? `<figcaption class="editorjs-image__caption" style="text-align:center;margin-top:0.5rem;margin-bottom:0;">${escapeHtml(caption)}</figcaption>`
        : '';

      return `<figure${classAttr} style="margin-top:1rem;margin-bottom:1rem;">
        <img src="${escapeHtml(imageUrl)}" alt="${escapeHtml(caption)}" style="display:block;margin-left:auto;margin-right:auto;" />
        ${captionHtml}
      </figure>`;
    }

    case 'quote': {
      const text = escapeHtml(data.text || '');
      const caption = escapeHtml(data.caption || '');
      const alignment = data.alignment || 'left';
      const captionHtml = caption ? `<cite>${caption}</cite>` : '';

      return `<blockquote class="quote-${alignment}">
        <p>${text}</p>
        ${captionHtml}
      </blockquote>`;
    }

    case 'marker': {
      const text = data.text || '';
      // Marker typically highlights text, so we'll use <mark>
      return `<mark>${escapeHtml(text)}</mark>`;
    }

    case 'embed': {
      const service = data.service || '';
      const embed = data.embed || '';
      const width = data.width || 600;
      const height = data.height || 400;
      const caption = data.caption || '';

      if (service === 'youtube' || service === 'vimeo') {
        const captionHtml = caption ? `<figcaption>${escapeHtml(caption)}</figcaption>` : '';
        return `<figure class="embed-${service}">
          <iframe src="${escapeHtml(embed)}" width="${width}" height="${height}" frameborder="0" allowfullscreen></iframe>
          ${captionHtml}
        </figure>`;
      }

      // Fallback for other embed types
      return `<div class="embed embed-${service}">
        ${embed}
        ${caption ? `<p class="embed-caption">${escapeHtml(caption)}</p>` : ''}
      </div>`;
    }

    case 'code': {
      const code = data.code || '';
      const language = data.language || '';
      const langAttr = language ? ` class="language-${language}"` : '';
      return `<pre><code${langAttr}>${escapeHtml(code)}</code></pre>`;
    }

    case 'delimiter': {
      return '<hr style="border:0;border-top:2px solid rgba(0,0,0,0.75);margin:16px 0;" />';
    }

    case 'table': {
      const content = data.content || [];
      if (content.length === 0) return '';

      // First row is usually header
      const headerRow = content[0] || [];
      const headerCells = headerRow
        .map((cell: string) => `<th>${escapeHtml(cell)}</th>`)
        .join('');

      // Rest are body rows
      const bodyRows = content.slice(1)
        .map((row: string[]) => {
          const cells = row
            .map((cell: string) => `<td>${escapeHtml(cell)}</td>`)
            .join('');
          return `<tr>${cells}</tr>`;
        })
        .join('');

      return `<table>
        ${headerCells ? `<thead><tr>${headerCells}</tr></thead>` : ''}
        <tbody>${bodyRows}</tbody>
      </table>`;
    }

    case 'checklist': {
      const items = data.items || [];
      const itemsHtml = items
        .map((item: { text?: string; checked?: boolean }) => {
          const text = escapeHtml(item.text || '');
          const checked = item.checked ? ' checked' : '';
          return `<div class="checklist-item">
            <input type="checkbox"${checked} disabled>
            <label>${text}</label>
          </div>`;
        })
        .join('');
      return `<div class="checklist">${itemsHtml}</div>`;
    }

    case 'linkTool':
    case 'link': {
      const link = data.link || data.url || '';
      const meta = data.meta || {};
      const title = meta.title || data.title || link;
      const description = meta.description || '';
      const image = meta.image || '';

      let imageHtml = '';
      if (image) {
        let imageUrl = image;
        if (baseUrl && imageUrl && !imageUrl.startsWith('http')) {
          imageUrl = imageUrl.startsWith('/') ? `${baseUrl}${imageUrl}` : `${baseUrl}/${imageUrl}`;
        }
        imageHtml = `<div class="link-image">
          <img src="${escapeHtml(imageUrl)}" alt="${escapeHtml(title)}" />
        </div>`;
      }

      return `<div class="link-block">
        <a href="${escapeHtml(link)}" target="_blank" rel="noopener noreferrer">
          ${imageHtml}
          <div class="link-content">
            <div class="link-title">${escapeHtml(title)}</div>
            ${description ? `<div class="link-description">${escapeHtml(description)}</div>` : ''}
            <div class="link-url">${escapeHtml(link)}</div>
          </div>
        </a>
      </div>`;
    }

    case 'inlineCode': {
      const code = data.text || '';
      return `<code class="inline-code">${escapeHtml(code)}</code>`;
    }

    case 'warning': {
      const title = data.title || 'Warning';
      const message = data.message || '';
      return `<div class="warning-block">
        <div class="warning-title">⚠️ ${escapeHtml(title)}</div>
        <div class="warning-message">${escapeHtml(message)}</div>
      </div>`;
    }

    case 'alert': {
      const type = data.type || 'info';
      const title = data.title || '';
      const message = data.message || '';
      return `<div class="alert alert-${type}">
        ${title ? `<div class="alert-title">${escapeHtml(title)}</div>` : ''}
        <div class="alert-message">${escapeHtml(message)}</div>
      </div>`;
    }

    case 'raw': {
      const html = data.html || data.htmlCode || '';
      // Return raw HTML (be careful with XSS)
      return html;
    }

    case 'personality': {
      const name = data.name || '';
      const description = data.description || '';
      const photo = data.photo || '';
      const linkText = data.linkText || '';
      const linkUrl = data.linkUrl || '';

      let photoHtml = '';
      if (photo) {
        let photoUrl = photo;
        if (baseUrl && photoUrl && !photoUrl.startsWith('http')) {
          photoUrl = photoUrl.startsWith('/') ? `${baseUrl}${photoUrl}` : `${baseUrl}/${photoUrl}`;
        }
        photoHtml = `<div class="personality-photo">
          <img src="${escapeHtml(photoUrl)}" alt="${escapeHtml(name)}" />
        </div>`;
      }

      const linkHtml = linkUrl && linkText
        ? `<a href="${escapeHtml(linkUrl)}" class="personality-link">${escapeHtml(linkText)}</a>`
        : '';

      return `<div class="personality-block">
        ${photoHtml}
        <div class="personality-content">
          <div class="personality-name">${escapeHtml(name)}</div>
          ${description ? `<div class="personality-description">${escapeHtml(description)}</div>` : ''}
          ${linkHtml}
        </div>
      </div>`;
    }

    default:
      // Unknown block type - return empty or log warning
      console.warn(`Unknown EditorJS block type: ${type}`);
      return '';
  }
}

/**
 * Escape HTML special characters
 */
function escapeHtml(text: string): string {
  const map: { [key: string]: string } = {
    '&': '&amp;',
    '<': '&lt;',
    '>': '&gt;',
    '"': '&quot;',
    "'": '&#039;',
  };

  return text.replace(/[&<>"']/g, (m) => map[m]);
}

/**
 * Convert EditorJS JSON data to HTML string
 * @param editorData - EditorJS JSON data (can be string or object)
 * @param baseUrl - Base URL for images (optional)
 * @returns HTML string
 */
export function editorjsToHtml(
  editorData: string | EditorJSData | null | undefined,
  baseUrl?: string
): string {
  if (!editorData) {
    return '';
  }

  // If it's a string, try to parse it as JSON
  let parsedData: EditorJSData;
  if (typeof editorData === 'string') {
    try {
      parsedData = JSON.parse(editorData);
    } catch {
      // If parsing fails, assume it's already HTML
      return editorData;
    }
  } else {
    parsedData = editorData;
  }

  // If it doesn't have blocks, assume it's already HTML
  if (!parsedData.blocks || !Array.isArray(parsedData.blocks)) {
    if (typeof editorData === 'string') {
      return editorData;
    }
    return '';
  }

  // Convert each block to HTML
  const htmlBlocks = parsedData.blocks
    .map((block) => blockToHtml(block, baseUrl))
    .filter((html) => html.length > 0);

  return htmlBlocks.join('\n');
}

/**
 * Check if content is EditorJS format
 */
export function isEditorJSFormat(
  content: string | EditorJSData | null | undefined
): boolean {
  if (!content) return false;

  try {
    const parsed =
      typeof content === 'string' ? JSON.parse(content) : content;
    return (
      parsed &&
      typeof parsed === 'object' &&
      Array.isArray(parsed.blocks) &&
      parsed.blocks.length > 0
    );
  } catch {
    return false;
  }
}
