import { injectStyle } from '@descope-ui/common/components-helpers';
import { compose } from '../../helpers';
import { forwardAttrs, getComponentName } from '../../helpers/componentHelpers';
import {
  createStyleMixin,
  draggableMixin,
  createProxy,
  componentNameValidationMixin,
  portalMixin,
} from '../../mixins';

export const componentName = getComponentName('modal');

const observedAttrs = ['opened'];

const customMixin = (superclass) =>
  class ModalMixinClass extends superclass {
    static get observedAttributes() {
      return [].concat(superclass.observedAttributes || [], observedAttrs);
    }

    get opened() {
      return this.getAttribute('opened') === 'true';
    }

    handleOpened() {
      if (this.opened) {
        this.style.display = '';
      } else {
        this.style.display = 'none';
      }
    }

    attributeChangedCallback(name, oldValue, newValue) {
      super.attributeChangedCallback?.(name, oldValue, newValue);

      if (name === 'opened') {
        this.handleOpened();
      }
    }

    init() {
      super.init?.();
      this.style.display = 'none';

      // vaadin-dialog might not be loaded in time
      // in order to make sure it's loaded before this block is running
      // we are wrapping it with setTimeout
      setTimeout(() => {
        // we want to sync descope-modal content through vaadin-dialog into the overlay
        // so we are adding a slot to the overlay, which allows us to forward the content from
        // vaadin-dialog to vaadin-dialog-overlay
        this.baseElement.shadowRoot
          .querySelector('vaadin-dialog-overlay')
          .appendChild(document.createElement('slot'));

        this.#overrideOverlaySettings();
        forwardAttrs(this, this.baseElement, { includeAttrs: ['opened'] });

        // we need to always open the modal in `opened=false`
        // to prevent it from rendering outside the dialog
        // first, we have to run `overrideOverlaySettings` to setup
        // the component.
        this.handleOpened();
      });
    }

    // the default vaadin behavior is to attach the overlay to the body when opened
    // we do not want that because it's difficult to style the overlay in this way
    // so we override it to open inside the shadow DOM
    #overrideOverlaySettings() {
      const overlay = this.baseElement.shadowRoot.querySelector('vaadin-dialog-overlay');

      overlay._attachOverlay = () => {
        overlay.bringToFront();
        injectStyle(
          `
          :host {
            display: flex!important;
          }
          `,
          this.baseElement
        );
      };
      overlay._detachOverlay = () => {
        this.baseElement.style.display = 'none';
      };
      overlay._enterModalState = () => {};

      overlay.close = () => false;
    }
  };

export const ModalClass = compose(
  createStyleMixin({
    mappings: {
      overlayBackdropColor: { property: () => ModalClass.cssVarList.overlay.backdropColor },
      overlayBackgroundColor: { property: () => ModalClass.cssVarList.overlay.backgroundColor },
      overlayShadow: { property: () => ModalClass.cssVarList.overlay.shadow },
      overlayWidth: { property: () => ModalClass.cssVarList.overlay.width },
      overlayBorderWidth: { property: () => ModalClass.cssVarList.overlay.borderWidth },
      overlayBorderStyle: { property: () => ModalClass.cssVarList.overlay.borderStyle },
      overlayBorderColor: { property: () => ModalClass.cssVarList.overlay.borderColor },
      overlayBorderRadius: { property: () => ModalClass.cssVarList.overlay.borderRadius },
    },
  }),
  portalMixin({
    name: 'overlay',
    selector: '',
    mappings: {
      hostDisplay: {
        selector: () => ':host(.descope-modal)',
        property: 'display',
        important: true,
      },
      backgroundColor: [
        { selector: () => '::part(content)', property: 'background-color' },
        { selector: () => '::part(overlay)', property: 'background-color' },
      ],
      backdropColor: {
        selector: () => '::part(backdrop)',
        property: 'background-color',
      },
      borderStyle: {
        selector: () => '::part(content)',
        property: 'border-style',
      },
      borderWidth: {
        selector: () => '::part(content)',
        property: 'border-width',
      },
      borderColor: {
        selector: () => '::part(content)',
        property: 'border-color',
      },
      borderRadius: {
        selector: () => '::part(content)',
        property: 'border-radius  ',
      },
      width: { selector: () => '::part(overlay)', property: 'width' },
      shadow: { selector: () => '::part(overlay)', property: 'box-shadow' },
    },
    forward: {
      include: false,
      attributes: ['opened', 'style'],
    },
  }),
  draggableMixin,
  componentNameValidationMixin,
  customMixin
)(
  createProxy({
    slots: [''],
    wrappedEleName: 'vaadin-dialog',
    style: () => `
      vaaadin-dialog {
        display: flex!important;
      }
    `,
    excludeAttrsSync: ['tabindex', 'opened', 'style'],
    componentName,
  })
);
