import {
  customElement,
  type TemplateResult,
  property,
  state,
  html,
  css,
  cssManager,
} from '@design.estate/dees-element';
import * as domtools from '@design.estate/dees-domtools';
import { demoFunc } from './dees-input-dropdown.demo.js';
import { DeesInputBase } from '../dees-input-base/dees-input-base.js';
import { cssGeistFontFamily } from '../../00fonts.js';
import { themeDefaultStyles } from '../../00theme.js';

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

@customElement('dees-input-dropdown')
export class DeesInputDropdown extends DeesInputBase<DeesInputDropdown> {
  public static demo = demoFunc;
  public static demoGroup = 'Input';

  // INSTANCE

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

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

  // Add value property for form compatibility
  public get value() {
    return this.selectedOption;
  }

  public set value(val: { option: string; key: string; payload?: any }) {
    this.selectedOption = val;
  }

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

  @state()
  accessor opensToTop: boolean = false;

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

  @state()
  accessor highlightedIndex: number = 0;

  @state()
  accessor isOpened = false;

  @state()
  accessor searchValue: string = '';

  public static styles = [
    themeDefaultStyles,
    ...DeesInputBase.baseStyles,
    cssManager.defaultStyles,
    css`
      /* TODO: Migrate hardcoded values to --dees-* CSS variables */
      * {
        box-sizing: border-box;
      }

      :host {
        font-family: ${cssGeistFontFamily};
        position: relative;
        color: ${cssManager.bdTheme('hsl(0 0% 15%)', 'hsl(0 0% 90%)')};
      }

      .maincontainer {
        display: block;
        position: relative;
      }

      .selectedBox {
        user-select: none;
        position: relative;
        width: 100%;
        height: 40px;
        line-height: 38px;
        padding: 0 40px 0 12px;
        background: transparent;
        border: 1px solid ${cssManager.bdTheme('hsl(0 0% 89.8%)', 'hsl(0 0% 14.9%)')};
        border-radius: 6px;
        transition: all 0.15s ease;
        font-size: 14px;
        color: ${cssManager.bdTheme('hsl(0 0% 9%)', 'hsl(0 0% 95%)')};
        cursor: pointer;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
      }

      .selectedBox:hover:not(.disabled) {
        border-color: ${cssManager.bdTheme('hsl(0 0% 79.8%)', 'hsl(0 0% 20.9%)')};
      }

      .selectedBox:focus-visible {
        outline: none;
        border-color: ${cssManager.bdTheme('hsl(222.2 47.4% 51.2%)', 'hsl(217.2 91.2% 59.8%)')};
        box-shadow: 0 0 0 3px ${cssManager.bdTheme('hsl(222.2 47.4% 51.2% / 0.1)', 'hsl(217.2 91.2% 59.8% / 0.1)')};
      }

      .selectedBox.disabled {
        background: ${cssManager.bdTheme('hsl(0 0% 95.1%)', 'hsl(0 0% 14.9%)')};
        border-color: ${cssManager.bdTheme('hsl(0 0% 89.8%)', 'hsl(0 0% 14.9%)')};
        color: ${cssManager.bdTheme('hsl(0 0% 63.9%)', 'hsl(0 0% 45.1%)')};
        cursor: not-allowed;
        opacity: 0.5;
      }

      /* Dropdown arrow */
      .selectedBox::after {
        content: '';
        position: absolute;
        right: 12px;
        top: 50%;
        transform: translateY(-50%);
        width: 0;
        height: 0;
        border-left: 4px solid transparent;
        border-right: 4px solid transparent;
        border-top: 4px solid ${cssManager.bdTheme('hsl(0 0% 45.1%)', 'hsl(0 0% 63.9%)')};
        transition: transform 0.15s ease;
      }

      .selectedBox.open::after {
        transform: translateY(-50%) rotate(180deg);
      }

      .selectionBox {
        will-change: transform, opacity;
        pointer-events: none;
        transition: all 0.15s ease;
        opacity: 0;
        transform: translateY(-8px) scale(0.98);
        background: ${cssManager.bdTheme('hsl(0 0% 100%)', 'hsl(0 0% 3.9%)')};
        border: 1px solid ${cssManager.bdTheme('hsl(0 0% 89.8%)', 'hsl(0 0% 14.9%)')};
        box-shadow: 0 4px 6px -1px hsl(0 0% 0% / 0.1), 0 2px 4px -2px hsl(0 0% 0% / 0.1);
        min-height: 40px;
        max-height: 300px;
        overflow: hidden;
        border-radius: 6px;
        position: absolute;
        user-select: none;
        margin-top: 4px;
        z-index: 50;
        left: 0;
        right: 0;
      }
      
      .selectionBox.top {
        bottom: calc(100% + 4px);
        top: auto;
        margin-top: 0;
        margin-bottom: 4px;
        transform: translateY(8px) scale(0.98);
      }
      
      .selectionBox.bottom {
        top: 100%;
      }

      .selectionBox.show {
        pointer-events: all;
        transform: translateY(0) scale(1);
        opacity: 1;
      }

      /* Options container */
      .options-container {
        max-height: 250px;
        overflow-y: auto;
        padding: 4px;
      }

      /* Options */
      .option {
        transition: all 0.15s ease;
        line-height: 32px;
        padding: 0 8px;
        border-radius: 4px;
        margin: 2px 0;
        cursor: pointer;
        font-size: 14px;
        color: ${cssManager.bdTheme('hsl(0 0% 15%)', 'hsl(0 0% 90%)')};
      }

      .option.highlighted {
        background: ${cssManager.bdTheme('hsl(0 0% 95.1%)', 'hsl(0 0% 14.9%)')};
      }

      .option:hover {
        background: ${cssManager.bdTheme('hsl(0 0% 95.1%)', 'hsl(0 0% 14.9%)')};
        color: ${cssManager.bdTheme('hsl(0 0% 9%)', 'hsl(0 0% 95%)')};
      }

      /* No options message */
      .no-options {
        padding: 8px;
        text-align: center;
        font-size: 14px;
        color: ${cssManager.bdTheme('hsl(0 0% 45.1%)', 'hsl(0 0% 63.9%)')};
        font-style: italic;
      }

      /* Search */
      .search {
        padding: 4px;
        border-bottom: 1px solid ${cssManager.bdTheme('hsl(0 0% 89.8%)', 'hsl(0 0% 14.9%)')};
        margin-bottom: 4px;
      }
      
      .search.bottom {
        border-bottom: none;
        border-top: 1px solid ${cssManager.bdTheme('hsl(0 0% 89.8%)', 'hsl(0 0% 14.9%)')};
        margin-bottom: 0;
        margin-top: 4px;
      }
      
      .search input {
        display: block;
        width: 100%;
        height: 32px;
        padding: 0 8px;
        background: transparent;
        border: 1px solid ${cssManager.bdTheme('hsl(0 0% 89.8%)', 'hsl(0 0% 14.9%)')};
        border-radius: 4px;
        color: inherit;
        font-size: 14px;
        font-family: inherit;
        outline: none;
        transition: border-color 0.15s ease;
      }

      .search input::placeholder {
        color: ${cssManager.bdTheme('hsl(0 0% 63.9%)', 'hsl(0 0% 45.1%)')};
      }

      .search input:focus {
        border-color: ${cssManager.bdTheme('hsl(222.2 47.4% 51.2%)', 'hsl(217.2 91.2% 59.8%)')};
      }

      /* Scrollbar styling */
      .options-container::-webkit-scrollbar {
        width: 8px;
      }

      .options-container::-webkit-scrollbar-track {
        background: transparent;
      }

      .options-container::-webkit-scrollbar-thumb {
        background: ${cssManager.bdTheme('hsl(0 0% 89.8%)', 'hsl(0 0% 14.9%)')};
        border-radius: 4px;
      }

      .options-container::-webkit-scrollbar-thumb:hover {
        background: ${cssManager.bdTheme('hsl(0 0% 79.8%)', 'hsl(0 0% 20.9%)')};
      }
    `,
  ];

