const fs = require("fs");
const path = require("path");
const lodash = require("lodash");

const depts = {};

async function handle(filename) {
    if (path.extname(filename) !== ".js") {
        return;
    }
    const code = fs.readFileSync(filename).toString();
    
    const inheritRegResult = /BI\.(.*?)\s=\sBI\.inherit\(/.exec(code);
    if (inheritRegResult) {
        const clzName = inheritRegResult[1];
        depts[clzName] = filename;
    } else {
        // 一个文件夹里面可能有多个 xtype
        const reg = /export\s+class\s+(.*?)([\s|{])([\w\W]*?)static xtype\s?=\s?((["|'])(.*?)(\5))/g;
        Array.from(code.matchAll(reg)).forEach(res => {
            const xtype = res[4];
            depts[xtype] = {
                clzName: res[1],
                clzPath: filename,
            };
        });
        // 同时找一下 export
        if (path.basename(filename) !== "index.js") {
            const regs = [
                /export function (.*?)\(/g,
                /export const (.*?) =/g,
                /export class (.*?) /g,
                /export \{([\w\W]*?)\}/g,
            ];
            regs.forEach((reg, index) => {
                Array.from(code.matchAll(reg)).forEach(el => {
                    depts[el[1]] = filename;
                    if (index === 3) {
                        el[1].split(",").map(el => el.trim()).forEach(key => {
                            depts[key] = filename;
                        });
                    }
                });
            });
        }
    }
}

function isExist(filePath) {
    return fs.existsSync(filePath);
}

async function bfs(filename) {
    const stat = fs.statSync(filename);
    const isDir = stat.isDirectory();
    if (isDir) {
        const files = fs.readdirSync(filename);
        for (let i = 0; i < files.length; i++) {
            const file = files[i];
            await bfs(path.resolve(filename, file));
        }
    } else {
        await handle(filename);
    }
}

async function initDepts() {
    // dfs 构建依赖关系
    await bfs(path.resolve("src"));
    const m = {};
    lodash.forEach(depts, value => {
        if (typeof value === "object") {
            m[value.clzName] = value.clzPath;
        }
    });
    Object.assign(depts, m);
}


function search(src, module) {
    let clzName = module;
    let clzPath = depts[module];

    if (!depts[clzName]) {
        return "";
    }

    if (clzName.indexOf("\"") >= 0) {
        clzName = depts[module].clzName;
        clzPath = depts[module].clzPath;
    }

    const dstName = path.basename(clzPath).replace(/.js$/g, "");
    const dstPath = path.normalize(clzPath).split("src")[1].split("\\").join("/").split("/");
    const srcPath = path.normalize(src).split("src")[1].split("\\").join("/").split("/");

    // console.log("src", src);
    // console.log("dst", depts[clzName]);

    dstPath.shift();
    dstPath.pop();
    srcPath.shift();
    srcPath.pop();

    const findDstIndexPath = (dstArr, startIndex) => {
        let i = startIndex;

        while (!isExist(path.resolve("src", dstArr.slice(0, i + 1).join("/"), "index.js")) && i < dstArr.length) {
            i++;
        }
     
        if (i < dstArr.length) {
            return dstArr.slice(startIndex, i + 1).join("/");
        } else {
            return `${dstArr.slice(startIndex).join("/")}/${dstName}`;
        }
    };

    // 不同包
    if (dstPath[0] !== srcPath[0]) {
        return `@/${dstPath[0]}`;
    }

    // 同包
    let i = 0;
    while (dstPath[i] === srcPath[i] && i < dstPath.length && i < srcPath.length) {
       i++;
    }
    
    // i 代表同名的位置
    i--;

    // 没有匹配完
    if (i < srcPath.length) {
        let result = "";
         
        // 回溯,向上找,回到目录 i
        for (let j = srcPath.length - 1; j > i; j--) {
            result += "../";
        }
        
        // 匹配过的下一个位置
        i++;

        if (i >= dstPath.length) {
            // 越界
            return `${result}${dstName}`;
        } else {
            // 看看这个目录下有没有 index
            return result + findDstIndexPath(dstPath, i);
        }
    } else if (i === srcPath.length) {
        if (i === dstPath.length) {
            return dstName;
        } else if (i < dstPath.length) {
            return findDstIndexPath(dstPath, i);
        }
    }
}

// search(process.argv[2], "Text").then(res => {
//     console.log(res);
// });

exports.initDepts = initDepts;
exports.search = search;
exports.depts = depts;