const P = require('parsimmon');
const R = require('ramda');
// map functions
const mapToThirdArg = (_1, _2, _3) => _3;
const mapToRepo = (_1, _2, _3, _4, _5) => `${_1}/${_5}`;
const reduceNodeToObj = R.reduce((acc, x) => R.merge({ [x.name]: x.value })(acc), {});
const transForSentence = R.pipe(mapToThirdArg, reduceNodeToObj);
// atoms
const _ = P.whitespace;
const _o = P.optWhitespace;
const to = P.string('to');
const on = P.string('on');
const at = P.string('at');
const fr = P.string('for'); // TODO: alt `for`
const slash = P.string('/');
const command = P.regex(/post +build/i);
const digit = P.digit;
const letterSmall = P.range('a', 'z');
const letterLarge = P.range('A', 'Z');
const letter = P.alt(letterSmall, letterLarge);
const hex = P.alt(P.range('a', 'f'), digit);
const symbolForSep = P.oneOf('._-');
const symbolForBranch = P.oneOf('._-/#+');
// parameters
const username = P.alt(letter, digit, symbolForSep).many().tie();
const reponame = P.alt(letter, digit, symbolForSep).many().tie();
const branch = P.alt(letter, digit, symbolForBranch).many().tie();
const job = P.alt(letter, digit, symbolForSep).many().tie();
const repo = P.seqMap(username, _o, slash, _o, reponame, mapToRepo);
const revision = hex.many().tie();
// nodes
const nodeRepo = P.seqMap(to, _, repo, mapToThirdArg).node('repo');
const nodeJob = P.seqMap(fr, _, job, mapToThirdArg).node('job');
const nodeBranch = P.seqMap(on, _, branch, mapToThirdArg).node('branch');
const nodeRevision = P.seqMap(at, _, revision, mapToThirdArg).node('revision');
const node = P.alt(nodeRepo, nodeJob, nodeBranch, nodeRevision);
const sentence = P.seqMap(command, _, node.sepBy(_), transForSentence);