import {DOCUMENT_OWNERSHIP_LEVELS} from "@common/constants.mjs";
import DocumentDirectory from "../document-directory.mjs";
import Adventure from "@client/documents/adventure.mjs";

/**
 * An Application that displays the indexed contents of a Compendium pack.
 * @template {ClientDocument} TDocument
 * @extends {DocumentDirectory<TDocument>}
 */
export default class Compendium extends DocumentDirectory {
  /** @override */
  static DEFAULT_OPTIONS = {
    id: "Compendium-{id}",
    classes: ["compendium-directory", "sidebar-popout"],
    window: {
      frame: true,
      positioned: true
    },
    position: {
      top: 70,
      left: 120,
      width: 350,
      height: window.innerHeight - 100
    },
    actions: {
      copyId: Compendium.#onCopyId
    }
  };

  /** @override */
  static PARTS = {
    header: {
      template: "templates/sidebar/apps/compendium/header.hbs"
    },
    directory: {
      template: "templates/sidebar/apps/compendium/directory.hbs",
      templates: ["templates/sidebar/directory/directory.hbs"],
      scrollable: [".directory-list"]
    },
    footer: super.PARTS.footer
  };

  /** @override */
  static _entryPartial = "templates/sidebar/apps/compendium/index-partial.hbs";

  /* -------------------------------------------- */
  /*  Properties                                  */
  /* -------------------------------------------- */

  /** @override */
  get isPopout() {
    return false;
  }

  /** @override */
  get title() {
    return _loc(this.collection.title);
  }

  /* -------------------------------------------- */
  /*  Rendering                                   */
  /* -------------------------------------------- */

  /** @inheritDoc */
  _initializeApplicationOptions(options) {
    const initialized = super._initializeApplicationOptions(options);
    initialized.uniqueId = initialized.collection.collection.replaceAll(".", "_");
    return initialized;
  }

  /* -------------------------------------------- */

  /** @override */
  _canCreateEntry() {
    const isOwner = this.collection.testUserPermission(game.user, "OWNER");
    return !this.collection.locked && isOwner && this.documentClass.canUserCreate(game.user);
  }

  /* -------------------------------------------- */

  /** @override */
  _canCreateFolder() {
    return this._canCreateEntry();
  }

  /* -------------------------------------------- */

  /** @inheritDoc */
  _canRender(options) {
    if ( !this.collection.visible ) {
      if ( options.force ) ui.notifications.warn("COMPENDIUM.CannotViewWarning", { localize: true });
      return false;
    }
    return super._canRender(options);
  }

  /* -------------------------------------------- */

  /** @inheritDoc */
  _configureRenderOptions(options) {
    super._configureRenderOptions(options);
    options.window ||= {};
    options.window.icon ||= `fa-solid fa-lock${this.collection.locked ? "" : "-open"}`;
  }

  /* -------------------------------------------- */

  /** @override */
  _getEntryContextOptions() {
    const isAdventure = this.documentName === "Adventure";
    const isScene = this.documentName === "Scene";
    return [{
      label: "COMPENDIUM.ImportEntry",
      icon: "fa-solid fa-download",
      visible: () => CONST.WORLD_DOCUMENT_TYPES.includes(this.documentName)
        && this.documentClass.canUserCreate(game.user),
      onClick: async (event, li) => {
        const collection = game.collections.get(this.documentName);
        const options = {clearOwnership: false, dialog: true, renderSheet: true};
        return collection.importFromCompendium(this.collection, li.dataset.entryId, {}, options);
      }
    }, {
      label: "ADVENTURE.ExportEdit",
      icon: "fa-solid fa-edit",
      visible: () => isAdventure && game.user.isGM && !this.collection.locked,
      onClick: async (event, li) => {
        const document = await this.collection.getDocument(li.dataset.entryId);
        return new CONFIG.Adventure.exporterClass({
          document: document.clone({}, {keepId: true})
        }).render({force: true});
      }
    }, {
      label: "SCENE.GenerateThumb",
      icon: "fa-solid fa-image",
      visible: () => !this.collection.locked && isScene,
      onClick: async (event, li) => {
        const scene = await this.collection.getDocument(li.dataset.entryId);
        try {
          const { thumb } = await scene?.createThumbnail() ?? {};
          if ( thumb ) await scene.update({thumb}, {diff: false});
          ui.notifications.info("SCENE.GenerateThumbSuccess", {format: {name: scene.name}});
        } catch(err) {
          ui.notifications.error(err.message);
        }
      }
    }, {
      label: "COMPENDIUM.DeleteEntry",
      icon: "fa-solid fa-trash",
      visible: () => game.user.isGM && !this.collection.locked,
      onClick: async (event, li) => {
        const document = await this.collection.getDocument(li.dataset.entryId);
        return document?.deleteDialog();
      }
    }];
  }