  public render(): TemplateResult {
    return html`
      <div class="input-wrapper">
        <dees-label .label=${this.label} .description=${this.description} .required=${this.required}></dees-label>
        <div class="maincontainer">
          <div
            class="selectedBox ${this.isOpened ? 'open' : ''} ${this.disabled ? 'disabled' : ''}"
            @click="${() => !this.disabled && this.toggleSelectionBox()}"
            tabindex="${this.disabled ? '-1' : '0'}"
            @keydown="${this.handleSelectedBoxKeydown}"
          >
            ${this.selectedOption?.option || 'Select an option'}
          </div>
          <div class="selectionBox ${this.isOpened ? 'show' : ''} ${this.opensToTop ? 'top' : 'bottom'}">
            ${this.enableSearch
              ? html`
                  <div class="search">
                    <input 
                      type="text" 
                      placeholder="Search options..." 
                      .value="${this.searchValue}"
                      @input="${this.handleSearch}"
                      @click="${(e: Event) => e.stopPropagation()}"
                      @keydown="${this.handleSearchKeydown}"
                    />
                  </div>
                `
              : null}
            <div class="options-container">
              ${this.filteredOptions.length === 0
                ? html`<div class="no-options">No options found</div>`
                : this.filteredOptions.map((option, index) => {
                    const isHighlighted = this.highlightedIndex === index;
                    return html`
                      <div
                        class="option ${isHighlighted ? 'highlighted' : ''}"
                        @click="${() => this.updateSelection(option)}"
                        @mouseenter="${() => this.highlightedIndex = index}"
                      >
                        ${option.option}
                      </div>
                    `;
                  })
              }
            </div>
          </div>
        </div>
      </div>
    `;
  }

