import { unified } from 'unified'
import remarkParse from 'remark-parse'
import remarkGfm from 'remark-gfm'
import remarkMath from 'remark-math'
import remarkRehype from 'remark-rehype'
import rehypeKatex from 'rehype-katex'
import rehypeRaw from 'rehype-raw'
import rehypeSanitize from 'rehype-sanitize'
import rehypeStringify from 'rehype-stringify'
import rehypePrettyCode from 'rehype-pretty-code'
import { defaultSchema, type Schema } from 'hast-util-sanitize'
import rehypeAbc from '~/lib/rehype-abc'
import rehypeMermaid from '~/lib/rehype-mermaid'
import rehypeFountain from '~/lib/rehype-fountain'
import rehypeFunctionPlot from '~/lib/rehype-functionplot'
import rehypeSpoiler from '~/lib/rehype-spoiler'
import rehypeIframely from '~/lib/rehype-iframely'
import remarkMentionsHashtags from '~/lib/remark-mentions-hashtags'
import type { Element } from 'hast'

// Create a custom sanitization schema that allows KaTeX elements
// This maintains security while allowing mathematical rendering
export const createSanitizeSchema = (): Schema => ({
  ...defaultSchema,
  // Allow KaTeX-specific MathML elements
  tagNames: [
    ...(defaultSchema.tagNames || []),
    // MathML elements used by KaTeX
    'math',
    'semantics', 
    'mrow',
    'mi',
    'mo',
    'mn', 
    'msup',
    'msub',
    'msubsup',
    'mfrac',
    'mover',
    'munder',
    'munderover',
    'annotation',
    // Additional MathML elements that might be needed
    'mspace',
    'mpadded',
    'mphantom',
    'mroot',
    'msqrt',
    // HTML elements for ABC notation
    'details',
    'summary',
    // Elements for syntax highlighting
    'code',
    'span',
    'data',
    // Elements for syntax highlighting
    'figure',
    'pre'
  ],
  attributes: {
    ...defaultSchema.attributes,
    // Allow KaTeX classes and limited style attributes
    '*': [
      ...(defaultSchema.attributes?.['*'] || []),
      'className',
      'role',
      'tabIndex'
    ],
    // Allow target/rel so remark-mentions-hashtags can open external links in a new tab
    // with rel="noopener noreferrer". Neither attribute can execute code; the real
    // security boundary for links is the href protocol allowlist below (http/https/mailto).
    a: [
      ...(defaultSchema.attributes?.a || []),
      'target',
      'rel',
    ],
    math: ['xmlns'],
    annotation: ['encoding'],
    // Combined span attributes for KaTeX, syntax highlighting, and spoilers
    span: [
      ...(defaultSchema.attributes?.span || []),
      ['style', /^(?!.*javascript:).*$/], // For KaTeX positioning and syntax highlighting, block javascript: URLs
      ['className', /^([\w\s-]+|spoiler-text|blur)$/], // For syntax highlighting tokens and spoiler text
      'dataLine', // Allow data-line for line highlighting
      'dataSpoilerId' // Allow spoiler identifier
    ],
    // Allow data attributes used by KaTeX, ABC notation, Mermaid, Fountain, Function Plot, and Iframely
    div: [
      ...(defaultSchema.attributes?.div || []),
      ['className', /^(katex|math|abc-notation|mermaid-diagram|fountain-screenplay|function-plot|iframely-embed)/], // Allow katex/math/abc/mermaid/fountain/functionplot/iframely related classes
      'dataAbcNotation', // Allow ABC notation data
      'dataAbcId', // Allow ABC notation IDs
      'dataMermaidCode', // Allow Mermaid code data
      'dataMermaidId', // Allow Mermaid diagram IDs
      'dataFountainCode', // Allow Fountain screenplay code data
      'dataFountainId', // Allow Fountain screenplay IDs
      'dataFunctionPlotCode', // Allow Function Plot code data
      'dataFunctionPlotId', // Allow Function Plot IDs
      'dataFunctionPlotWidth', // Allow Function Plot width configuration
      'dataFunctionPlotHeight', // Allow Function Plot height configuration
      'dataFunctionPlotXMin', // Allow Function Plot x-axis minimum
      'dataFunctionPlotXMax', // Allow Function Plot x-axis maximum
      'dataFunctionPlotYMin', // Allow Function Plot y-axis minimum
      'dataFunctionPlotYMax', // Allow Function Plot y-axis maximum
      'dataFunctionPlotGrid', // Allow Function Plot grid configuration
      'dataEmbedUrl', // Allow embed URL data
      'dataEmbedId', // Allow embed IDs
      'dataEmbedWidth', // Allow embed width configuration
      'dataEmbedHeight', // Allow embed height configuration
      'id' // Allow IDs for ABC, Mermaid, Fountain, Function Plot, and Iframely containers
    ],
    details: [
      ...(defaultSchema.attributes?.details || []),
      ['className', /^(abc-notation|mermaid-diagram|fountain-screenplay|function-plot)/] // Allow ABC notation, Mermaid, Fountain, and Function Plot details
    ],
    summary: [
      ...(defaultSchema.attributes?.summary || []),
      ['className', /^[\w\s-]+$/] // Allow summary classes
    ],
    code: [
      ...(defaultSchema.attributes?.code || []),
      ['className', /^language-[\w\s-]+$/], // Allow language- classes for code blocks
      'style', // Allow inline styles for syntax highlighting
      'dataLanguage', // Allow language specification
      'dataTheme', // Allow theme specification
      'dataLine', // Allow line highlighting
      'dataLineNumbers' // Allow line numbering
    ],
    // Allow pre element attributes for copy button positioning
    pre: [
      ...(defaultSchema.attributes?.pre || []),
      ['className', /^[\w\s-]+$/], // Allow classes for theming
      'tabindex', // Allow tabindex for accessibility
      'dataLanguage', // Allow language specification
      'dataTheme', // Allow theme specification
      ['style', /^(?!.*javascript:).*$/] // Allow background-color and other styles from theme, block javascript: URLs
    ],
    // Allow figure wrapper for rehype-pretty-code
    figure: [
      ['className', /^[\w\s-]+$/], // Allow classes
      'dataRehypePrettyCodeFigure' // Allow rehype-pretty-code figure wrapper
    ]
  },
  // Remove dangerous protocols
  protocols: {
    ...defaultSchema.protocols,
    href: ['http', 'https', 'mailto'], // Only allow safe link protocols
    src: ['http', 'https', 'blob'] // blob: allowed for local image preview before upload
  }
})

