/* 
 * This file is part of the warpgate module (https://github.com/trioderegion/warpgate)
 * Copyright (c) 2021 Matthew Haentschke.
 * 
 * This program is free software: you can redistribute it and/or modify  
 * it under the terms of the GNU General Public License as published by  
 * the Free Software Foundation, version 3.
 *
 * This program is distributed in the hope that it will be useful, but 
 * WITHOUT ANY WARRANTY; without even the implied warranty of 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License 
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */


import { logger } from './logger.js'
import { Gateway } from './gateway.js'
import { MODULE } from './module.js'
import {queueUpdate} from './update-queue.js'
import { Mutator } from './mutator.js'

export class UserInterface {

  static register() {
    this.hooks();
    this.settings();
  }

  static hooks() {
    Hooks.on("renderActorSheet", UserInterface._renderActorSheet);
  }

  static settings() {
    const config = true;
    const settingsData = {
      showDismissLabel : {
        scope: "client", config, default: true, type: Boolean,
      },
      showRevertLabel : {
        scope: "client", config, default: true, type: Boolean,
      },
      dismissButtonScope : {
        scope: "client", config, default: 'spawned', type: String, choices: {
          disabled: MODULE.localize('setting.option.disabled'),
          spawned: MODULE.localize('setting.option.spawnedOnly'),
          all: MODULE.localize('setting.option.all')
        }
      },
      revertButtonBehavior : {
        scope: 'client', config, default: 'pop', type: String, choices: {
          disabled: MODULE.localize('setting.option.disabled'),
          pop: MODULE.localize('setting.option.popLatestMutation'),
          menu: MODULE.localize('setting.option.showMutationList')
        }
      }
    };

    MODULE.applySettings(settingsData);
  }

  static _renderActorSheet(app, html, data) {
    logger.debug("app |", app);
    logger.debug("html |", html);
    logger.debug("data |", data);
    
    UserInterface.addDismissButton(app, html, data);
    UserInterface.addRevertMutation(app, html, data);
  }

  static _shouldAddDismiss(token) {

    if ( !(token instanceof TokenDocument) ) return false;

    switch (MODULE.setting('dismissButtonScope')){
      case 'disabled':
        return false;
      case 'spawned':
        
        const controlData = token?.actor.getFlag(MODULE.data.name, 'control');

        /** do not add the button if we are not the controlling actor AND we aren't the GM */
        if ( !(controlData?.user === game.user.id) &&
          !game.user.isGM) return false;

        return !!controlData;
      case 'all':
        return true;
    }

  }

  static addDismissButton(app, html/*, data*/) {
    const token = app.token;

    /** this is not a warpgate spawned actor */
    if (!UserInterface._shouldAddDismiss(token)) return;

    /* do not add duplicate buttons! */
    if(html.closest('.app').find('.dismiss-warpgate').length !== 0) {
      logger.debug(MODULE.localize('debug.dismissPresent'));  
      return;
    }

    const label = MODULE.setting('showDismissLabel') ? MODULE.localize("display.dismiss") : ""
    let dismissButton = $(`<a class="dismiss-warpgate" title="${MODULE.localize('display.dismiss')}"><i class="fas fa-user-slash"></i>${label}</a>`);

    dismissButton.click( (/*event*/) => {
      if (!token) {
        logger.error(MODULE.localize('error.sheetNoToken'));
        return;
      }
      const {id, parent} = token;
      Gateway.dismissSpawn(id, parent?.id);

      /** close the actor sheet if provided */
      app?.close({submit: false});
    });

    let title = html.closest('.app').find('.window-title');
    dismissButton.insertAfter(title);

  }

  static _shouldAddRevert(token) {

    if ( !(token instanceof TokenDocument) ) return false;

    const mutateStack = warpgate.mutationStack(token).stack;

    /* this is not a warpgate mutated actor,
     * or there are no remaining stacks to peel */
    if (mutateStack.length == 0) return false;

    return MODULE.setting('revertButtonBehavior') !== 'disabled';
  }

  static _getTokenFromApp(app) {
    
    const {token, actor} = app;
    
    const hasToken = token instanceof TokenDocument;

    if( !hasToken ) {
      /* check if linked and has an active token on scene */
      const candidates = actor?.getActiveTokens() ?? [];
      const linkedToken = candidates.find( t => (MODULE.isV10?t.document:t.data).actorLink )?.document ?? null;
      
      return linkedToken;
      
    }

    return token;
  }

  static addRevertMutation(app, html, data) {

    /* do not add duplicate buttons! */
    let foundButton = html.closest('.app').find('.revert-warpgate')

    /* we remove the current button on each render
     * in case the render was triggered by a mutation
     * event and we need to update the tool tip
     * on the revert stack
     */
    if (foundButton) {
      foundButton.remove();
    }

    const token = UserInterface._getTokenFromApp(app);

    if(!UserInterface._shouldAddRevert(token)) return;

    const mutateStack = token?.actor?.getFlag(MODULE.data.name, 'mutate');

    /* construct the revert button */
    const label = MODULE.setting('showRevertLabel') ? MODULE.localize("display.revert") : ""
    const stackCount = mutateStack.length > 1 ? ` 1/${mutateStack.length}` : '';
    let revertButton = $(`<a class="revert-warpgate" title="${MODULE.localize('display.revert')}${stackCount}"><i class="fas fa-undo-alt"></i>${label}</a>`);

    revertButton.click( async (event) => {
      const shouldShow = (shiftKey) => {
        const mode = MODULE.setting('revertButtonBehavior')
        const show = mode == 'menu' ? !shiftKey : shiftKey;
        return show;
      }

      let name = undefined;
      const showMenu = shouldShow(event.shiftKey);

      if (showMenu) {
        const buttons = mutateStack.map( mutation => {return {label: mutation.name, value: mutation.name}} )
        name = await warpgate.buttonDialog({buttons, title: MODULE.localize('display.revertDialogTitle')}, 'column');
        if (name === false) return;
      }

      /* need to queue this since 'click' could
       * happen at any time.
       * Do not need to remove the button here 
       * as it will be refreshed on the render call
       */
      queueUpdate( async () => {
        await Mutator.revertMutation(token, name);
        app?.render(false);
      });

    });

    let title = html.closest('.app').find('.window-title');
    revertButton.insertAfter(title);
  }

}