  /* -------------------------------------------- */

  /** @inheritDoc */
  _getFolderContextOptions() {
    return super._getFolderContextOptions().filter(({ label }) => {
      return (label !== "OWNERSHIP.Configure") && (label !== "FOLDER.Export");
    });
  }

  /* -------------------------------------------- */

  /** @inheritDoc */
  _getFrameButtons(options) {
    const buttons = super._getFrameButtons(options);
    if ( this.collection.collection ) buttons.push({
      icon: "fa-solid fa-passport",
      label: "COMPENDIUM.CopyId",
      action: "copyId"
    });
    return buttons;
  }

  /* -------------------------------------------- */

  /** @inheritDoc */
  async _prepareHeaderContext(context, options) {
    await super._prepareHeaderContext(context, options);
    Object.assign(context, {collection: this.collection, title: this.title});
  }

  /* -------------------------------------------- */

  /** @inheritDoc */
  async _onRender(context, options) {
    await super._onRender(context, options);
    if ( this.options.classes.includes("themed") ) return;
    this.element.classList.remove("theme-light", "theme-dark");
    const { colorScheme } = game.settings.get("core", "uiConfig");
    if ( colorScheme.interface ) this.element.classList.add("themed", `theme-${colorScheme.interface}`);
  }

  /* -------------------------------------------- */
  /*  Event Listeners & Handlers                  */
  /* -------------------------------------------- */

  /** @inheritDoc */
  async _onClickEntry(event, target, options={}) {
    if ( this.documentName !== "Adventure" ) return super._onClickEntry(event, target, options);

    event.preventDefault();
    const { entryId } = target.closest("[data-entry-id]").dataset;

    // If full document is already cached, open its sheet as normal.
    const cached = this.collection.get(entryId);
    if ( cached instanceof foundry.abstract.Document ) return cached.sheet.render(true);

    // Otherwise create a shallow Adventure from index data.
    let adventure = Adventure.implementation.fromIndex(entryId, this.collection);

    // V1 sheets need the full Document.
    if ( adventure.sheet instanceof foundry.appv1.sheets.AdventureImporter ) {
      adventure = await this.collection.getDocument(entryId);
    }

    adventure.sheet.render(true);
  }

  /* -------------------------------------------- */

  /** @inheritDoc */
  _onCreateEntry(event, target) {
    // If this is an Adventure, use the Adventure Exporter application.
    if ( this.documentName === "Adventure" ) {
      const pack = this.collection.collection;
      const name = Adventure.implementation.defaultName({ pack });
      const adventure = new Adventure.implementation({ name }, { pack });
      return new CONFIG.Adventure.exporterClass({document: adventure}).render({force: true});
    }
    return super._onCreateEntry(event, target);
  }

  /* -------------------------------------------- */

  /**
   * Handle click events to copy the ID of this compendium to clipboard.
   * @param {PointerEvent} event
   * @this {Compendium}
   */
  static #onCopyId(event) {
    event.preventDefault(); // Don't open context menu
    event.stopPropagation(); // Don't trigger other events
    if ( event.detail > 1 ) return; // Ignore repeated clicks
    const id = this.collection.collection;
    game.clipboard.copyPlainText(id);
    ui.notifications.info("COMPENDIUM.IdCopiedClipboard", {format: {id}});
  }

  /* -------------------------------------------- */
  /*  Drag & Drop                                 */
  /* -------------------------------------------- */

  /** @override */
  _canDragDrop(selector) {
    return this.collection.testUserPermission(game.user, DOCUMENT_OWNERSHIP_LEVELS.OWNER);
  }

  /* -------------------------------------------- */

  /** @override */
  _entryAlreadyExists(entry) {
    return (entry.collection === this.collection) && this.collection.index.has(entry.id);
  }

  /* -------------------------------------------- */

  /** @override */
  _getEntryDragData(entryId) {
    return {
      type: this.documentName,
      uuid: this.collection.getUuid(entryId)
    };
  }
}
