'use strict';
const assert = require('assert-plus');
const cheerio = require('cheerio');
const Encoder = require('node-html-encoder').Encoder;
const fs = require('fs-extra');
const path = require('canonical-path');
module.exports = function dabFactory(ngIoProjPath) {
    const encoder = new Encoder('entity');
    // Get the functionality we need from the dgeni package by the same name.
    const dartApiBuilderDgeniProjPath = 'tools/api-builder/dart-package';
    const dab = require(path.resolve(ngIoProjPath, dartApiBuilderDgeniProjPath)).module;
    const log = dab.logFactory[1]();
    const dartPkgConfigInfo = dab.dartPkgConfigInfo[1]();
    const preprocessDartDocData = dab.preprocessDartDocData[1](log, dartPkgConfigInfo);
    const loadDartDocDataProcessor = dab.loadDartDocDataProcessor[1](log, dartPkgConfigInfo, preprocessDartDocData);
    const apiListDataFileService = dab.apiListDataFileService[1](log, dartPkgConfigInfo);
    const Array_from = dab.arrayFromIterable[1];
    // Load API data, then create and save 'api-list.json'.
    function loadApiDataAndSaveToApiListFile() {
        const docs = [];
        loadDartDocDataProcessor.$process(docs);
        log.debug('Number of Dart API entries loaded:', docs.length);
        var libMap = apiListDataFileService.createDataAndSaveToFile(docs);
        for (let name in libMap) {
            log.debug('  ', name, 'has', libMap[name].length, 'top-level entries');
        }
        return docs;
    }
    // Create and save the container's '_data.json' file.
    function _createDirData(containerName, destDirPath, entries) {
        const entryNames = Array_from(entries.keys()).sort();
        const dataMap = Object.create(null);
        entryNames.map((n) => {
            const e = entries.get(n);
            assert.object(e, `entry named ${n}`);
            dataMap[path.basename(e.path, '.html')] = e;
        });
        const dataFilePath = path.resolve(destDirPath, '_data.json');
        fs.writeFile(dataFilePath, JSON.stringify(dataMap, null, 2));
        log.info(containerName, 'wrote', Object.keys(dataMap).length, 'entries to', dataFilePath);
    }
    function _adjustDocsRelativeLinks($, div) {
        // Omit leading https://angular.io so links work for local test sites.
        const urlToDocs = '/docs/dart/latest/';
        const urlToExamples = 'http://angular-examples.github.io/';
        const docsLinkList = div.find('a[href^="docs/"],a[href^="examples/"]');
        docsLinkList.each((i, elt) => {
            const href = $(elt).attr('href');
            const matches = href.match(/(\w+)\/(.*)$/);
            // TODO: support links to chapters of other languages, e.g., 'docs/ts/latest/...'.
            const urlStart = matches[1] === 'docs' ? urlToDocs : urlToExamples;
            const absHref = urlStart + matches[2];
            log.info(`Found angular.io relative link: ${href} --> ${absHref}`);
            $(elt).attr('href', absHref);
        });
    }
    function _insertExampleFragments(enclosedByName, eltId, $, div) {
        const fragDirBase = path.join(dartPkgConfigInfo.ngIoDartApiDocPath, '../../../_fragments/');
        const exList = div.find('p:contains("{@example")');
        exList.each((i, elt) => {
            const text = $(elt).text();
            log.debug(`Found example: ${enclosedByName} ${eltId}`, text);
            const matches = text.match(/^\s*{@example\s+([^\s]+)(\s+region=[\'\"]?([-\w]+)[\'\"]?)?\s*}([\s\S]*)$/);
            if (!matches) {
                log.warn(enclosedByName, eltId, 'has an invalidly formed @example tag:', text);
                return true;
            }
            // const [, exRelPath, /*regionTagAndValue*/, region, rest] = matches;
            const rest = matches[4].trim();
            if (rest) log.warn(enclosedByName, eltId, '@example must be the only element in a paragraph, but found:', text);
            const exRelPath = matches[1];
            const region = matches[3];
            let exRelPathParts = path.dirname(exRelPath).split(path.sep);
            let fragDir;
            if (exRelPathParts[0] === 'docs') {
                // Path is to a docs example, not an API example.
                const exampleName = exRelPathParts[1];
                fragDir = path.join(fragDirBase, exampleName, 'dart');
                exRelPathParts = exRelPathParts.slice(2);
            } else {
                fragDir = path.join(fragDirBase, '_api');
            }
            const extn = path.extname(exRelPath);
            const baseName = path.basename(exRelPath, extn);
            const fileNameNoExt = baseName + (region ? `-${region}` : '')
            const exFragPath = path.resolve(fragDir, ...exRelPathParts, `${fileNameNoExt}${extn}.md`);
            if (!fs.existsSync(exFragPath)) {
                log.warn('Fragment not found:', exFragPath);
                return true;
            }
            $(elt).empty();
            const md = fs.readFileSync(exFragPath, 'utf8');
            const codeElt = _extractAndWrapInCodeTags(md);
            $(elt).html(codeElt);
            log.silly('Fragment code in html:', $(elt).html());
        });
    }
    function _extractAndWrapInCodeTags(md) {
        const lines = md.split('\n');
        // Drop first and last lines that are the code markdown tripple ticks (and last \n):
        lines.shift();
        while (lines && lines.pop().trim() !== '```') {}
        const code = lines.map((line) => encoder.htmlEncode(line)).join('\n');
        // TS uses format="linenums"; removing that for now.
        return `