import { compileMDX } from 'next-mdx-remote/rsc'
import matter from 'gray-matter'
import rehypeSlug from 'rehype-slug'
import rehypeAutolinkHeadings from 'rehype-autolink-headings'
import remarkGfm from 'remark-gfm'
import { parseFrontmatter, safeParseFrontmatter, type Frontmatter } from './frontmatter'

/**
 * MDX Compiler Utilities
 * 
 * Provides functions for compiling MDX content with custom components
 * and extracting frontmatter metadata
 */

export interface MDXCompileResult<TFrontmatter = Frontmatter> {
  content: React.ReactElement
  frontmatter: TFrontmatter
  headings: TableOfContentsItem[]
}

export interface TableOfContentsItem {
  id: string
  title: string
  level: number
}

export interface CompileMDXOptions {
  components?: Record<string, React.ComponentType<unknown>>
  scope?: Record<string, unknown>
  validateFrontmatter?: boolean
}

/**
 * Extract frontmatter from raw MDX content
 */
export function extractFrontmatter(source: string): { 
  content: string
  data: Record<string, unknown>
} {
  const { content, data } = matter(source)
  return { content, data }
}

/**
 * Extract headings from MDX content for table of contents
 */
export function extractHeadings(content: string): TableOfContentsItem[] {
  const headingRegex = /^(#{1,6})\s+(.+)$/gm
  const headings: TableOfContentsItem[] = []
  let match
  
  while ((match = headingRegex.exec(content)) !== null) {
    const level = match[1].length
    const title = match[2].trim()
    // Generate slug from title (same logic as rehype-slug)
    const id = title
      .toLowerCase()
      .replace(/[^a-z0-9]+/g, '-')
      .replace(/^-+|-+$/g, '')
    
    headings.push({ id, title, level })
  }
  
  return headings
}

/**
 * Compile MDX content with components and plugins
 */
export async function compileMDXContent<TFrontmatter = Frontmatter>(
  source: string,
  options: CompileMDXOptions = {}
): Promise<MDXCompileResult<TFrontmatter>> {
  const { components = {}, scope = {}, validateFrontmatter = true } = options
  
  // Extract frontmatter first
  const { content: mdxContent, data: rawFrontmatter } = extractFrontmatter(source)
  
  // Validate frontmatter if requested
  const frontmatter = validateFrontmatter 
    ? parseFrontmatter(rawFrontmatter) as TFrontmatter
    : rawFrontmatter as TFrontmatter
  
  // Extract headings for ToC
  const headings = extractHeadings(mdxContent)
  
  // Compile MDX
  const { content } = await compileMDX({
    source: mdxContent,
    components,
    options: {
      parseFrontmatter: false, // Already extracted
      mdxOptions: {
        remarkPlugins: [remarkGfm],
        rehypePlugins: [
          rehypeSlug,
          [rehypeAutolinkHeadings, { behavior: 'wrap' }],
        ],
      },
      scope: {
        ...scope,
        frontmatter,
      },
    },
  })
  
  return {
    content,
    frontmatter,
    headings,
  }
}

/**
 * Quick compile for previews (less validation)
 */
export async function quickCompileMDX(
  source: string,
  components: Record<string, React.ComponentType<unknown>> = {}
): Promise<{ content: React.ReactElement; frontmatter: Record<string, unknown> }> {
  const { content: mdxContent, data: frontmatter } = extractFrontmatter(source)
  
  const { content } = await compileMDX({
    source: mdxContent,
    components,
    options: {
      parseFrontmatter: false,
      mdxOptions: {
        remarkPlugins: [remarkGfm],
        rehypePlugins: [rehypeSlug],
      },
    },
  })
  
  return { content, frontmatter }
}

/**
 * Validate MDX content without compiling (for linting)
 */
export function validateMDXContent(source: string): {
  valid: boolean
  errors: string[]
  warnings: string[]
} {
  const errors: string[] = []
  const warnings: string[] = []
  
  try {
    const { data } = extractFrontmatter(source)
    
    // Check frontmatter
    const frontmatterResult = safeParseFrontmatter(data)
    if (!frontmatterResult) {
      errors.push('Invalid frontmatter format')
    }
    
    // Check for common issues
    if (!data.title) {
      warnings.push('Missing title in frontmatter')
    }
    
    if (!data.description) {
      warnings.push('Missing description in frontmatter (recommended for SEO)')
    }
    
  } catch (error) {
    errors.push(`Parse error: ${error instanceof Error ? error.message : 'Unknown error'}`)
  }
  
  return {
    valid: errors.length === 0,
    errors,
    warnings,
  }
}
