//Unlock all numbers challenge
//rename quiz to quizReactor? Maybe make it a collection to log quizes?
//Weeding challenges
//What if user runs out of chars/phrases to unlock for challenges?

var Backbone, _, langData, quiz, langData, synchronousEach, toast, mySeeds, myPhrasesOwned, myGameState, myTransactions;

var challengeScript = (function(){
  var plantChars = function(steps, extraP){
    return {
      type : 'char', steps: steps, extraP: extraP
    };
  };
  var plantPhrases = function(steps, extraP){
    return {
      type : 'phrase', steps: steps, extraP: extraP
    };
  };
  var bChain = function(extraP){
    return {
      type : 'bChain', steps: 1, extraP: extraP
    };
  };
  var charUnlock = function(steps, extraP){
    return {
      type : 'charUnlock', steps: steps, extraP: extraP
    };
  };
  var phraseUnlock = function(steps, extraP){
    return {
      type : 'phraseUnlock', steps: steps, extraP: extraP
    };
  };
  var bucketOfGold = function(){
    return {
      type : 'bucketOfGold', steps: 1, extraP: 1
    };
  };
  return [
    [plantChars(4, 1), phraseUnlock(2, 2), charUnlock(4, 1)],
    [bChain(2), charUnlock(4, 2), plantPhrases(2, 2)],
    [plantChars(4,2), charUnlock(3, 2), charUnlock(3, 1), phraseUnlock(3, 2)],
    [plantPhrases(4, 2), charUnlock(4, 3), bChain(2)],
    [phraseUnlock(2, 3), plantPhrases(5, 2), bChain(2)],
    [phraseUnlock(2, 3), charUnlock(4, 4), plantPhrases(4, 3), bChain(3)],
    [plantChars(10, 3), plantPhrases(3, 3), charUnlock(4, 4)],
    //Require count to 10 here?
    [plantChars(12, 3), plantChars(3, 4), charUnlock(5, 3)],
    [plantPhrases(16, 2), phraseUnlock(4, 2), charUnlock(4, 4)],
    [plantChars(8, 4), phraseUnlock(2, 4), bChain(3)],
    [plantChars(16, 3), charUnlock(4, 3), bChain(3)],
    [bChain(4), phraseUnlock(6, 3), charUnlock(4, 5)],
    [plantChars(16, 2), plantPhrases(12, 3), charUnlock(6, 4), charUnlock(2, 6)],
    [plantChars(8, 6), charUnlock(6, 6), phraseUnlock(4, 4)],
    [plantPhrases(6, 4), bChain(5)],
    [plantChars(8, 7), charUnlock(4, 7)],
    [plantPhrases(16, 3), plantPhrases(8, 4), bChain(6)],
    [bucketOfGold()],
    [{type : 'lastChallenge', steps: 1, extraP: 1}]
  ];
})();

