const sources = [
  "js/releasable-observer.js",
  "js/pcg-base.js",
  "js/pcg-dom-util.js",

  "js/helpers/rand.js",

  "js/model/store.js",
  "js/model/data.js",

  "js/model/provider.js",
  "js/model/slice/productTable.js",

  "js/model/tag.js",
  "js/model/product.js",

  "js/helpers/textFilter.js",
  "js/helpers/answer.js",

  "js/controller/quizBits/main.js",

  "js/controller/quizGenerator.js",
  "js/controller/quizBits/checkbox.js",
  "js/controller/quizBits/checkboxPhoto.js",
  "js/controller/quizBits/radio.js",
  "js/controller/quizBits/radioPhoto.js",
  "js/controller/quizBits/seal.js"
];
const fs = require('fs'),
  path = require('path');
var js = sources.map(a=>path.join(__dirname,'../../public',a)).map(n=>fs.readFileSync(n)+'').join('\n\n');


const data = require("../../db.js");
const body = 'const window = {}, localStorage = {getItem:()=>"{}"};'+js+'; return {quizGenerator, standardGenerator, quizTypes, probabilityRand, initDataProvider, seeded: Math.random.seeded, rand, dP}';

var ctxCtor = new Function('',body);


var ctx;
var initCtx = function() {
  ctx = ctxCtor();
  ctx.ready = new Promise((r,j)=>{
    ctx._r = r;
  });
  ctx.setData = function(data) {
    ctx.initDataProvider( data );
    countStdQ = Object.values(data.standardQuestions).length;
    //console.log(ctx.dP)
    ctx._r();
  };
};
const normalizeText = function(text) {
  return (text+'').trim().toLowerCase().replace(/[^а-я]/g,'').replace(/[аоуеэюёиыя]+/g,'о')
};
initCtx();
let standardQuestions;
let subcats = {};
data.after = function(inComeData, skipInit){
  if( inComeData ){
    for(let i in inComeData.products){
      let cmp = inComeData.products[i];
      subcats[ normalizeText( cmp.title ) ] = cmp.subcat;
    }
    ctx.setData(theData=inComeData);
    standardQuestions = inComeData.standardQuestions;
    //firstRequest();
  }
};


