var fs = require("fs");
var path = require("path");

var remark = require("remark");
var stringify = require("remark-stringify");
var zone = require("mdast-zone");
var yaml = require("js-yaml");

var unist = require("../unistHelpers");
var ngHelpers = require("../ngHelpers");


module.exports = {
    "initPhase": initPhase,
    "readPhase": readPhase,
    "aggPhase": aggPhase,
    "updatePhase": updatePhase
}

var angFilenameRegex = /([a-zA-Z0-9\-]+)\.((component)|(directive)|(model)|(pipe)|(service)|(widget))\.ts/;
var searchFolderOmitRegex = /(config)|(mock)|(i18n)|(assets)|(styles)/;

var docsFolderPath = path.resolve("..", "docs");
var undocStoplistFileName = path.resolve(docsFolderPath, "undocStoplist.json");
var rootFolder = ".";
var indexMdFilePath = path.resolve(docsFolderPath, "README.md");
var guideSummaryFileName = path.resolve(docsFolderPath, "summary.json");

var maxBriefDescLength = 180;

var adfLibNames = ["core", "content-services", "insights", "process-services"];

var deprecatedIconURL = "docassets/images/DeprecatedIcon.png";
var experimentalIconURL = "docassets/images/ExperimentalIcon.png";


function initPhase(aggData) {
    aggData.stoplist = makeStoplist(undocStoplistFileName);    
    aggData.srcData = {};
    aggData.mdFileDesc = [];
    aggData.mdFileStatus = [];

    searchLibraryRecursive(aggData.srcData, path.resolve(rootFolder));

    //console.log(JSON.stringify(aggData.srcData));
}


function readPhase(tree, pathname, aggData) {
    var itemName = path.basename(pathname, ".md");

    // Look for the first paragraph in the file by skipping other items.
    // Should usually be a position 1 in the tree.
    var s;
    var briefDesc;

    if (tree.children[0].type == "yaml")
        s = 1;
    else
        s = 0;

    for (;
        (s < tree.children.length) && !unist.isParagraph(tree.children[s]);
        s++
    );

    if (s < tree.children.length) {
        briefDesc = tree.children[s];
    }

    aggData.mdFileDesc[itemName] = briefDesc;

    if (tree.children[0].type == "yaml") {
        var metadata = yaml.load(tree.children[0].value);
        var status = metadata["Status"];

        if (status) {
            var compName = path.basename(pathname, ".md");
            aggData.mdFileStatus[compName] = status;
        }

    }
}

function aggPhase(aggData) {
    var sections = prepareIndexSections(aggData);
    //console.log(JSON.stringify(sections));

    var indexFileText = fs.readFileSync(indexMdFilePath, "utf8");
    var indexFileTree = remark().parse(indexFileText);

    for (var l = 0; l < adfLibNames.length; l++) {

        var libName = adfLibNames[l];
        var libSection = sections[libName];
        
        var md = makeLibSectionMD(libSection);

        zone(indexFileTree, libName, (startComment, oldSection, endComment) => {
            md.unshift(startComment);
            md.push(endComment);
            return md;
        });
    }

    var guideSection = buildGuideSection(guideSummaryFileName);

    zone(indexFileTree, "guide", (startComment, oldSection, endComment) => {
        return [
            startComment, guideSection, endComment
        ]
    });

    fs.writeFileSync(path.resolve("..", "docs", "README.md"), remark().data("settings", {paddedTable: false}).stringify(indexFileTree));
    //fs.writeFileSync(indexMdFilePath, remark().stringify(indexFileTree));
    //fs.writeFileSync(path.resolve(".", "testJson.md"), JSON.stringify(indexFileTree));
}


function updatePhase(tree, pathname, aggData) {
    return false;
}


// Create a stoplist of regular expressions.
function makeStoplist(slFilePath) {
    var listExpressions = JSON.parse(fs.readFileSync(slFilePath, 'utf8'));
    
    var result = [];
    
    for (var i = 0; i < listExpressions.length; i++) {
        result.push(new RegExp(listExpressions[i]));
    }
    
    return result;
}