var challengeTypes = {
  //TODO: not sure that if I should require individual flowers
  'char': {
    challengeInit: function() {
      var that = this;
      quiz.on('pass', function self(bouquet) {
        var qualifyingChars = _.filter(bouquet, function(seed){
          return langData.spHash[seed.get('spid')].tier === that.get('extraP');
        });
        that.incrementStep(qualifyingChars.length);
        if (that.isAchieved()) {
          quiz.off('pass', self);
        }
      });
    },
    messageTemplate: 'Sell <%- steps %> character-flowers that take <%- Math.pow(2, extraP) %> minutes to bloom'
  },
  'phrase': {
    challengeInit: function() {
      var that = this;
      quiz.on('pass', function self(bouquet) {
        if (bouquet.length !== that.get('extraP')) return;
        that.incrementStep(1);
        if (that.isAchieved()) {
          quiz.off('pass', self);
        }
      });
    },
    messageTemplate: 'Sell <%- steps %> phrase-bouquets with <%- extraP %> character-flowers'
  },
  'charUnlock': {
    challengeInit: function() {
      var that = this;
      mySeeds.on('add', function self(seed) {
        console.log(JSON.stringify(langData.spHash[seed.get('spid')]));
        if( langData.spHash[seed.get('spid')].tier !== that.get('extraP')) return;
        that.incrementStep(1);
        if (that.isAchieved()) mySeeds.off('add', self);
      });
    },
    messageTemplate: 'Unlock <%- steps %> character-flowers that take <%- Math.pow(2, extraP) %> minutes to bloom'
  },
  'phraseUnlock': {
    challengeInit: function() {
      var that = this;
      myPhrasesOwned.on('add', function self(phrase) {
        if(phrase.get('spid').length !== that.get('extraP')) return;
        that.incrementStep(1);
        if (that.isAchieved()) myPhrasesOwned.off('add', self);
      });
    },
    messageTemplate: 'Buy <%- steps %> phrases with <%- extraP %> characters'
  },
  'bChain': {
    challengeInit: function() {
      var that = this;
      quiz.on('allPass', function self(bouquets) {
        if (bouquets.length < that.get('extraP')) return;
        that.incrementStep(1);
        if (that.isAchieved()) {
          quiz.off('allPass', self);
        }
      });
    },
    rewardMultiplier: 60,
    messageTemplate: 'Sell a <%- extraP %> phrase bouquet chain'
  },
  'bucketOfGold': {
    challengeInit: function() {
      var that = this;
      myTransactions.on('add', function self(bouquets) {
        if (myTransactions.currentBalance() < 1000000) return;
        that.incrementStep(1);
        if (that.isAchieved()) {
          myTransactions.off('add', self);
          $( "#complete-popup" ).popup("open");
        }
      });
    },
    rewardMultiplier: 100000,
    messageTemplate: 'Earn your first bucket of gold (1,000,000 元)'
  },
  'lastChallenge': {
    //This challenge cannot be completed
    challengeInit: function() {}
  }
};
var Challenge = Backbone.Model.extend({
  activate: function(options) {
    var type = this.get('type');
    var that = this;
    _.extend(this, challengeTypes[type]);
    this.message = _.template(this.messageTemplate, this.toJSON());
    
    if(this.isAchieved()) return;
    
    this.challengeInit();
    
    this.on('change:step', function(){
      console.log('change:step');
      if(that.isAchieved()) {
        window.setTimeout(function(){
          toast({
            theme : 'e',
            click : function(){
              $('#challenges').panel('open');
              $(this).remove();
            },
            html: '<p><b>Challenge completed!</b></p>',
            css: {
              top: 50,
              'background' : 'lightgreen'
            },
            delay: 3000
          });
        }, 500);
      }
    });
  },
  challengeInit : function(){
    console.log("WARNING: Missing challengeInit function");
  },
  messageTemplate : 'Unknown challenge',
  defaults: function(){
    return {
      step : 0,
      type: "char",
      steps : 1,
      extraP : 1
    };
  },
  isAchieved: function(){
    return this.get('step') >= this.get('steps');
  },
  incrementStep: function(amount){
    this.set('step', Math.min(this.get('step') + amount, this.get('steps'))).save();
  },
  rewardMultiplier : 12,
  calculateReward: function() {
    return this.rewardMultiplier * this.get('steps') * this.get('extraP');
  }
});
//Move to HTML
var challengeTemplate = _.template('<li class="challenge-item <% if(finished) { %>ui-disabled"<% } %>"><%- message %> <br /> <sub><%- step %> / <%- steps %></sub></li>');
var Challenges = Backbone.Collection.extend({
  localStorage: new Backbone.LocalStorage("challenges"),
  model: Challenge,
  getScriptIdx : function(){
    if(this.length > 0) {
      return _.max(this.pluck('sIdx'));
    } else {
      return -1;
    }
  },
  getActiveChallenges : function(){
    var currentScriptIdx = this.getScriptIdx();
    return this.filter(function(challenge){
      return challenge.get('sIdx') === currentScriptIdx;
    });
  },
  addChallenges : function() {
    var that = this;
    var currentScriptIdx = this.getScriptIdx() + 1;
    if(currentScriptIdx >= challengeScript.length) {
      //All challenges are complete, can't add any more.
      //Remove the loading message
      $('.challenge-list').empty();
      return;
    }
    _.each(challengeScript[currentScriptIdx], function(chDescritor){
      chDescritor.sIdx = currentScriptIdx;
      that.create(chDescritor).activate();
    });
  }
});
var myChallenges = new Challenges();

var renderChallenges = function(activeChallenges){
  console.log('rendering challenges');
  var $chlist = $('.challenge-list');
  if(activeChallenges.length === 0) {
    $chlist.text('<div class="ch-msg">No challenges</div>');
    return;
  }
  window.a=activeChallenges;
  if(activeChallenges[0].get('type') === 'lastChallenge') {
    $chlist.html('<div class="ch-msg">Challenges complete!</div>');
    return;
  }
  $chlist.html('<li data-role="list-divider">Level ' +
    activeChallenges[0].get('sIdx') +
    '</li>');
  
  _.each(activeChallenges, function(challenge){
    var $challengeEl = $(challengeTemplate(_.extend({
      message : challenge.message,
      finished : false
    }, challenge.toJSON())));
    $chlist.append($challengeEl);
    
    $challengeEl.on('vclick', function(){
      if(challenge.isAchieved() && !challenge.get('finished')) {
        myTransactions.create({ amount : challenge.calculateReward() });
        challenge.set('finished', true).save();
        //This should trigger the myChallenges change listener.
      }
    });
  });
  $chlist.listview('refresh');
};

myGameState.on("ready", _.wrap(function(){
  //Making all the challenges complete before restocking them makes
  //it possible to use similar challenges without balanching them,
  //or use overlapping challenges by presenting them in different tiers.
  var refresh = _.debounce(function(){
    var activeChallenges = myChallenges.getActiveChallenges();

    if(activeChallenges.length === 0) {
      myChallenges.addChallenges();
    } else if(_.every(activeChallenges, function(challenge){
      return challenge.get('finished');
    })) {
      $('.challenge-item').slideUp(800);
      window.setTimeout(function(){
        myChallenges.addChallenges();
      }, 800);
      return;
    }
    
    renderChallenges(activeChallenges);
  });
  myChallenges.reset();
  myChallenges.on('add change', refresh);
  myChallenges.fetch({
    success: function(){
      _.invoke(myChallenges.getActiveChallenges(), 'activate');
      refresh();
    }
  });
}, function(reallyReady){
  myChallenges.fetch({
    success: function(){
      synchronousEach(myChallenges.models, function(val, next){
        if(!val.has('sIdx')) {
          console.log("No sIdx " + JSON.stringify(val.toJSON()));
          val.destroy({ success: next });
        } else {
          next();
        }
      }, reallyReady);
    }
  });
}));
