import fs from 'fs-extra'
import matter from 'gray-matter'
import path from 'path'
import c from 'picocolors'
import { findRegion } from '../markdown/plugins/snippet'
import { slash } from '../shared'

export function processIncludes(
  srcDir: string,
  src: string,
  file: string,
  includes: string[]
): string {
  const includesRE = /<!--\s*@include:\s*(.*?)\s*-->/g
  const regionRE = /(#[\w-]+)/
  const rangeRE = /\{(\d*),(\d*)\}$/

  return src.replace(includesRE, (m: string, m1: string) => {
    if (!m1.length) return m

    const range = m1.match(rangeRE)
    const region = m1.match(regionRE)

    const hasMeta = !!(region || range)

    if (hasMeta) {
      const len = (region?.[0].length || 0) + (range?.[0].length || 0)
      m1 = m1.slice(0, -len) // remove meta info from the include path
    }

    const atPresent = m1[0] === '@'

    try {
      const includePath = atPresent
        ? path.join(srcDir, m1.slice(m1[1] === '/' ? 2 : 1))
        : path.join(path.dirname(file), m1)
      let content = fs.readFileSync(includePath, 'utf-8')

      if (region) {
        const [regionName] = region
        const lines = content.split(/\r?\n/)
        const regionLines = findRegion(lines, regionName.slice(1))
        content = lines.slice(regionLines?.start, regionLines?.end).join('\n')
      }

      if (range) {
        const [, startLine, endLine] = range
        const lines = content.split(/\r?\n/)
        content = lines
          .slice(
            startLine ? parseInt(startLine, 10) - 1 : undefined,
            endLine ? parseInt(endLine, 10) : undefined
          )
          .join('\n')
      }

      if (!hasMeta && path.extname(includePath) === '.md') {
        content = matter(content).content
      }

      includes.push(slash(includePath))
      // recursively process includes in the content
      return processIncludes(srcDir, content, includePath, includes)

      //
    } catch (error) {
      if (process.env.DEBUG) {
        process.stderr.write(c.yellow(`\nInclude file not found: ${m1}`))
      }

      return m // silently ignore error if file is not present
    }
  })
}