// Check if an item is covered by the stoplist and reject it if so.
function rejectItemViaStoplist(stoplist, itemName) {
    for (var i = 0; i < stoplist.length; i++) {
        if (stoplist[i].test(itemName)) {
            return true;
        }
    }
    
    return false;
}


//  Search source folders for .ts files to discover all components, directives, etc.
function searchLibraryRecursive(srcData, folderPath) {
    var items = fs.readdirSync(folderPath);
    
    for (var i = 0; i < items.length; i++) {
        var itemPath = path.resolve(folderPath, items[i]);
        var info = fs.statSync(itemPath);
        
        if (info.isFile() && (items[i].match(angFilenameRegex))) {
            var nameNoSuffix = path.basename(items[i], '.ts');
            
            var displayPath = itemPath.replace(/\\/g, '/');
            displayPath = displayPath.substr(displayPath.indexOf("lib") + 4);

            // Type == "component", "directive", etc.
            var itemType = nameNoSuffix.split('.')[1];
            
            srcData[nameNoSuffix] = { "path": displayPath, "type": itemType };            
        } else if (info.isDirectory() && !items[i].match(searchFolderOmitRegex)) {
            searchLibraryRecursive(srcData, itemPath);
        }
    }
}


function prepareIndexSections(aggData) {
    var srcNames = Object.keys(aggData.srcData);
    var sections = initEmptySections();

    for (var i = 0; i < srcNames.length; i++) {
        var itemName = srcNames[i];
        var srcData = aggData.srcData[itemName];
        var libName = srcData.path.substr(0, srcData.path.indexOf("/"));

        var briefDesc = aggData.mdFileDesc[itemName];

        var displayName = ngHelpers.ngNameToDisplayName(itemName);

        var status = "";

        if (aggData.mdFileStatus[itemName])
            status = aggData.mdFileStatus[itemName];

        if (briefDesc) {
            sections[libName][srcData.type].documented.push({
                "displayName": displayName,
                "mdName": itemName + ".md",
                "srcPath": srcData.path,
                "briefDesc": briefDesc,
                "status": status
            });
        } else if (!rejectItemViaStoplist(aggData.stoplist, itemName)) {
            sections[libName][srcData.type].undocumented.push({
                "displayName": displayName,
                "mdName": itemName + ".md",
                "srcPath": srcData.path
            });
        }
    }

    return sections;
}


function initEmptySections() {
    var result = {};

    for (var l = 0; l < adfLibNames.length; l++) {
        var lib = result[adfLibNames[l]] = {};

        for (var c = 0; c < ngHelpers.classTypes.length; c++) {
            var classType = lib[ngHelpers.classTypes[c]] = {};

            classType.undocumented = [];
            classType.documented = [];
        }
    }

    return result;
}


function buildMDDocumentedSection(docItems) {
    var listItems = [];

    for (var i = 0; i < docItems.length; i++) {
        listItems.push(makeMDDocumentedListItem(docItems[i]));
    }

    return unist.makeListUnordered(listItems);
}


function buildMDUndocumentedSection(docItems) {
    var listItems = [];

    for (var i = 0; i < docItems.length; i++) {
        listItems.push(makeMDUndocumentedListItem(docItems[i]));
    }

    return unist.makeListUnordered(listItems);
}


function buildMDDocumentedTable(docItems) {
    var rows = [
        
    ];
    
    for (var i = 0; i < docItems.length; i++) {
        rows.push(makeMDDocumentedTableRow(docItems[i]));
    }

    return rows;
    //return unist.makeTable([null, null, null, null], rows);
}


function buildMDUndocumentedTable(docItems) {
    var rows = [
       
    ];
    
    for (var i = 0; i < docItems.length; i++) {
        rows.push(makeMDUndocumentedTableRow(docItems[i]));
    }

    return rows;
    //return unist.makeTable([null, null, null, null], rows);
}


