/**
 * 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 { html, nothing } from 'lit';
import { customElement, property, query } from 'lit/decorators.js';
import { classMap } from 'lit/directives/class-map.js';
import type { CSSResultGroup } from 'lit';

import { styles } from './nile-nav-tab.css';
import '../nile-icon-button/nile-icon-button';
import { MouseKey } from '../internal/enum';
import { watch } from '../internal/watch';
import NileElement from '../internal/nile-element';
import '../nile-link/nile-link';
let id = 0;

@customElement('nile-nav-tab')
export class NileNavTab extends NileElement {
  static styles: CSSResultGroup = styles;

  private readonly attrId = ++id;
  private readonly componentId = `nile-nav-tab-${this.attrId}`;

  @query('.nav-tab') navTab!: HTMLElement;

  /** The name of the tab panel this tab is associated with. */
  @property({ reflect: true }) panel = '';

  /** Draws the tab in an active state. */
  @property({ type: Boolean, reflect: true }) active = false;

  /** Makes the tab closable and shows a close button. */
  @property({ type: Boolean }) closable = false;

  /** Disables the tab and prevents selection. */
  @property({ type: Boolean, reflect: true }) disabled = false;

  @property({ type: Boolean, reflect: true }) centered = false;

  @property({ type: String, reflect: true }) link?: string;

  connectedCallback() {
    super.connectedCallback();
    this.setAttribute('role', 'tab');
    this.syncA11yState();
  }

  firstUpdated() {
    this.syncA11yState();
    this.updateAccessibleName();
  }

  updated() {
    this.syncA11yState();
    this.updateAccessibleName();
  }

  private syncA11yState() {
    this.id = this.id || this.componentId;
    this.tabIndex = this.disabled ? -1 : this.active ? 0 : -1;

    this.setAttribute('aria-selected', this.active ? 'true' : 'false');
    this.setAttribute('aria-disabled', this.disabled ? 'true' : 'false');

    if (this.disabled) {
      this.setAttribute('aria-hidden', 'true');
    } else {
      this.removeAttribute('aria-hidden');
    }
  }

  /**
   * Give the host element the accessible name, since nile-link is hidden
   * from the accessibility tree.
   * Author `aria-label` (without `data-auto-aria-label`) is never overwritten so icon-only tabs can keep explicit names.
   * Auto-derived names set `data-auto-aria-label="true"` so slot/text updates can refresh them.
   */
  private updateAccessibleName() {
    const userDefinedAriaLabel =
      this.hasAttribute('aria-label') && this.getAttribute('data-auto-aria-label') !== 'true';

    if (userDefinedAriaLabel) {
      return;
    }

    const label = (this.textContent || '').replace(/\s+/g, ' ').trim();

    if (label) {
      this.setAttribute('aria-label', label);
      this.setAttribute('data-auto-aria-label', 'true');
    } else {
      this.removeAttribute('aria-label');
      this.removeAttribute('data-auto-aria-label');
    }
  }

  private handleCloseClick(event: Event) {
    event.preventDefault();
    event.stopPropagation();
    this.emit('nile-close');
  }

  private handleTabClick(event: MouseEvent) {
    if (this.disabled) {
      event.preventDefault();
      event.stopPropagation();
      return;
    }
    const isModifiedClick =
      Object.values(MouseKey).some(key => event[key as keyof MouseEvent]) ||
      event.button !== 0;

    if (isModifiedClick) {
      return;
    }

    event.preventDefault();
  }

  @watch('active')
  handleActiveChange() {
    this.syncA11yState();
  }

  @watch('disabled')
  handleDisabledChange() {
    this.syncA11yState();
  }

  focus(options?: FocusOptions) {
    super.focus(options);
  }

  blur() {
    super.blur();
  }

  render() {
    this.id = this.id || this.componentId;

    return html`
      <li part="base tab" class="nav-tab-container" role="presentation">
        <nile-link
          class=${classMap({
            'nav-tab': true,
            'tab--centered': this.centered,
            'nav-tab--active': this.active,
            'nav-tab--closable': this.closable,
            'nav-tab--disabled': this.disabled
          })}
          tabindex="-1"
          role="none"
          href=${this.link || nothing}
          aria-hidden="true"
          exportparts="
            base:link,
            prefix:link-prefix,
            label:link-label,
            suffix:link-suffix
          "
          @click=${this.handleTabClick}
        >
          <slot name="prefix" @slotchange=${this.updateAccessibleName}></slot>
          <span part="name"><slot @slotchange=${this.updateAccessibleName}></slot></span>
          <slot name="suffix" @slotchange=${this.updateAccessibleName}></slot>

          ${this.closable
            ? html`
                <nile-icon-button
                  part="close-button"
                  exportparts="base:close-button__base"
                  name="var(--nile-icon-close, var(--ng-icon-x-close))"
                  library="system"
                  label="close"
                  class="nav-tab__close-button"
                  ?disabled=${this.disabled}
                  @click=${this.handleCloseClick}
                  tabindex="-1"
                ></nile-icon-button>
              `
            : nothing}
        </nile-link>
      </li>
    `;
  }
}

export default NileNavTab;

declare global {
  interface HTMLElementTagNameMap {
    'nile-nav-tab': NileNavTab;
  }
}