import {
  customElement,
  DeesElement,
  type TemplateResult,
  property,
  state,
  html,
  css,
  cssManager,
  type CSSResult,
} from '@design.estate/dees-element';
import * as domtools from '@design.estate/dees-domtools';
import { demoFunc } from './dees-input-dropdown.demo.js';
import { DeesWindowLayer } from './dees-windowlayer.js';

declare global {
  interface HTMLElementTagNameMap {
    'dees-input-dropdown': DeesInputDropdown;
  }
}

@customElement('dees-input-dropdown')
export class DeesInputDropdown extends DeesElement {
  public static demo = demoFunc;

  // INSTANCE
  public changeSubject = new domtools.plugins.smartrx.rxjs.Subject();

  @property({
    type: String,
    reflect: true,
  })
  public label: string = 'Label';

  @property()
  public key: string;

  @property()
  public options: { option: string; key: string; payload?: any }[] = [];

  @property()
  public selectedOption: { option: string; key: string; payload?: any } = null;

  @property({
    type: Boolean,
  })
  public required: boolean = false;

  @property({
    type: Boolean,
  })
  public enableSearch: boolean = true;

  @property({
    type: Boolean,
  })
  public disabled: boolean = false;

  @state()
  public opensToTop: boolean = false;

  @state()
  private filteredOptions: { option: string; key: string; payload?: any }[] = [];

  @state()
  private highlightedIndex: number = 0;

  @state()
  public isOpened = false;

  public static styles = [
    cssManager.defaultStyles,
    css`
      * {
        box-sizing: border-box;
      }

      :host {
        font-family: Roboto;
        position: relative;
        display: block;
        color: ${cssManager.bdTheme('#222', '#fff')};
        margin-bottom: 24px;
      }

      .maincontainer {
        display: block;
      }

      .label {
        font-size: 14px;
        margin-bottom: 8px;
      }

      .selectedBox {
        user-select: none;
        position: relative;
        max-width: 420px;
        height: 40px;
        line-height: 40px;
        padding: 0px 8px;
        background: ${cssManager.bdTheme('#fafafa', '#222222')};
        box-shadow: ${cssManager.bdTheme('0px 1px 4px rgba(0,0,0,0.3)', 'none')};
        border-radius: 3px;
        border-top: ${cssManager.bdTheme('1px solid #CCC', '1px solid #ffffff10')};
        border-bottom: ${cssManager.bdTheme('1px solid #CCC', '1px solid #222')};
        transition: all 0.2s ease;
        font-size: 16px;
        color: ${cssManager.bdTheme('#222', '#ccc')};
      }

      .selectedBox:hover {
        filter: ${cssManager.bdTheme('brightness(0.95)', 'brightness(1.1)')};
      }

      .accentBottom {
        filter: none !important;
      }

      .accentTop {
        filter: none !important;
      }

      .selectionBox {
        will-change: transform;
        pointer-events: none;
        transition: all 0.2s ease;
        opacity: 0;
        background: ${cssManager.bdTheme('#ffffff', '#222222')};
        max-width: 420px;
        box-shadow: 0px 0px 5px rgba(0, 0, 0, 0.2);
        min-height: 40px;
        border-radius: 8px;
        padding: 4px 8px;
        position: absolute;
        user-select: none;
        margin: 3px 0px 0px 0px;
        border-top: ${cssManager.bdTheme('1px solid #CCC', '1px solid #ffffff10')};
      }
      .selectionBox.top {
        transform: translate(0px, 4px);
      }
      .selectionBox.bottom {
        transform: translate(0px, -4px);
      }

      .selectionBox.show {
        pointer-events: all;
        transform: scale(1, 1) translate(0px, 0px);
        opacity: 1;
        box-shadow: 0px 0px 8px rgba(0, 0, 0, 0.8);
      }

      .option {
        transition: all 0.1s;
        line-height: 32px;
        padding: 0px 4px;
        border-radius: 3px;
        margin: 4px 0px;
      }

      .option.highlighted {
        border-left: 2px solid #0069f2;
        padding-left: 6px;
        background: #ffffff20;
      }

      .option:hover {
        color: #fff;
        padding-left: 8px;
        background: #0069f2;
      }

      .search.top {
        padding-top: 4px;
      }
      .search.bottom {
        padding-bottom: 4px;
      }
      .search input {
        display: block;
        background: none;
        border: none;
        height: 24px;
        color: inherit;
        text-align: left;
        font-size: 12px;
        font-weight: 600;
        width: 100%;
        margin: auto;
      }

      .search.top input {
        border-bottom: 1px dotted #333;
      }
      .search.bottom input {
        border-top: 1px dotted #333;
      }

      .search input:focus {
        outline: none;
      }
    `,
  ];

  public render(): TemplateResult {
    return html`
      <div class="maincontainer" @keydown="${this.isOpened ? this.handleKeyDown : undefined}">
        ${this.label ? html`<div class="label">${this.label}</div>` : html``}
        <div class="selectionBox">
          ${this.enableSearch && !this.opensToTop
            ? html`
                <div class="search top">
                  <input type="text" placeholder="Search" @input="${this.handleSearch}" />
                </div>
              `
            : null}
          ${this.filteredOptions.map((option, index) => {
            const isHighlighted = this.highlightedIndex === index;
            return html`
              <div
                class="option ${isHighlighted ? 'highlighted' : ''}"
                @click=${() => {
                  this.updateSelection(option);
                }}
              >
                ${option.option}
              </div>
            `;
          })}
          ${this.enableSearch && this.opensToTop
            ? html`
                <div class="search bottom">
                  <input type="text" placeholder="Search" @input="${this.handleSearch}" />
                </div>
              `
            : null}
        </div>
        <div
          class="selectedBox"
          @click="${(event) => {
            if (!this.isElevated) {
              this.toggleSelectionBox();
            } else {
              this.updateSelection(this.selectedOption);
            }
          }}"
        >
          ${this.selectedOption?.option || 'Select...'} 
        </div>
      </div>
    `;
  }