let theData;
let countStdQ;
let firstRequest;
module.exports = {
  '/api/database/get': {
    method: 'GET',
    summary: 'Return the database',
    options: {},
    fn: async function(){
      await ctx.ready;
      return theData;
    }
  },
  '/api/database/update': {
    method: 'GET',
    summary: 'Reload data from https://api.new.local.vkusvill.testin.ru/api/admin/category/',
    options: {},
    fn: firstRequest = async function() {

      var request = function(o, fn){fn(false, {body:JSON.stringify(require('../../data/mocked.json'))})};//require('request');
      var options = {
        'method': 'GET',
        'url': 'https://api.new.local.vkusvill.testin.ru/api/admin/category/',
        'headers': {}
      };
      request(options, function (error, response) {
        if (error) throw new Error(error);
        var s = data,
          l = JSON.parse(response.body);
        var mimicri = {
          tags: [],
          connections: [],
          products: {},
          components: {}
        };
        var cmpID = 1;
        l.forEach(category=>{
          if(category.type === 1 && !category.hidden){
            category.cards.forEach(card=>{
              card.components.forEach(cmp=>{
                mimicri.components[cmpID++] = {
                  id: card.id,
                  iID: cmp.id,
                  name: cmp.name
                };
              });

              mimicri.products[card.id] = {
                "category_id": card.category_id,
                "id": card.id,
                "title": card.name,
                "description": card.text,
                "subcat": subcats[ normalizeText( card.name ) ],
                "use": card.is_test,
                "image": card.image === null ? void 0 : card.image,
                "type": card.type,
                "items": card.components.map(a=>a.id)
              };
            })
          }
        });
        mimicri.standardQuestions = standardQuestions
          //console.log(response.body);
        initCtx();
        theData = JSON.stringify(mimicri);
        ctx.setData(mimicri);

      });
      return 'true';
    }

  },
  '/api/generate/random': {
    method: 'GET',
    summary: 'Generate random quiz',
    options:{
      seed: {required: false, description: 'initialize random state. Make response determined', type: String},
      photo: {required: false, description: 'question with photo', type: Boolean},
      type: {required: false, description: '1 - products, 2 - standards', type: Number},
      nolog: {required: false, description: 'remove human readable log', type: Boolean},
      exclude: {required: false, description: 'remove human readable log', type: Array}
    },
    fn: async function(args) {
      await ctx.ready; const rand = ctx.rand, seeded = ctx.seeded;
      let seed = args.seed || Math.random().toString(36).substr(2);
      ctx.seeded.setStringSeed( seed );

      let option = ctx.probabilityRand([].concat.apply([],Object.values(ctx.quizTypes)))

      let multiple = option.multiple,//seeded() > 24 / ( 46 + 24 ),
          photo = option.photo, //seeded() > 0.7,
          result, attempts = 0;

      while(!result){
        if( ( args.type !== void 0 ? args.type === 2 : seeded() > 0.5 ) ){
          result = ctx.standardGenerator( () => rand( 1, countStdQ ) )
        }else{
          result = ctx.quizGenerator( multiple ? 'checkbox' : 'radio', args.photo !== void 0 ? args.photo : photo );
        }
        if(result && args.exclude){
          if(args.exclude.filter((a)=>a.categoryId === result.categoryId && a.productId === result.productId).length){
            attempts++;
            if(attempts < 20){
              result = false;
            }
          }
        }
      }

      console.log(`cat: ${result.categoryId}, prod: ${result.productId}, seed: ${seed}. ${result.question.substr(0,33)}`);

      if(args.nolog)
        delete result.log;

      return result;
    }
  },
  '/api/generate/random/sequence': {
    method: 'GET',
    summary: 'Generate list of random quizes',
    options:{
      count: {required: true, description: 'Count of generated questions', type: Number},
      seed: {required: false, description: 'initialize random state. Make response determined', type: String},
      photo: {required: false, description: 'question with photo', type: Boolean},
      type: {required: false, description: '1 - products, 2 - standards', type: Number},
      nolog: {required: false, description: 'remove human readable log', type: Boolean},
      stats: {required: false, description: 'aggregate stats and explain questions', type: Boolean},
      human: {required: false, description: 'aggregate stats and explain questions', type: Boolean}
    },
    fn: async function(args, req, res) {
      await ctx.ready; const rand = ctx.rand, seeded = ctx.seeded;

      let seed = args.seed || Math.random().toString(36).substr(2);
      ctx.seeded.setStringSeed( seed );
      let used = {}, generated = 0;
      let last = {c:-1},
        list = [],
        globalMaxTries = args.count*500,
        globalTries = 0;
      if(args.count>100)args.count = 100;
      while(generated<args.count && globalTries < globalMaxTries){
        globalTries++;

        let option = ctx.probabilityRand([].concat.apply([],Object.values(ctx.quizTypes)))

        let multiple = option.multiple,//seeded() > 24 / ( 46 + 24 ),
          photo = option.photo; //seeded() > 0.7

        let cur = {
          m: multiple,//seeded() > 24 / ( 46 + 24 ),
          p: photo,//seeded() > 0.7,
          c: 1
        };
        if( seeded() > 0.3 ){
        //if( last.c === 1 && seeded() > 0.5 ){
          cur = {
            c: 2
          };
          let id, tries = 0;
          /*do{
            id = rand(1, countStdQ);
            tries++;
            if(tries === 100){
              break;
            }
          }while('2.'+id in used);*/
          if(tries===100)
            continue;
          cur.id = id;
        }

        let tries = 0,
          result;
        do{
          if(cur.c === 1){
            result = ctx.quizGenerator( cur.m ? 'checkbox' : 'radio', cur.p );
          }else{
            let counter = 0, r = 2;
            do{
              r = rand( 1, countStdQ );
              let q = data.standardQuestions[ r ];
              if(q && !(q.category_id+'.'+q.qID in used))
                break;
              counter++;
            }while(counter < 100);
            debugger

            result = ctx.standardGenerator(()=>r);
            if(result)
            if(!result){
              tries = 100;
              break;
            }
          }
          tries++;
          if(tries === 100)
            break;
        }while(result.categoryId+'.'+result.productId in used || (cur.c>1 && result.categoryId === cur.c));
        if(tries !== 100){
          cur.c = result.categoryId;

          used[result.categoryId+'.'+result.productId] = true;
          list.push(result);
          if(args.nolog)
            delete result.log;
          last = cur;
          generated++;
          result.number = generated;
        }
      }

      if(args.stats){
        res.header("Content-Type", "text/html; charset=utf-8");
        let stats = {};
        let statsImage = {};
        let statsCategory = {};
        let statsType = {};

        list.forEach(i=>{
          if(i.categoryId === void 0)
            debugger;
          let key = i.type+', '+(i.image?'image':'no image')+', '+i.categoryId;
          stats[key] = (stats[key]||0)+1;

          key = i.type+'';
          statsType[key] = (statsType[key]||0)+1;

          key = (i.image?'image':'no image');
          statsImage[key] = (statsImage[key]||0)+1;

          key = i.categoryId+'';
          statsCategory[key] = (statsCategory[key]||0)+1;


        });
        return '<HTML><head></head><body>' +
          `<h2>Generated: ${list.length}</h2>` +
          '<div>'+Object.keys(stats).map(k=>`<b>${k}</b>: <span>${stats[k]}</span>`).join('<br/>')+'</div>'+
          '<h2>Image</h2><div>'+Object.keys(statsImage).map(k=>`<b>${k}</b>: <span>${statsImage[k]}</span>`).join('<br/>')+'</div>'+
          '<h2>Category</h2><div>'+Object.keys(statsCategory).map(k=>`<b>${k}</b>: <span>${statsCategory[k]}</span>`).join('<br/>')+'</div>'+
          '<h2>Type</h2><div>'+Object.keys(statsType).map(k=>`<b>${k}</b>: <span>${statsType[k]}</span>`).join('<br/>')+'</div>'+
          '</body></HTML>'
      }
      if(args.human){
        res.header("Content-Type", "text/html; charset=utf-8");
        return '<HTML><head>'+`<style>
.hidden {
display: none
}
.how-block {
white-space: pre-wrap;
    padding: 0 16px;
    border-left: 4px solid #ff0060;
}
.seed {color: #999}
.title {font-size:26px}
*{font-family: Verdana;}
pre {font-family: monospace;}
.how {color: #ff0060;border-bottom: 1px dotted;font-size:14px;cursor: pointer}
</style><script>var toggle=function(a){a.parentNode.parentNode.querySelector('.how-block').classList.toggle('hidden')}</script>`+'</head><body><div class="seed">seed: '+seed+'</div> ' +
          list.map((result, i)=>
          `<div class="quest"><div class="title">${i+1}) ${result.question} <span class="how" onclick="toggle(this)">Как так получилось?</span></div> 
<pre>${result.image?'<img height="100px" src="'+TRANSFORMER.IMAGE(result.image)+'" style="float: left"/>':''}
${ result.answers.map(a=>
            ( (result.type==='checkbox'?(a.correct?'[v]':'[ ]'):(a.correct?'(o)':'( )'))+ ' '+a.text)
          ).join('\n')}

</pre>
<pre class="how-block hidden">${result.log.join('\n')}</pre>
</div>
`
          ).join('<br/><br/>')+
          '</body></HTML>'


      }
      return list;
    }
  }
};

const TRANSFORMER = {
  IMAGE: function( image ){
    if( !image ){

    }else{
      image = image.trim();
      if( image.indexOf( '/upload/resize' ) === 0 ){
        image = 'https://vkusvill.ru' + image;
      }else{
        image = image ? 'https://api.new.local.vkusvill.testin.ru/storage' + image.trim() : void 0;
      }
    }
    return image;
  }
}