/* -------------------------------------------- */  
import { SoSCombat } from "./sos-combat.js";
import { SoSDialogCombatActions } from "./sos-dialog-combat-actions.js";

/* -------------------------------------------- */  
const severity2malus = { "none": 0, "light": -1, "moderate": -2, "severe": -3, "critical": -4};
/* -------------------------------------------- */  
const severity2bonus = { "none": 0, "light": 1, "moderate": 2, "severe": 3, "critical": 4};

/* -------------------------------------------- */  
export class SoSUtility extends Entity {
  
  /* -------------------------------------------- */  
  static async preloadHandlebarsTemplates() {
    
    const templatePaths = [
      'systems/foundryvtt-shadows-over-sol/templates/actor-sheet.html',
      'systems/foundryvtt-shadows-over-sol/templates/editor-notes-gm.html',
      'systems/foundryvtt-shadows-over-sol/templates/stat-option-list.html',
      'systems/foundryvtt-shadows-over-sol/templates/stat-name-list.html',

      'systems/foundryvtt-shadows-over-sol/templates/item-sheet.html',
      'systems/foundryvtt-shadows-over-sol/templates/item-geneline-sheet.html',
      'systems/foundryvtt-shadows-over-sol/templates/item-subculture-sheet.html',
      'systems/foundryvtt-shadows-over-sol/templates/item-weapon-sheet.html',
      'systems/foundryvtt-shadows-over-sol/templates/item-commongear-sheet.html',

      'systems/foundryvtt-shadows-over-sol/templates/dialog-flip.html'
    ]
    return loadTemplates(templatePaths);    
  }

  /* -------------------------------------------- */
  static fillRange (start, end) {
    return Array(end - start + 1).fill().map((item, index) => start + index);
  }

  /* -------------------------------------------- */
  static onSocketMesssage( msg ) {
    if( !game.user.isGM ) return; // Only GM

    if (msg.name == 'msg_declare_actions' ) {
      let combat = game.combats.get( msg.data.combatId); // Get the associated  combat
      combat.setupActorActions( msg.data );
    } else if (msg.name == 'msg_close_action') {
      game.combat.closeAction( msg.data.uniqId );
    } else if (msg.name == 'msg_request_defense') {
      SoSUtility.applyDamage( msg.data );
    } else if (msg.name == 'msg_reaction_cover') {
      SoSUtility.reactionCover( msg.data.uniqId );
    } else if (msg.name == 'msg_reaction_melee') {
      SoSUtility.reactionMelee( msg.data.uniqId );
    } else if (msg.name == 'msg_reaction_hit') {
      SoSUtility.reactionHit( msg.data.uniqId );
    }
  }

  /* -------------------------------------------- */
  static async loadCompendiumNames(compendium) {
    const pack = game.packs.get(compendium);
    let competences;
    await pack.getIndex().then(index => competences = index);
    return competences;
  }
  
  /* -------------------------------------------- */
  static async loadCompendium(compendium, filter = item => true) {
    let compendiumItems = await SoSUtility.loadCompendiumNames(compendium);

    const pack = game.packs.get(compendium);
    let list = [];
    for (let compendiumItem of compendiumItems) {
      await pack.getEntity(compendiumItem._id).then(it => {
        const item = it.data;
        if (filter(item)) {
          list.push(item);
        }
      });
    };
    return list;
  }
  
  /* -------------------------------------------- */
  static updateCombat(combat, round, diff, id) {
    combat.requestActions();
  }

  /* -------------------------------------------- */
  static async openDeclareActions( event) {
    event.preventDefault();
    let round = event.currentTarget.attributes['data-round'].value;
    let combatantId = event.currentTarget.attributes['data-combatant-id'].value;
    let combatId = event.currentTarget.attributes['data-combat-id'].value;
    let uniqId = event.currentTarget.attributes['data-uniq-id'].value;
    let d = await SoSDialogCombatActions.create( combatId, combatantId, round, uniqId );
    d.render(true);      
  }

  /* -------------------------------------------- */
  static getConsequenceMalus(severity) {
    return severity2malus[severity] ?? 0;
  }
  /* -------------------------------------------- */
  static getConsequenceBonus(severity) {
    return severity2bonus[severity] ?? 0;
  }
  
  /* -------------------------------------------- */
  static computeEncumbrance( items) {
    let trappings = items.filter( item => item.type == 'gear' || item.type == 'armor' || item.type == 'weapon' );
    let sumEnc = 0;
    for (let object of trappings) {
      if ( (!object.data.worn) && (!object.data.neg) && (!object.data.software) && (!object.data.implant) && (!object.data.containerid || object.data.containerid == "") ) {
        sumEnc += (object.big > 0) ? object.big : 1;
      }
    }
    return sumEnc;
  }

