// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/* eslint-disable @devtools/no-imperative-dom-api */

import dropTargetStyles from './dropTarget.css.js';
import {createShadowRootWithCoreStyles} from './UIUtils.js';

export class DropTarget {
  private element: HTMLElement;
  private readonly transferTypes: Array<{
    kind: string,
    type: RegExp,
  }>;
  private messageText: string;
  private readonly handleDrop: (arg0: DataTransfer) => void;
  private enabled: boolean;
  private dragMaskElement: HTMLElement|null;

  constructor(
      element: HTMLElement, transferTypes: Array<{
        kind: string,
        type: RegExp,
      }>,
      messageText: string, handleDrop: (arg0: DataTransfer) => void) {
    element.addEventListener('dragenter', this.onDragEnter.bind(this), true);
    element.addEventListener('dragover', this.onDragOver.bind(this), true);
    this.element = element;
    this.transferTypes = transferTypes;
    this.messageText = messageText;
    this.handleDrop = handleDrop;
    this.enabled = true;
    this.dragMaskElement = null;
  }

  setEnabled(enabled: boolean): void {
    this.enabled = enabled;
  }

  private onDragEnter(event: DragEvent): void {
    if (this.enabled && this.hasMatchingType(event)) {
      event.consume(true);
    }
  }

  private hasMatchingType(event: DragEvent): boolean {
    if (!event.dataTransfer) {
      return false;
    }
    for (const transferType of this.transferTypes) {
      const found = Array.from(event.dataTransfer.items).find(item => {
        return transferType.kind === item.kind && Boolean(transferType.type.exec(item.type));
      });
      if (found) {
        return true;
      }
    }
    return false;
  }

  private onDragOver(event: DragEvent): void {
    if (!this.enabled || !this.hasMatchingType(event)) {
      return;
    }
    if (event.dataTransfer) {
      event.dataTransfer.dropEffect = 'copy';
    }
    event.consume(true);
    if (this.dragMaskElement) {
      return;
    }
    this.dragMaskElement = this.element.createChild('div', '');
    const shadowRoot = createShadowRootWithCoreStyles(this.dragMaskElement, {cssFile: dropTargetStyles});
    shadowRoot.createChild('div', 'drop-target-message').textContent = this.messageText;
    this.dragMaskElement.addEventListener('drop', this.onDrop.bind(this), true);
    this.dragMaskElement.addEventListener('dragleave', this.onDragLeave.bind(this), true);
  }

  private onDrop(event: DragEvent): void {
    event.consume(true);
    this.removeMask();
    if (this.enabled && event.dataTransfer) {
      this.handleDrop(event.dataTransfer);
    }
  }

  private onDragLeave(event: Event): void {
    event.consume(true);
    this.removeMask();
  }

  private removeMask(): void {
    if (this.dragMaskElement) {
      this.dragMaskElement.remove();
      this.dragMaskElement = null;
    }
  }
}

export const Type = {
  URI: {kind: 'string', type: /text\/uri-list/},
  Folder: {kind: 'file', type: /$^/},
  File: {kind: 'file', type: /.*/},
  WebFile: {kind: 'file', type: /[\w]+/},
  ImageFile: {kind: 'file', type: /image\/.*/},
};