// Create the unified processor with security - only $$ math syntax
export const createMarkdownProcessor = (theme?: 'light' | 'dark') => {
  const sanitizeSchema = createSanitizeSchema()
  
  // Temporary workaround: some plugins bring incompatible TypeScript overloads
  // for the unified Processor type (different plugin packages can depend on
  // different unified major versions). Casting to `any` silences the TS error
  // while keeping runtime behavior the same. Recommended: align unified/remark/rehype
  // package major versions in package.json and reinstall to remove this cast.
  return (unified() as any) // eslint-disable-line @typescript-eslint/no-explicit-any
    .use(remarkParse)
    .use(remarkGfm)
    .use(remarkMentionsHashtags)
    .use(remarkMath, {
      // Only allow $$ syntax, disable $ syntax
      singleDollarTextMath: false
    })
    .use(remarkRehype, { allowDangerousHtml: true }) // Still needed for KaTeX and ABC
    .use(rehypeKatex, {
      // Let rehype-katex automatically determine display mode from the math node type
    })
    .use(rehypeAbc, {
      // Configure ABC notation rendering options
      responsive: 'resize',
      staffwidth: 740,
      scale: 1.0
    })
    .use(rehypeMermaid, {
      // Configure Mermaid diagram rendering options
      theme: 'default'
    })
    .use(rehypeFountain, {
      // Configure Fountain screenplay rendering options
      // Using fountain-js defaults for now
    })
    .use(rehypeFunctionPlot, {
      // Configure Function Plot rendering options
      width: 800,
      height: 400,
      xDomain: [-10, 10],
      yDomain: [-10, 10],
      grid: true
    })
    .use(rehypeIframely, {
      // Configure Iframely embed rendering options
      width: 444,
      height: 250,
      maxEmbedsPerDoc: 10,
      performanceThreshold: 1000
    })
    .use(rehypeSpoiler)
    .use(rehypePrettyCode, {
      theme: theme === 'light' ? 'github-light-default' : 'github-dark-default', // Conditional theme based on system preference https://shiki.style/themes
      keepBackground: true, // Keep the theme's background color
      defaultLang: 'plaintext', // Default language for unmarked code blocks
      onVisitLine(node: Element) { // Customize the line number display
        if (node.children.length === 0) {
          node.children = [{ type: 'text', value: ' ' }]
        }
      }
    })
    .use(rehypeRaw) // Process raw HTML (needed for KaTeX, ABC, Mermaid, Fountain, and Function Plot output)
    .use(rehypeSanitize, sanitizeSchema) // Sanitize after KaTeX, ABC, Mermaid, Fountain, and Function Plot processing
    .use(rehypeStringify)
}

// Simple approach: convert math in standalone paragraphs to display math
export const fixBlockMath = (htmlString: string) => {
  // Convert paragraphs that contain only KaTeX to display math
  // This covers the most common use case where math on its own line should be centered
  return htmlString.replace(
    /<p>\s*(<span class="katex"><span class="katex-mathml">.*?<\/span><span class="katex-html".*?<\/span><\/span>)\s*<\/p>/g,
    '<div class="math-display-wrapper block text-center my-6 p-4 bg-gray-50 dark:bg-gray-800 rounded-lg border border-gray-200 dark:border-gray-700 text-xl">$1</div>'
  )
}


// Process markdown to HTML
export const processMarkdown = async (markdownText: string, theme?: 'light' | 'dark'): Promise<string> => {
  const processor = createMarkdownProcessor(theme)
  const result = await processor.process(markdownText)
  let htmlString = String(result)
  
  // Post-process to convert standalone math to display math
  htmlString = fixBlockMath(htmlString)
  
  
  return htmlString
}
