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');


let 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(dataSet) {
    ctx.initDataProvider( dataSet );
    countStdQ = Object.values(dataSet.standardQuestions).length;
    //console.log(ctx.dP)
    data = dataSet
    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 = require('request');//function(o, fn){fn(false, {body:JSON.stringify(require('../../data/mocked.json'))})};//
      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 options = {
          'method': 'GET',
          'url': 'https://api.new.local.vkusvill.testin.ru/api/admin/tag/',
          'headers': {}
        };
        request( options, function( error, response ){
          if( error ) throw new Error( error );
          var tags = JSON.parse( response.body );

          var options = {
            'method': 'GET',
            'url': 'https://api.new.local.vkusvill.testin.ru/api/admin/question/',
            'headers': {}
          };
          request( options, function( error, response ){
            if( error ) throw new Error( error );
            var questions = JSON.parse( response.body );

            var qCardHash = {};
            questions.forEach(function(q) {
              (qCardHash[q.card_info_id] || (qCardHash[q.card_info_id]=[])).push(q);
            });

            var mimicri = {
              tags: [],
              connections: [],
              products: {},
              components: {},
              standardQuestions: {}
            };
            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 ] = {
                    tags: card.tags.map( t => t.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
                  };
                } )
              }else if( category.type === 2 && !category.hidden ){
                category.cards.forEach( card => {
                  var base = {
                    category: card.category_id,
                    cardInfoID: card.id,
                    category_id: card.category_id
                  };
                  if(card.id in qCardHash){
                    qCardHash[card.id].forEach(q=>{
                      mimicri.standardQuestions[q.id] = Object.assign({
                        qID: q.id,
                        title: q.text,
                        multiple: q.type !== 'radio',
                        image: card.image,
                        answers: q.answers.map(a=>{
                          return {
                            "qID": q.id,
                            "title": a.text,
                            "correct": a.correct,
                            "id": a.id
                          };
                        })
                      }, base);

                    });
                   /* {
                      "id": 4,
                      "card_info_id": 480,
                      "text": "ДА?",
                      "image": null,
                      "type": "radio",
                      "created_at": "2020-03-04 20:32:05",
                      "updated_at": "2020-03-04 21:29:36",
                      "answers": [
                      {
                        "id": 99,
                        "question_id": 4,
                        "text": "Да",
                        "correct": true,
                        "created_at": "2020-03-04 20:32:44",
                        "updated_at": "2020-03-04 20:32:44"
                      },
                      {
                        "id": 100,
                        "question_id": 4,
                        "text": "Нет",
                        "correct": false,
                        "created_at": "2020-03-04 20:34:06",
                        "updated_at": "2020-03-04 20:34:06"
                      },
                      {
                        "id": 107,
                        "question_id": 4,
                        "text": "Мда",
                        "correct": true,
                        "created_at": "2020-03-04 21:29:03",
                        "updated_at": "2020-03-04 21:29:03"
                      },
                      {
                        "id": 108,
                        "question_id": 4,
                        "text": "Мнет",
                        "correct": false,
                        "created_at": "2020-03-04 21:29:05",
                        "updated_at": "2020-03-04 21:29:05"
                      },
                      {
                        "id": 113,
                        "question_id": 4,
                        "text": "TTT",
                        "correct": false,
                        "created_at": "2020-03-04 21:46:24",
                        "updated_at": "2020-03-04 21:46:24"
                      }
                    ],
                      "media": []
                    }*/
                  }
                } );

                /*
                category: 2
                qID: 2
                title: "С какого года на рынке компания "Избёнка"?"
                cardInfoID: 301
                multiple: false
                image: null
                answer_type: "текст"
                category_id: 2
                 */


              }
            } );
            //mimicri.standardQuestions = standardQuestions;
            //console.log(response.body);
            initCtx();
            theData = JSON.stringify( mimicri );
            ctx.setData( mimicri );
          });
        } );
      });
      return 'true';
    }

  },
  '/api/get/questions': {
    method: 'GET',
    summary: 'Get questions attached to standard card',
    options:{
      id: {required: true, description: 'Item ID', type: Number},
      category: {required: false, description: 'Item Category', type: Number},
      title: {required: false, description: 'Item Category', type: String}
    },
    fn: async function(args) {
      debugger
      ctx.probabilityRand
    }
  },
  '/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},
      category: {required: false, description: 'comma sepparated categories', type: String},
    },
    fn: async function(args, req, res) {
      await ctx.ready; const rand = ctx.rand, seeded = ctx.seeded;
      let useCategory = false,
        categoryHash = {};

      if(args.category){
        useCategory = true;
        categoryHash = args.category
          .split(',')
          .map(a=>a.trim())
          .reduce((s,c)=>{s[c]=1; return s}, {});

      }
      let error = false;
      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( (useCategory && !categoryHash[1]) || 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;

            if(useCategory){

              let possible = Object.values(data.standardQuestions)
                .map( ( q ) => ( { q, c: q.category_id, n: q.qID } ) )
                .filter( q => q.c in categoryHash )
                .filter( q => !(q.c +'.'+q.n in used) )
                .map( q => q.n );
              if(possible.length){
                r = rand( possible )
              }else{
                error = 'Not enough questions';
                break;
              }

            }else{
              do{
                r = rand( 1, countStdQ );
                let q = data.standardQuestions[ r ];
                if( q && !( q.category_id + '.' + q.qID in used ) )
                  break;
                counter++;
              }while( counter < 100 );
            }

            result = ctx.standardGenerator(()=>r);


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

        if(error)
          break;
        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 ){
    return 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;
  }
}