/**
 * Copyright Aquera Inc 2023
 *
 * This source code is licensed under the BSD-3-Clause license found in the
 * LICENSE file in the root directory of this source tree.
 */

import {
  LitElement,
  html,
  CSSResultArray,
  TemplateResult,
} from 'lit';
import { customElement, property } from 'lit/decorators.js';
import { styles } from './nile-inline-edit.css';
import NileElement from '../internal/nile-element';
import {
  getDisplayValue,
  updateSlottedElementValue,
  handleDocumentFocusIn,
  handleDocumentMouseDown,
} from './nile-inline-edit-utils';

/**
 * Nile inline-edit component.
 *
 * @tag nile-inline-edit
 *
 */
@customElement('nile-inline-edit')
export class NileInlineEdit extends NileElement {
  /**
   * The styles for nile-inline-edit
   * @remarks If you are extending this class you can extend the base styles with super. Eg `return [super(), myCustomStyles]`
   */
  public static get styles(): CSSResultArray {
    return [styles];
  }

  /** Gives the label to the Inline Edit */
  @property({ type: String, reflect: true }) label = '';

  /** Gives the Placeholder to the Inline Edit */
  @property({ type: String, reflect: true }) placeholder = '';

  /** Open prop for displaying default slot in Inline Edit */
  @property({ type: Boolean, reflect: true }) open = false;

  /** Gives the Value to the Inline Edit */
  @property({ type: String, reflect: true }) value = '';

  /** Maximum length for the placeholder value. Values longer than this will be truncated */
  @property({ type: Number, attribute: 'max-placeholder-length' }) maxPlaceholderLength: number = 25;

  /** Enables automatic closing when focus moves outside the component or when clicking outside */
  @property({ type: Boolean, attribute: 'auto-close' }) autoClose: boolean = false;

  /** Disables the inline edit, preventing it from being opened */
  @property({ type: Boolean, reflect: true}) disabled: boolean = false;

  /* #endregion */

  /* #region Methods */

  /**
   * Render method
   * @slot This is a slot test
   */

  private handleCloseResult(result: { shouldClose: boolean; newValue: string | null }) {
    if (result.shouldClose) {
      if (result.newValue !== null) {
        this.value = result.newValue;
      }
      this.open = false;
    }
  }

  private handleDocumentFocusInWrapper = (event: FocusEvent) => {
    const result = handleDocumentFocusIn(event, this, this.open);
    this.handleCloseResult(result);
  };

  private handleDocumentMouseDownWrapper = (event: MouseEvent) => {
    const result = handleDocumentMouseDown(event, this, this.open);
    this.handleCloseResult(result);
  };

  connectedCallback() {
    super.connectedCallback();
  }

  updated(changedProperties: Map<string, unknown>) {
    super.updated(changedProperties);
    
    if (changedProperties.has('open') && this.autoClose) {
      if (this.open) {
        updateSlottedElementValue(this.updateComplete, this.shadowRoot, this.value);
        document.addEventListener('focusin', this.handleDocumentFocusInWrapper, true);
        document.addEventListener('mousedown', this.handleDocumentMouseDownWrapper, true);
      } else {
        document.removeEventListener('focusin', this.handleDocumentFocusInWrapper, true);
        document.removeEventListener('mousedown', this.handleDocumentMouseDownWrapper, true);
      }
    }
  }

  disconnectedCallback() {
    super.disconnectedCallback();
    document.removeEventListener('focusin', this.handleDocumentFocusInWrapper, true);
    document.removeEventListener('mousedown', this.handleDocumentMouseDownWrapper, true);
  }

  private handleClick() {
    if (this.disabled) return;
    this.open = true;
  }
  public render(): TemplateResult {
    // Use truncated value for display, or placeholder if empty
    const displayValue = this.autoClose ? getDisplayValue(this.value, this.maxPlaceholderLength) : this.value;
    const textInsideContainer = displayValue || this.placeholder;
    return html`
      <div class="inline__edit--label" part="label">${this.label}</div>
      ${this.open
        ? html` <slot class="inline__edit--open--container" part="base"> </slot>`
        : html` <div class="inline__edit--container" part="container" @click=${this.handleClick}>
            ${textInsideContainer}
          </div>`}
    `;
  }

  /* #endregion */
}

export default NileInlineEdit;

declare global {
  interface HTMLElementTagNameMap {
    'nile-inline-edit': NileInlineEdit;
  }
}
