import { Hero6Utility } from "./hero6-utility.js";

/* -------------------------------------------- */
export class Hero6CombatTracker extends CombatTracker {

  /* -------------------------------------------- */
  static get defaultOptions() {
    let path = "systems/fvtt-hero-system-6/templates/apps/combat-tracker.hbs";
    return foundry.utils.mergeObject(super.defaultOptions, {
      template: path,
    });
  }
}

/* -------------------------------------------- */
export class Hero6Combat extends Combat {

  /* -------------------------------------------- */
  static ready() {
    Hooks.on("getCombatTrackerEntryContext", (html, options) => { Hero6Combat.pushMenuOptions(html, options); });
    game.combat.settings.resource = "characteristics.spd.value";
  }

  /* -------------------------------------------- */
  static pushMenuOptions(html, options) {
    let newOpt
    for (let i = 0; i < options.length; i++) {
      let option = options[i];
      if (option.name == 'COMBAT.CombatantReroll') { // Replace !
        option.name = "Hold/Unhold action";
        option.condition = true;
        option.icon = '<i class="far fa-question-circle"></i>';
        option.callback = target => {
          let id = target.data('combatant-id')
          let c = game.combat.combatants.get(id)
          c.actor.holdAction()
        }
        //newOpt = duplicate(option)
      }
    }
    //options.push(newOpt)
  }

  /* -------------------------------------------- */
  holdAction(combatantId) {
    this.rebuildInitiative()
    //console.log("Rebuilding.....")
  }

  /* -------------------------------------------- */
  abortAction(actorId, abortState) {
    this.rebuildInitiative()
  }

  /* -------------------------------------------- */
  constructor(data, context) {
    super(data, context);

    this.turnNumber = 0;
    this.segmentNumber = 12;
  }

  /* -------------------------------------------- */
  async startCombat() {
    game.combat.settings.resource = "characteristics.spd.value";

    let updList = []
    for (let c of this.combatants) {
      this.computeInitiative(c, updList)
      await c.actor.cleanCombat()
    }
    if (updList.length > 0) {
      await this.updateEmbeddedDocuments("Combatant", updList);
    }

    super.startCombat();
  }
  /* -------------------------------------------- */
  forceHold(actor, isHold) {
    if (game.user.isGM) {
      let updList = []
      let c = this.combatants.find(c => c.actor._id == actor.id)
      let name = actor.name + ((isHold) ? " (H)" : "")
      console.log("ForceHold!!", c, actor)
      updList.push({ _id: c.id || c._id, name: name, initiative: actor.getBaseInit(this.segmentNumber) })
      this.updateEmbeddedDocuments("Combatant", updList)
    } else {
      game.socket.emit("system.fvtt-hero-system-6", { name: "msg_force_hold", data: { actorId: actor.id, isHold: isHold } });
    }
  }
  /* -------------------------------------------- */
  forceAbort(actor, isAbort) {
    if (game.user.isGM) {
      let updList = []
      let c = this.combatants.find(c => c.actor._id == actor.id)
      let name = actor.name + ((isAbort) ? " (A)" : "")
      updList.push({ _id: c.id || c._id, name: name, initiative: actor.getBaseInit(this.segmentNumber) })
      this.updateEmbeddedDocuments("Combatant", updList)
    } else {
      game.socket.emit("system.fvtt-hero-system-6", { name: "msg_force_abort", data: { actorId: actor.id, isAbort: isAbort } });
    }
  }

  /* -------------------------------------------- */
  computeInitiative(c, updList) {
    let id = c._id || c.id
    let hasSegment = c.actor.hasPhase(this.segmentNumber)
    let isOnHold = c.actor.getHoldAction()
    let isOnAbort = c.actor.getAbortAction()
    let name = c.actor.name
    if (hasSegment || isOnHold || isOnAbort) {
      let baseInit = c.actor ? c.actor.getBaseInit(this.segmentNumber) : 0;
      if (isOnHold) {
        if (hasSegment) { // On hold + current segment -> auto-disable on hold
          c.actor.disableHoldAction()
        } else {
          name = c.actor.name + " (H)"
        }
      }
      if (isOnAbort) {
        name = c.actor.name + " (A)"
        if (c.actor.incAbortActionCount()) {
          c.actor.disableAbortAction()
        }
      }
      updList.push({ _id: id, name: name, initiative: baseInit, holdAction: c.holdAction })
    } else {
      updList.push({ _id: id, name: name, initiative: 0, holdAction: c.holdAction })
    }
  }

  /* -------------------------------------------- */
  async rollInitiative(ids, formula = undefined, messageOptions = {}) {
    ids = typeof ids === "string" ? [ids] : ids;

    let updList = []
    for (let cId = 0; cId < ids.length; cId++) {
      const c = this.combatants.get(ids[cId])
      this.computeInitiative(c, updList)
    }

    if (updList.length > 0) {
      await this.updateEmbeddedDocuments("Combatant", updList);
    }

    return this;
  }