  /* -------------------------------------------- */
  static closeAction(event) {
    let uniqId = event.currentTarget.attributes['data-uniq-id'].value;

    if ( game.user.isGM ) {
      game.combat.closeAction( uniqId );
    } else {
      game.socket.emit("system.foundryvtt-shadows-over-sol", {
          name: "msg_close_action", data: { uniqId: uniqId}  } );
    }
  }

  /* -------------------------------------------- */
  static async registerChatCallbacks(html) {
    html.on("click", '#button-declare-actions', event => {
      SoSUtility.openDeclareActions( event );
    });
    html.on("click", '#button-end-action', event => {
      SoSUtility.closeAction( event );
    });    

    html.on("click", '#button-reaction-cover', event => {
      let uniqId = event.currentTarget.attributes['data-uniq-id'].value;
      if ( game.user.isGM ) {
        SoSUtility.reactionCover( uniqId );
      } else {
        game.socket.emit("system.foundryvtt-shadows-over-sol", { name: "msg_reaction_cover", data: { uniqId: uniqId}  } );
      }
    });    

    html.on("click", '#button-reaction-melee', event => {
      let uniqId = event.currentTarget.attributes['data-uniq-id'].value;
      if ( game.user.isGM ) {
        SoSUtility.reactionMelee( uniqId );
      } else {
        game.socket.emit("system.foundryvtt-shadows-over-sol", { name: "msg_reaction_melee", data: { uniqId: uniqId}  } );
      }
    });    
    html.on("click", '#button-reaction-hit', event => {
      let uniqId = event.currentTarget.attributes['data-uniq-id'].value;
      if ( game.user.isGM ) {
        SoSUtility.reactionHit( uniqId );
      } else {
        game.socket.emit("system.foundryvtt-shadows-over-sol", { name: "msg_reaction_hit", data: { uniqId: uniqId}  } );
      }
    });        
  }

  /* -------------------------------------------- */
  static getTarget() {
    if (game.user.targets && game.user.targets.size == 1) {
      for (let target of game.user.targets) {
        return target;
      }
    }
    return undefined;
  }

  /* -------------------------------------------- */
  static increaseConsequenceSeverity( severity ) {
    if ( severity == 'none') return 'light';
    if ( severity == 'light') return 'moderate';
    if ( severity == 'moderate') return 'severe';      
    if ( severity == 'severe') return 'critical';
    return 'critical';
  }

  /* -------------------------------------------- */
  static getConsequenceSeverityLevel( severity) {
    if ( severity == 'none')     return 0;
    if ( severity == 'light')    return 1;
    if ( severity == 'moderate') return 2;
    if ( severity == 'severe')   return 3;
    if ( severity == 'critical') return 4;
    return 0;
  }
  
  /* -------------------------------------------- */
  static increaseSeverity( severity ) {
    if ( severity == 'L') return 'M';
    if ( severity == 'M') return 'S';
    if ( severity == 'S') return 'C';
    if ( severity == 'C') return 'F';
  }

  /* -------------------------------------------- */
  static decreaseSeverity( severity ) {
    if ( severity == 'C') return 'S';
    if ( severity == 'S') return 'M';
    if ( severity == 'M') return 'L';
    if ( severity == 'L') return 'N';
  }

  /* -------------------------------------------- */
  static getSeverityLevel( severity) {
    if ( severity == 'C') return 4;
    if ( severity == 'S') return 3;
    if ( severity == 'M') return 2;
    if ( severity == 'L') return 1;
    return 0;
  }

  /* -------------------------------------------- */
  static async confirmDelete(actorSheet, li) {
    let itemId = li.data("item-id");
    let objet = actorSheet.actor.items.find(item => item._id == itemId);
    let msgTxt = "<p>Are you sure to delete this item ?";
    let buttons = {
      delete: {
          icon: '<i class="fas fa-check"></i>',
          label: "Yes, delete it",
          callback: () => {
            console.log("Delete : ", itemId);
            actorSheet.actor.deleteOwnedItem(itemId);
            li.slideUp(200, () => actorSheet.render(false));
          }
        },
        cancel: {
          icon: '<i class="fas fa-times"></i>',
          label: "Cancel"
        }
      }
      msgTxt += "</p>";
      let d = new Dialog({
        title: "Confirm deletion",
        content: msgTxt,
        buttons: buttons,
        default: "cancel"
      });
      d.render(true);
    }
  
