/**
 * @license
 * Copyright (c) 2017 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
import { eventInWindow, getMouseOrFirstTouchEvent } from './vaadin-dialog-utils.js';
/**
 * @polymerMixin
 */
export const DialogResizableMixin = (superClass) =>
  class VaadinDialogResizableMixin extends superClass {
    static get properties() {
      return {
        /**
         * Set to true to enable resizing the dialog by dragging the corners and edges.
         */
        resizable: {
          type: Boolean,
          value: false,
          reflectToAttribute: true,
        },
      };
    }

    /** @protected */
    ready() {
      super.ready();
      this._originalBounds = {};
      this._originalMouseCoords = {};
      this._resizeListeners = { start: {}, resize: {}, stop: {} };
      this._addResizeListeners();
    }

    /** @private */
    _addResizeListeners() {
      // Note: edge controls added before corners
      ['n', 'e', 's', 'w', 'nw', 'ne', 'se', 'sw'].forEach((direction) => {
        const resizer = document.createElement('div');
        this._resizeListeners.start[direction] = (e) => this._startResize(e, direction);
        this._resizeListeners.resize[direction] = (e) => this._resize(e, direction);
        this._resizeListeners.stop[direction] = () => this._stopResize(direction);
        if (direction.length === 1) {
          resizer.classList.add('edge');
        }
        resizer.classList.add('resizer');
        resizer.classList.add(direction);
        resizer.addEventListener('mousedown', this._resizeListeners.start[direction]);
        resizer.addEventListener('touchstart', this._resizeListeners.start[direction]);
        this.$.overlay.$.resizerContainer.appendChild(resizer);
      });
    }

    /**
     * @param {!MouseEvent | !TouchEvent} e
     * @param {!DialogResizableDirection} direction
     * @protected
     */
    _startResize(e, direction) {
      // Don't initiate when there's more than 1 touch (pinch zoom)
      if (e.type === 'touchstart' && e.touches.length > 1) {
        return;
      }

      if (e.button === 0 || e.touches) {
        e.preventDefault();

        this._originalBounds = this.$.overlay.getBounds();
        const event = getMouseOrFirstTouchEvent(e);
        this._originalMouseCoords = { top: event.pageY, left: event.pageX };
        window.addEventListener('mousemove', this._resizeListeners.resize[direction]);
        window.addEventListener('touchmove', this._resizeListeners.resize[direction]);
        window.addEventListener('mouseup', this._resizeListeners.stop[direction]);
        window.addEventListener('touchend', this._resizeListeners.stop[direction]);
        this.$.overlay.setBounds(this._originalBounds);
        this.$.overlay.setAttribute('has-bounds-set', '');

        const { width, height, top, left } = this._originalBounds;
        this.dispatchEvent(new CustomEvent('resize-start', { detail: { width, height, top, left } }));
      }
    }

    /**
     * @param {!MouseEvent | !TouchEvent} e
     * @param {!DialogResizableDirection} resizer
     * @protected
     */
    _resize(e, resizer) {
      const event = getMouseOrFirstTouchEvent(e);
      if (eventInWindow(event)) {
        const minimumSize = 40;
        resizer.split('').forEach((direction) => {
          switch (direction) {
            case 'n': {
              const height = this._originalBounds.height - (event.pageY - this._originalMouseCoords.top);
              const top = this._originalBounds.top + (event.pageY - this._originalMouseCoords.top);
              if (height > minimumSize) {
                this.top = top;
                this.height = height;
              }
              break;
            }
            case 'e': {
              const width = this._originalBounds.width + (event.pageX - this._originalMouseCoords.left);
              if (width > minimumSize) {
                this.width = width;
              }
              break;
            }
            case 's': {
              const height = this._originalBounds.height + (event.pageY - this._originalMouseCoords.top);
              if (height > minimumSize) {
                this.height = height;
              }
              break;
            }
            case 'w': {
              const width = this._originalBounds.width - (event.pageX - this._originalMouseCoords.left);
              const left = this._originalBounds.left + (event.pageX - this._originalMouseCoords.left);
              if (width > minimumSize) {
                this.left = left;
                this.width = width;
              }
              break;
            }
            default:
              break;
          }
        });
      }
    }

    /**
     * @param {!DialogResizableDirection} direction
     * @protected
     */
    _stopResize(direction) {
      window.removeEventListener('mousemove', this._resizeListeners.resize[direction]);
      window.removeEventListener('touchmove', this._resizeListeners.resize[direction]);
      window.removeEventListener('mouseup', this._resizeListeners.stop[direction]);
      window.removeEventListener('touchend', this._resizeListeners.stop[direction]);
      this.dispatchEvent(new CustomEvent('resize', { detail: this._getResizeDimensions() }));
    }

    /**
     * @return {!DialogResizeDimensions}
     * @protected
     */
    _getResizeDimensions() {
      const { width, height, top, left } = getComputedStyle(this.$.overlay.$.overlay);
      return { width, height, top, left };
    }

    /**
     * Fired when the dialog resize is started.
     *
     * @event resize-start
     */

    /**
     * Fired when the dialog resize is finished.
     *
     * @event resize
     */
  };