  /* -------------------------------------------- */
  async rebuildInitiative() {
    let updList = []
    for (let c of this.combatants) {
      this.computeInitiative(c, updList)
    }
    if (updList.length > 0) {
      await this.updateEmbeddedDocuments("Combatant", updList);
      //console.log("Rebuild INIT", updList)
      for (let c of updList) {
        if (c.initiative != 0) {
          return true
        }
      }
    }
    return false
  }

  /* -------------------------------------------- */
  nextTurn() {
    let nbC = this.combatants.filter(c => c.initiative > 0).length
    //console.log("Next turn called....", this.turn, nbC)
    if (this.turn < nbC - 1) {
      super.nextTurn()
    } else {
      this.nextRound()
    }
  }

  /* -------------------------------------------- */
  async previousRound() {
    let hasCombatants = false
    let nextRound = this.round
    let advanceTime = 0
    let turn = this.turn === null ? null : 0; // Preserve the fact that it's no-one's turn currently.
    let turnData = this.getFlag("world", "turnData")

    //console.log("Next round called....", nextRound, turnData)
    while (!hasCombatants) {
      if (this.settings.skipDefeated && (turn !== null)) {
        turn = this.turns.findIndex(t => !t.isDefeated);
        if (turn === -1) {
          ui.notifications.warn("COMBAT.NoneRemaining", { localize: true });
          turn = 0;
        }
      }  
      advanceTime = -1 * (Math.max(this.turns.length - this.turn, 0) * CONFIG.time.turnTime);
      advanceTime -= CONFIG.time.roundTime;
      nextRound = nextRound -1
      //console.log("Next round called....2", nextRound, turnData)
      turnData = this.getFlag("world", "turnData")
      if (!turnData) {
        turnData = { turnNumber: 0, segmentNumber: 12 }
        this.setFlag("world", "turnData", turnData)
      }
      turnData = duplicate(turnData)
      turnData.segmentNumber -= 1
      if (turnData.segmentNumber <= 0) {
        turnData.segmentNumber = 12
        turnData.turnNumber--
      }
      await this.setFlag("world", "turnData", turnData)
      this.turnNumber = turnData.turnNumber;
      this.segmentNumber = turnData.segmentNumber;
      //console.log("Next round called....3", nextRound, turnData)

      // Re-compute init of actors
      hasCombatants = await this.rebuildInitiative()
      //console.log("Going round....", nextRound, hasCombatants)
    }

    // Update the document, passing data through a hook first
    const updateData = { round: nextRound, turn };
    const updateOptions = { advanceTime, direction: -1 };
    Hooks.callAll("combatRound", this, updateData, updateOptions);
    console.log(this)
    return this.update(updateData, updateOptions);
  }

  /* -------------------------------------------- */
  async nextRound() {
    let hasCombatants = false
    let nextRound = this.round
    let advanceTime = 0
    let turn = this.turn === null ? null : 0; // Preserve the fact that it's no-one's turn currently.
    let turnData = this.getFlag("world", "turnData")

    //console.log("Next round called....", nextRound, turnData)
    while (!hasCombatants) {
      if (this.settings.skipDefeated && (turn !== null)) {
        turn = this.turns.findIndex(t => !t.isDefeated);
        if (turn === -1) {
          ui.notifications.warn("COMBAT.NoneRemaining", { localize: true });
          turn = 0;
        }
      }
      advanceTime = Math.max(this.turns.length - this.turn, 0) * CONFIG.time.turnTime;
      advanceTime += CONFIG.time.roundTime;
      nextRound = nextRound + 1;
      //console.log("Next round called....2", nextRound, turnData)
      turnData = this.getFlag("world", "turnData")
      if (!turnData) {
        turnData = { turnNumber: 0, segmentNumber: 12 }
        this.setFlag("world", "turnData", turnData)
      }
      turnData = duplicate(turnData)
      turnData.segmentNumber += 1
      if (turnData.segmentNumber > 12) {
        turnData.segmentNumber = 1
        turnData.turnNumber++
        ChatMessage.create({
          content: "Complete Post-Segment 12 Recoveries."
        })
      }
      await this.setFlag("world", "turnData", turnData)
      this.turnNumber = turnData.turnNumber;
      this.segmentNumber = turnData.segmentNumber;
      //console.log("Next round called....3", nextRound, turnData)

      // Re-compute init of actors
      hasCombatants = await this.rebuildInitiative()
      //console.log("Going round....", nextRound, hasCombatants)
    }

    // Update the document, passing data through a hook first
    const updateData = { round: nextRound, turn };
    const updateOptions = { advanceTime, direction: 1 };
    Hooks.callAll("combatRound", this, updateData, updateOptions);
    console.log(this)
    return this.update(updateData, updateOptions);
  }


  /* -------------------------------------------- */
  async _onCreateEmbeddedDocuments(type, documents, result, options, userId) {
    //console.log("Added...")
    await super._onCreateEmbeddedDocuments(type, documents, result, options, userId)
    await this.rebuildInitiative()
  }

  /* -------------------------------------------- 
  _onUpdate(changed, options, userId) {
  }*/

  /* -------------------------------------------- */
  static async checkTurnPosition() {
    while (game.combat.turn > 0) {
      await game.combat.previousTurn()
    }
  }

}