  /* -------------------------------------------- */
  static async applyDamage( flipData ) {
    if (!this.registry) this.registry = {};

    if ( flipData.isReaction) { // Check again resut in case of reaction !
      flipData.magnitude = flipData.finalScore - flipData.tn; // Update magnitude
      if ( flipData.magnitude < 0 ) {
        let html = await renderTemplate('systems/foundryvtt-shadows-over-sol/templates/chat-reaction-result.html', flipData );
        ChatMessage.create( { content: html });    
        return;
      }
    }

    let dr = flipData.target.actor.data.data.scores.dr.value;
    let shock = flipData.target.actor.data.data.scores.shock.value;
    let defenseCritical = flipData.target.actor.data.data.scores.defense.critical;
    flipData.damageStatus = 'apply_damage';

    flipData.targetShock = shock;
    flipData.targetDR    = dr;
    flipData.targetCritical = defenseCritical;
    // DR management
    if ( flipData.damageValue < dr) { 
      if (flipData.damageValue < dr / 2) {
        flipData.damageStatus = "no_damage";
        // TODO : No damage !
      } else {
        flipData.damageSeverity = this.decreaseSeverity(flipData.damageSeverity );
        if ( flipData.damageSeverity == 'N') {
          flipData.damageStatus = "no_damage";
        } 
      }
    }
    
    // Shock management
    flipData.woundsList = [];
    if ( flipData.damageValue >= shock) {
      let incSeverity = Math.floor(flipData.damageValue / shock);
      for (let i=0; i<incSeverity; i++) {
        if ( flipData.damageSeverity == 'C') {
          flipData.woundsList.push( flipData.damageSeverity );
          flipData.damageSeverity = 'L';
        } else {
          flipData.damageSeverity = this.increaseSeverity( flipData.damageSeverity );
        }
      }
    }
    flipData.woundsList.push( flipData.damageSeverity );
    flipData.nbWounds = flipData.woundsList.length;

    // Critical management
    flipData.isCritical = ( flipData.cardTotal >= defenseCritical);

    let html = await renderTemplate('systems/foundryvtt-shadows-over-sol/templates/chat-damage-target.html', flipData );
    ChatMessage.create( { content: html });

    // Is target able to dodge ??
    let defender = game.actors.get( flipData.target.actor._id);
    flipData.coverConsequence = defender.data.items.find( item => item.type == 'consequence' && item.name == 'Cover');
    flipData.APavailable = game.combat.getAPFromActor( defender.data._id );
    console.log("FLIPDATE : ", flipData);
    if ( !flipData.isReaction && flipData.APavailable > 0) {
      if ( (flipData.weapon.data.category == 'melee' ) || ( (flipData.weapon.data.category == 'laser' || flipData.weapon.data.category == 'ballistic') && 
        flipData.coverConsequence.data.severity != 'none') )  {
        flipData.coverSeverityLevel = this.getConsequenceSeverityLevel( flipData.coverConsequence.data.severity ) * 2;
        flipData.coverSeverityFlag  = (flipData.coverSeverityLevel > 0);
        flipData.isMelee = (flipData.weapon.data.category == 'melee' );
        let melee = defender.data.items.find( item => item.type == 'skill' && item.name == 'Melee');
        flipData.defenderMelee = melee.data.value;
        flipData.uniqId = randomID(16);
        this.registry[flipData.uniqId] = flipData;
        let html = await renderTemplate('systems/foundryvtt-shadows-over-sol/templates/chat-damage-request-dodge.html', flipData );
        ChatMessage.create( { content: html, whisper: ChatMessage.getWhisperRecipients(flipData.target.actor.name).concat(ChatMessage.getWhisperRecipients("GM")) } );
        return; // Wait message response
      }
    }
    flipData.isReaction = false;
    this.takeWounds( flipData);
  }

   /* -------------------------------------------- */
   static reactionCover( uniqId) {
    let flipData = this.registry[uniqId];
    flipData.tn += flipData.coverSeverityLevel;
    flipData.isReaction = true;
    game.combat.decreaseAPFromActor( flipData.target.actor._id );
    SoSUtility.applyDamage( flipData);
   }

  /* -------------------------------------------- */
  static reactionMelee( uniqId) {
    let flipData = this.registry[uniqId];
    flipData.tn += flipData.defenderMelee;
    flipData.isReaction = true;
    game.combat.decreaseAPFromActor( flipData.target.actor._id );
    SoSUtility.applyDamage( flipData);
  }

  /* -------------------------------------------- */
  static reactionHit( uniqId) {
    let flipData = this.registry[uniqId];
    flipData.isReaction = true;
    SoSUtility.takeWounds( flipData);
  }
  
   /* -------------------------------------------- */
   static takeWounds( flipData ) {
    let defender = game.actors.get( flipData.target.actor._id);
    defender.applyWounds( flipData );
  }

}