  firstUpdated() {
    this.selectedOption = this.selectedOption || null;
    this.filteredOptions = this.options; // Initialize filteredOptions
  }

  public async updateSelection(selectedOption) {
    this.selectedOption = selectedOption;

    this.dispatchEvent(
      new CustomEvent('selectedOption', {
        detail: selectedOption,
        bubbles: true,
      })
    );
    if (this.isElevated) {
      this.toggleSelectionBox();
    }
    this.changeSubject.next(this);
  }

  private isElevated: boolean = false;
  private windowOverlay: DeesWindowLayer;
  public async toggleSelectionBox() {
    this.isOpened = !this.isOpened;
    const domtoolsInstance = await this.domtoolsPromise;
    const selectedBox: HTMLElement = this.shadowRoot.querySelector('.selectedBox');
    const selectionBox: HTMLElement = this.shadowRoot.querySelector('.selectionBox');
    if (!this.isElevated) {
      this.windowOverlay = await DeesWindowLayer.createAndShow({
        blur: false,
      });
      const elevatedDropdown = new DeesInputDropdown();
      elevatedDropdown.isElevated = true;
      elevatedDropdown.label = this.label;
      elevatedDropdown.enableSearch = this.enableSearch;
      elevatedDropdown.required = this.required;
      elevatedDropdown.disabled = this.disabled;
      elevatedDropdown.style.position = 'fixed';
      elevatedDropdown.style.top = this.getBoundingClientRect().top + 'px';
      elevatedDropdown.style.left = this.getBoundingClientRect().left + 'px';
      elevatedDropdown.style.width = this.clientWidth + 'px';
      elevatedDropdown.options = this.options;
      elevatedDropdown.selectedOption = this.selectedOption;
      elevatedDropdown.highlightedIndex = elevatedDropdown.selectedOption ? elevatedDropdown.options.indexOf(
        elevatedDropdown.options.find((option) => option.key === this.selectedOption.key)
      ) : -1;
      console.log(elevatedDropdown.options);
      console.log(elevatedDropdown.selectedOption);
      console.log(elevatedDropdown.highlightedIndex);
      this.windowOverlay.appendChild(elevatedDropdown);
      await domtoolsInstance.convenience.smartdelay.delayFor(0);
      elevatedDropdown.toggleSelectionBox();
      const destroyOverlay = async () => {
        (elevatedDropdown.shadowRoot.querySelector('.selectionBox') as HTMLElement).style.opacity =
          '0';
        elevatedDropdown.removeEventListener('selectedOption', handleSelection);
        this.windowOverlay.removeEventListener('clicked', destroyOverlay);
        this.windowOverlay.destroy();
      };
      const handleSelection = async (event) => {
        await this.updateSelection(elevatedDropdown.selectedOption);
        destroyOverlay();
      };
      elevatedDropdown.addEventListener('selectedOption', handleSelection);
      this.windowOverlay.addEventListener('clicked', destroyOverlay);
    } else {
      if (!selectionBox.classList.contains('show')) {
        selectionBox.style.width = selectedBox.clientWidth + 'px';
        const spaceData = selectedBox.getBoundingClientRect();
        if (300 > window.innerHeight - spaceData.bottom) {
          this.opensToTop = true;
          selectedBox.classList.add('accentTop');
          selectionBox.classList.add('top');
          selectionBox.style.bottom = selectedBox.clientHeight + 2 + 'px';
        } else {
          selectedBox.classList.add('accentBottom');
          selectionBox.classList.add('bottom');
          this.opensToTop = false;
          const labelOffset = this.label ? 24 : 0;
          selectionBox.style.top = selectedBox.clientHeight + labelOffset + 'px';
        }
        await domtoolsInstance.convenience.smartdelay.delayFor(0);
        const searchInput = selectionBox.querySelector('input');
        searchInput?.focus();
        selectionBox.classList.add('show');
      } else {
        selectedBox.style.pointerEvents = 'none';
        selectionBox.classList.remove('show');
        // selectedBox.style.opacity = '0';
      }
    }
  }

  private handleSearch(event: Event): void {
    const searchTerm = (event.target as HTMLInputElement).value.toLowerCase();
    this.filteredOptions = this.options.filter((option) =>
      option.option.toLowerCase().includes(searchTerm)
    );
    this.highlightedIndex = 0; // Reset highlighted index
  }

  private handleKeyDown(event: KeyboardEvent): void {
    if (!this.isOpened) {
      console.log('discarded key event. Check why this function is called.');
      return;
    }
    const key = event.key;
    const maxIndex = this.filteredOptions.length - 1;

    if (key === 'ArrowDown') {
      this.highlightedIndex = this.highlightedIndex + 1 > maxIndex ? 0 : this.highlightedIndex + 1;
      event.preventDefault();
    } else if (key === 'ArrowUp') {
      this.highlightedIndex = this.highlightedIndex - 1 < 0 ? maxIndex : this.highlightedIndex - 1;
      event.preventDefault();
    } else if (key === 'Enter') {
      this.updateSelection(this.filteredOptions[this.highlightedIndex]);
      event.preventDefault();
    }
  }
}