  async connectedCallback() {
    super.connectedCallback();
    this.handleClickOutside = this.handleClickOutside.bind(this);
  }

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

  updated(changedProperties: Map<string, any>) {
    super.updated(changedProperties);
    
    if (changedProperties.has('options')) {
      this.filteredOptions = this.options;
    }
  }

  public async updateSelection(selectedOption: { option: string; key: string; payload?: any }) {
    this.selectedOption = selectedOption;
    this.isOpened = false;
    this.searchValue = '';
    this.filteredOptions = this.options;
    this.highlightedIndex = 0;

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

  private handleClickOutside = (event: MouseEvent) => {
    const path = event.composedPath();
    if (!path.includes(this)) {
      this.isOpened = false;
      this.searchValue = '';
      this.filteredOptions = this.options;
      document.removeEventListener('click', this.handleClickOutside);
    }
  };
  
  public async toggleSelectionBox() {
    this.isOpened = !this.isOpened;
    
    if (this.isOpened) {
      // Check available space and set position
      const selectedBox = this.shadowRoot.querySelector('.selectedBox') as HTMLElement;
      const rect = selectedBox.getBoundingClientRect();
      const spaceBelow = window.innerHeight - rect.bottom;
      const spaceAbove = rect.top;
      
      // Determine if we should open upwards
      this.opensToTop = spaceBelow < 300 && spaceAbove > spaceBelow;
      
      // Focus search input if present
      await this.updateComplete;
      const searchInput = this.shadowRoot.querySelector('.search input') as HTMLInputElement;
      if (searchInput) {
        searchInput.focus();
      }
      
      // Add click outside listener
      setTimeout(() => {
        document.addEventListener('click', this.handleClickOutside);
      }, 0);
    } else {
      // Cleanup
      this.searchValue = '';
      this.filteredOptions = this.options;
      document.removeEventListener('click', this.handleClickOutside);
    }
  }

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

  private handleKeyDown(event: KeyboardEvent): void {
    const key = event.key;
    const maxIndex = this.filteredOptions.length - 1;

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

  private handleSearchKeydown(event: KeyboardEvent): void {
    if (event.key === 'ArrowDown' || event.key === 'ArrowUp' || event.key === 'Enter') {
      this.handleKeyDown(event);
    }
  }

  private handleSelectedBoxKeydown(event: KeyboardEvent) {
    if (this.disabled) return;
    
    if (event.key === 'Enter' || event.key === ' ') {
      event.preventDefault();
      this.toggleSelectionBox();
    } else if (event.key === 'ArrowDown' || event.key === 'ArrowUp') {
      event.preventDefault();
      if (!this.isOpened) {
        this.toggleSelectionBox();
      }
    } else if (event.key === 'Escape') {
      event.preventDefault();
      if (this.isOpened) {
        this.isOpened = false;
      }
    }
  }

  public getValue(): { option: string; key: string; payload?: any } {
    return this.selectedOption;
  }

  public setValue(value: { option: string; key: string; payload?: any }): void {
    this.selectedOption = value;
  }
  
  async disconnectedCallback() {
    await super.disconnectedCallback();
    document.removeEventListener('click', this.handleClickOutside);
  }
}