function makeMDDocumentedListItem(docItem) {
    var mdFileLink = unist.makeLink(unist.makeText(docItem.displayName), docItem.mdName);
    var srcFileLink = unist.makeLink(unist.makeText("Source"), "../lib/" + docItem.srcPath);
    var desc = docItem.briefDesc;

    var para = unist.makeParagraph([
        mdFileLink, unist.makeText(" ("), srcFileLink, unist.makeText(") "), desc 
    ]);

    return unist.makeListItem(para);
}


function makeMDUndocumentedListItem(docItem) {
    var itemName = unist.makeText(docItem.displayName);
    var srcFileLink = unist.makeLink(unist.makeText("Source"), "../lib/" + docItem.srcPath);

    var para = unist.makeParagraph([
       unist.makeText("* "), itemName, unist.makeText(" ("), srcFileLink, unist.makeText(")") 
    ]);

    return unist.makeListItem(para);
}


function makeMDDocumentedTableRow(docItem) {
    var mdFileLink = unist.makeLink(unist.makeText(docItem.displayName), docItem.mdName);
    var srcFileLink = unist.makeLink(unist.makeText("Source"), "../lib/" + docItem.srcPath);
    var desc = docItem.briefDesc;

    var linkCellItems = [mdFileLink];

    if (docItem.status) {
        if (docItem.status === "Deprecated") {
            linkCellItems.push(unist.makeText(" "));
            linkCellItems.push(unist.makeImage(deprecatedIconURL, "Deprecated"));
        } else if (docItem.status === "Experimental") {
            linkCellItems.push(unist.makeText(" "));
            linkCellItems.push(unist.makeImage(experimentalIconURL, "Experimental"));
        }
    }

    return unist.makeTableRow([
        unist.makeTableCell(linkCellItems),
        unist.makeTableCell([desc]),
        unist.makeTableCell([srcFileLink])
    ]);
}


function makeMDUndocumentedTableRow(docItem) {
    var itemName = unist.makeText(docItem.displayName);
    var srcFileLink = unist.makeLink(unist.makeText("Source"), "../lib/" + docItem.srcPath);

    return unist.makeTableRow([
        unist.makeTableCell([unist.makeEmphasis([itemName])]),
        unist.makeTableCell([unist.makeEmphasis([unist.makeText("Not currently documented")])]),
        unist.makeTableCell([srcFileLink])
    ]);
}


function makeLibSectionMD(libSection){
    var md = [];

    var libClassTypes = Object.keys(libSection);
    
    for (var i = 0; i < libClassTypes.length; i++) {
        var classType = libClassTypes[i];

        var classSection = libSection[classType];

        if (!classSection)
            continue;

        var displayNameNode;

        if ((classSection.documented.length > 0) || (classSection.undocumented.length > 0)) {
            displayNameNode = unist.makeText(ngHelpers.dekebabifyName(classType + "s"));
            md.push(unist.makeHeading(displayNameNode, 2));
        
            var tableRows = [
                unist.makeTableRow([
                    unist.makeTableCell([unist.makeText("Name")]),
                    unist.makeTableCell([unist.makeText("Description")]),
                    unist.makeTableCell([unist.makeText("Source link")])
                ])
            ];

            if (classSection.documented.length > 0) {
                //md.push(buildMDDocumentedSection(classSection.documented));
                tableRows = tableRows.concat(buildMDDocumentedTable(classSection.documented));
            }

            if (classSection.undocumented.length > 0) {
                // md.push(buildMDUndocumentedSection(classSection.undocumented));
                tableRows = tableRows.concat(buildMDUndocumentedTable(classSection.undocumented));
            }

            md.push(unist.makeTable([null, null, null, null], tableRows));
        }
    }

    return md;
}


function buildGuideSection(guideJsonFilename) {
    var summary = JSON.parse(fs.readFileSync(guideJsonFilename, "utf8"));

    var listItems = [];

    for (var i = 0; i < summary.length; i++) {
        var link = unist.makeLink(unist.makeText(summary[i].title), summary[i].file);
        listItems.push(unist.makeListItem(link));
    }

    return unist.makeListUnordered(listItems);
}