const { readFileSync, existsSync, readdirSync, statSync } = require('fs');
const { dirname, resolve, basename } = require('path');
const fetchCode = require('./fetchCode');

function parseIndent(text) {
  const lines = text.split(/\r?\n/).filter(Boolean);
  const root = {};
  const stack = [{ indent: -1, obj: root }];

  for (const line of lines) {
    const match = line.match(/^(\s*)([^:]+):?\s*(.*)$/);
    if (!match) continue;

    const indent = match[1].length;
    const key = match[2].trim();
    const value = match[3].trim();

    while (stack.length && indent <= stack[stack.length - 1].indent) {
      stack.pop();
    }

    const parent = stack[stack.length - 1].obj;

    if (value === '') {
      parent[key] = {};
      stack.push({ indent, obj: parent[key] });
    } else {
      parent[key] = isNaN(Number(value)) ? value : Number(value);
    }
  }

  return root;
}

const contentRegex = /---([\s\S]*?)---/;
const enusRegex = /(##\sen-US)(.*)/gms;
const contentAttrs = md => {
  const matches = md.match(contentRegex);
  if (matches && matches.length > 1 && matches[1]) {
    const attrsStr = matches[1];
    const attrs = parseIndent(attrsStr);
    return attrs;
  }
  return null;
};

const readDemo = dir => {
  const files = readdirSync(dir);
  const demos = files.reduce((acc, file) => {
    const filePath = resolve(dir, file);
    const state = statSync(filePath);
    if (state.isDirectory()) {
      return [...acc, ...readDemo(filePath)];
    } else if (state.isFile() && file.endsWith('.vue')) {
      const fileName = file.replace('.vue', '');
      const vueCode = readFileSync(filePath, 'utf-8');
      const docs = fetchCode(vueCode, 'docs')?.trim();
      const template = fetchCode(vueCode, 'template');
      const script = fetchCode(vueCode, 'script');
      const style = fetchCode(vueCode, 'style');
      const { order: originOrder, title = {} } = contentAttrs(docs) ?? {};
      let newDocs = docs.replace(contentRegex, '').replace(enusRegex, '');
      Object.keys(title).forEach(key => {
        if (newDocs.includes(key)) {
          const value = title[key];
          newDocs = newDocs.replace(key, value);
        }
      });
      const newContent = `${newDocs}
\`\`\`html
${template}
${script}
${style}
  \`\`\`
  `;
      return [
        ...acc,
        {
          filePath,
          content: newContent,
          fileName,
          order: originOrder ? Number(originOrder) : 0,
        },
      ];
    }
    return acc;
  }, []);

  return demos.sort((a, b) => a.order - b.order);
};

const transform = file => {
  let content = readFileSync(file, 'utf-8');
  const id = file.replace(process.cwd(), '');
  const fileName = basename(file);
  const dir = dirname(file);
  const demoDir = resolve(dir, 'demo');
  const attrs = contentAttrs(content) ?? {};
  const { title, category } = attrs;
  const uploadFileName = `${title ?? ''}${category ? `-${category}` : ''}`;

  let demo = [];
  if (existsSync(demoDir)) {
    demo = readDemo(demoDir);
  }

  const index = content.indexOf('## API');
  if (index > -1 && demo.length > 0) {
    const demoContent = demo.map(item => item.content).join('\n');
    content = content.slice(0, index) + demoContent + content.slice(index);
  }

  content = content.replace(contentRegex, '');

  return {
    content,
    id,
    fileName: uploadFileName || fileName.replace('.md', ''),
  };
};

module.exports = transform;
