const test_stdout: string = `running 2 tests from ./src/auth/permission.test.ts
permission.test ... ok (14ms)
permission empty ... ok (16ms)
running 4 tests from ./src/auth/session.test.ts
Session ...
  set ... ok (14ms)
  delete ... ok (16ms)
ok (49ms)
Login Handler ...
  login with invalid format ... ok (15ms)
  login with invalid password ... ok (16ms)
  login ... ok (15ms)
  logout with no session ... ok (17ms)
  logout ... ok (16ms)
ok (94ms)
getSession ... ok (15ms)
getSession with invalid cookie ... ok (15ms)
running 1 test from ./src/auth/user.test.ts
user.createAdminUser ... ok (5ms)
running 4 tests from ./src/document/filedoc.test.ts
readDocFile ... ok (12ms)
readDocFile: not found ... ok (15ms)
readDocFile: invalid json ... ok (15ms)
saveDocFile ... ok (15ms)
running 3 tests from ./src/router/methodHandle.test.ts
methodHandle: basic methods ... ok (14ms)
methodHandle: not found ... ok (15ms)
methodHandle: options ... ok (17ms)
running 8 tests from ./src/router/route.test.ts
route: basic route ... ok (6ms)
route: double slash route ... ok (12ms)
route: double match ... ok (16ms)
route: test context ... ok (15ms)
route: test regex ... ok (15ms)
route: test not found ... ok (2ms)
route: encode_route ... ok (12ms)
route: router in router ... ok (15ms)
running 4 tests from ./src/rpc/chunk.test.ts
basic chunk operation ...
  create chunk ... ok (13ms)
  delete chunk ... ok (15ms)
  modify chunk ... ok (16ms)
  move chunk ... ok (16ms)
  invalid chunk operation ... ok (16ms)
ok (96ms)
test chunk notification operation ... ok (16ms)
test chunk conflict ... ok (15ms)
test chunk conflict resolve with history ... ok (32ms)
running 2 tests from ./src/rpc/doc.test.ts
handleDocumentMethod ... ok (5ms)
handleTagMethod ...
  setTag ... ok (9ms)
  getTag ... ok (16ms)
  conflict ... ok (16ms)
ok (58ms)
running 3 tests from ./src/rpc/share.test.ts
handleShareGetInfo ... ok (16ms)
handleShareDocMethod ... ok (2ms)
handleShareMethod with no existing share token ... ok (12ms)
running 1 test from ./src/server.test.ts
server rpc test ... ok (4s)
running 1 test from ./src/watcher/fswatcher.test.ts
WatchFilteredReadWriter ... ok (79ms)
running 1 test from ./src/watcher/readWriter.test.ts
QueueReadWriter ... ok (57ms)
running 1 test from ./src/watcher/util.test.ts
watcher util isHidden ... ok (5ms)

test result: ok. 35 passed (15 steps); 0 failed; 0 ignored; 0 measured; 0 filtered out (6s)
`;

interface TestStep{
    name: string;
    result: boolean;
    time: number;
}

interface TestResult{
    name: string;
    result: boolean;
    time: number;
    steps: TestStep[];
}

interface TestFiles{
    path: string;
    tests: TestResult[];
}

const lines = test_stdout.split("\n");
let cur = 0;

function getMs(time: string){
    if (time.endsWith("ms")){
        return parseInt(time.replace("ms", ""));
    }
    return parseInt(time.replace("s", "")) * 1000;
}

let testFiles: TestFiles[] = [];

function parseTest(): TestResult {
    const m = /^(.*) \.\.\.(.*)/.exec(lines[cur]);
    let steps: TestStep[] = []
    if(m){
        const name = m[1];
        const status = m[2];
        let result = status.includes("ok");
        let time = 0;
        if(status === ""){
            cur++;
            while(!lines[cur].startsWith("ok")){
                const s = /^  (.*) \.\.\. (.*) \((\d+m?s)\)/.exec(lines[cur]);
                if(!s){
                    console.log("unexpected line: " + lines[cur]);
                    Deno.exit(1);
                }
                const stepname = s[1];
                const stepstatus = s[2];
                const steptime = s[3];
                //console.log(`${name} ${stepname} ${stepstatus} ${steptime}`);
                steps.push({name: stepname, result: stepstatus.includes("ok"), time: getMs(steptime)});
                cur++;
            }
            result = lines[cur].startsWith("ok");
            time = getMs(lines[cur].match(/\d+m?s/)![0]);
        }
        else{
            time = getMs(status.match(/\d+m?s/)![0]);
        }
        //console.log(name, result, time);
        cur++;
        return {name, result, time, steps};
    }
    console.log("unexpected line: " + lines[cur]);
    Deno.exit(1);
}

while(cur < lines.length){
    const line = lines[cur];
    if(line === ""){
        cur++;
        break;
    }
    const m = /^running (\d+) tests? from (.+)/.exec(lines[cur]);
    if(m){
        const num = parseInt(m[1]);
        const file = m[2];
        //console.log(`${num} tests from ${file}`);
        cur++;
        let tests = [];
        for(let i = 0; i < num; i++){
            const test = parseTest();
            tests.push(test);
        }
        testFiles.push({path: file, tests});
    }
    else {
        console.log("%c unexpected : "+line,"color: red");
        break;
    }
    //console.log("endwith " + cur);
}

const lastResultRegex = /test result: (.*)\. (\d+) passed \((\d+) steps\); (\d+) failed; (\d+) ignored; (\d+) measured; (\d+) filtered out \((\d+m?s)\)/;
const mm = lastResultRegex.exec(lines[cur]);
if(!mm){
    console.log("unexpected line: " + lines[cur]);
    Deno.exit(1);
}
const mok = mm[1];
const numPassed = parseInt(mm[2]);
const numSteps = parseInt(mm[3]);
const numFailed = parseInt(mm[4]);
const numIgnored = parseInt(mm[5]);
const numMeasured = parseInt(mm[6]);
const numFiltered = parseInt(mm[7]);
const time = getMs(mm[8]);


import * as path from "https://deno.land/std@0.142.0/path/mod.ts";

let duration = 0;
//console.log(testFiles);
testFiles.forEach(file => {
    console.log(`### ${path.basename(file.path)}`);
    console.log(`| name | result | duration |`);
    console.log(`| ---- | ------ | -------- |`);
    file.tests.forEach(test => {
        if(test.steps.length > 0){
            test.steps.forEach(step => {
                console.log(`|${test.name + " : " + step.name} |${step.result ? "✅" : "❌"}|${step.time}ms|`);
                duration += step.time;
            });
        }
        else{
            console.log(`|${test.name}|${test.result ? "✅" : "❌"}|${test.time}ms|`);
            duration += test.time;
        }
    });
});

console.log(`### Total`);
console.log(`| name | passed | Steps | Failed | duration |`);
console.log(`| ---- | ------ | ----- | ------ | -------- |`);
console.log(`| ${mok} | ${numPassed} | ${numSteps} | ${numFailed} | ${duration}ms |`);