import { Component, Input, Output, EventEmitter, ChangeDetectionStrategy, ViewEncapsulation, signal, computed } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
import { 
  faChevronRight, 
  faChevronLeft, 
  faAnglesRight, 
  faAnglesLeft,
  faSearch,
  faTimes
} from '@fortawesome/free-solid-svg-icons';

export interface TransferListItem {
  id: string | number;
  label: string;
  disabled?: boolean;
  data?: any;
}

export type TransferListSize = 'sm' | 'md' | 'lg';

@Component({
  selector: 'ui-transfer-list',
  standalone: true,
  imports: [CommonModule, FormsModule, FontAwesomeModule],
  changeDetection: ChangeDetectionStrategy.OnPush,
  encapsulation: ViewEncapsulation.None,
  template: `
    <div 
      class="ui-transfer-list"
      [class.ui-transfer-list--{{size}}]="size"
      [class.ui-transfer-list--disabled]="disabled"
      role="application"
      [attr.aria-label]="ariaLabel || 'Transfer list'"
    >
      <!-- Source List -->
      <div class="ui-transfer-list__panel ui-transfer-list__panel--source">
        <div class="ui-transfer-list__header">
          <h3 class="ui-transfer-list__title">{{ sourceTitle }}</h3>
          @if (showSearch) {
            <div class="ui-transfer-list__search">
              <fa-icon [icon]="faSearch" class="ui-transfer-list__search-icon"></fa-icon>
              <input
                type="text"
                class="ui-transfer-list__search-input"
                [(ngModel)]="sourceSearchTerm"
                [placeholder]="searchPlaceholder"
                [disabled]="disabled"
                (input)="updateSourceSearch()"
              />
              @if (sourceSearchTerm()) {
                <button
                  type="button"
                  class="ui-transfer-list__search-clear"
                  (click)="clearSourceSearch()"
                  [disabled]="disabled"
                  aria-label="Clear search"
                >
                  <fa-icon [icon]="faTimes"></fa-icon>
                </button>
              }
            </div>
          }
          @if (showSelectAll) {
            <label class="ui-transfer-list__select-all">
              <input
                type="checkbox"
                [checked]="isAllSourceSelected()"
                [indeterminate]="isSourceIndeterminate()"
                [disabled]="disabled || filteredSourceItems().length === 0"
                (change)="toggleAllSource($event)"
              />
              <span>Select all ({{ getSourceSelectedCount() }}/{{ filteredSourceItems().length }})</span>
            </label>
          }
        </div>
        
        <div class="ui-transfer-list__list-container">
          <div 
            class="ui-transfer-list__list"
            role="listbox"
            [attr.aria-label]="sourceTitle + ' items'"
            tabindex="0"
            (keydown)="handleSourceKeydown($event)"
          >
            @if (filteredSourceItems().length === 0) {
              <div class="ui-transfer-list__empty" role="option">
                @if (sourceSearchTerm()) {
                  No items match your search
                } @else {
                  No items available
                }
              </div>
            } @else {
              @for (item of filteredSourceItems(); track item.id) {
                <div
                  class="ui-transfer-list__item"
                  [class.ui-transfer-list__item--selected]="isSourceItemSelected(item.id)"
                  [class.ui-transfer-list__item--disabled]="disabled || item.disabled"
                  role="option"
                  [attr.aria-selected]="isSourceItemSelected(item.id)"
                  [attr.aria-disabled]="disabled || item.disabled"
                  [tabindex]="disabled || item.disabled ? -1 : 0"
                  (click)="toggleSourceItem(item)"
                  (keydown)="handleItemKeydown($event, item, 'source')"
                >
                  @if (showCheckboxes) {
                    <input
                      type="checkbox"
                      class="ui-transfer-list__checkbox"
                      [checked]="isSourceItemSelected(item.id)"
                      [disabled]="disabled || item.disabled"
                      (change)="toggleSourceItem(item)"
                      tabindex="-1"
                    />
                  }
                  <span class="ui-transfer-list__item-label">{{ item.label }}</span>
                </div>
              }
            }
          </div>
        </div>
        
        <div class="ui-transfer-list__footer">
          {{ getSourceSelectedCount() }} of {{ filteredSourceItems().length }} selected
        </div>
      </div>

      <!-- Transfer Controls -->
      <div class="ui-transfer-list__controls">
        <button
          type="button"
          class="ui-transfer-list__control-btn"
          [disabled]="disabled || selectedSourceItems().length === 0"
          (click)="moveSelectedToTarget()"
          [attr.aria-label]="'Move ' + selectedSourceItems().length + ' selected items to ' + targetTitle"
          title="Move selected items"
        >
          <fa-icon [icon]="faChevronRight"></fa-icon>
        </button>
        
        @if (showMoveAll) {
          <button
            type="button"
            class="ui-transfer-list__control-btn"
            [disabled]="disabled || filteredSourceItems().length === 0"
            (click)="moveAllToTarget()"
            [attr.aria-label]="'Move all ' + filteredSourceItems().length + ' items to ' + targetTitle"
            title="Move all items"
          >
            <fa-icon [icon]="faAnglesRight"></fa-icon>
          </button>
        }
        
        @if (showMoveAll) {
          <button
            type="button"
            class="ui-transfer-list__control-btn"
            [disabled]="disabled || filteredTargetItems().length === 0"
            (click)="moveAllToSource()"
            [attr.aria-label]="'Move all ' + filteredTargetItems().length + ' items back to ' + sourceTitle"
            title="Move all items back"
          >
            <fa-icon [icon]="faAnglesLeft"></fa-icon>
          </button>
        }
        
        <button
          type="button"
          class="ui-transfer-list__control-btn"
          [disabled]="disabled || selectedTargetItems().length === 0"
          (click)="moveSelectedToSource()"
          [attr.aria-label]="'Move ' + selectedTargetItems().length + ' selected items back to ' + sourceTitle"
          title="Move selected items back"
        >
          <fa-icon [icon]="faChevronLeft"></fa-icon>
        </button>
      </div>

      <!-- Target List -->
      <div class="ui-transfer-list__panel ui-transfer-list__panel--target">
        <div class="ui-transfer-list__header">
          <h3 class="ui-transfer-list__title">{{ targetTitle }}</h3>
          @if (showSearch) {
            <div class="ui-transfer-list__search">
              <fa-icon [icon]="faSearch" class="ui-transfer-list__search-icon"></fa-icon>
              <input
                type="text"
                class="ui-transfer-list__search-input"
                [(ngModel)]="targetSearchTerm"
                [placeholder]="searchPlaceholder"
                [disabled]="disabled"
                (input)="updateTargetSearch()"
              />
              @if (targetSearchTerm()) {
                <button
                  type="button"
                  class="ui-transfer-list__search-clear"
                  (click)="clearTargetSearch()"
                  [disabled]="disabled"
                  aria-label="Clear search"
                >
                  <fa-icon [icon]="faTimes"></fa-icon>
                </button>
              }
            </div>
          }
          @if (showSelectAll) {
            <label class="ui-transfer-list__select-all">
              <input
                type="checkbox"
                [checked]="isAllTargetSelected()"
                [indeterminate]="isTargetIndeterminate()"
                [disabled]="disabled || filteredTargetItems().length === 0"
                (change)="toggleAllTarget($event)"
              />
              <span>Select all ({{ getTargetSelectedCount() }}/{{ filteredTargetItems().length }})</span>
            </label>
          }
        </div>
        
        <div class="ui-transfer-list__list-container">
          <div 
            class="ui-transfer-list__list"
            role="listbox"
            [attr.aria-label]="targetTitle + ' items'"
            tabindex="0"
            (keydown)="handleTargetKeydown($event)"
          >
            @if (filteredTargetItems().length === 0) {
              <div class="ui-transfer-list__empty" role="option">
                @if (targetSearchTerm()) {
                  No items match your search
                } @else {
                  No items selected
                }
              </div>
            } @else {
              @for (item of filteredTargetItems(); track item.id) {
                <div
                  class="ui-transfer-list__item"
                  [class.ui-transfer-list__item--selected]="isTargetItemSelected(item.id)"
                  [class.ui-transfer-list__item--disabled]="disabled || item.disabled"
                  role="option"
                  [attr.aria-selected]="isTargetItemSelected(item.id)"
                  [attr.aria-disabled]="disabled || item.disabled"
                  [tabindex]="disabled || item.disabled ? -1 : 0"
                  (click)="toggleTargetItem(item)"
                  (keydown)="handleItemKeydown($event, item, 'target')"
                >
                  @if (showCheckboxes) {
                    <input
                      type="checkbox"
                      class="ui-transfer-list__checkbox"
                      [checked]="isTargetItemSelected(item.id)"
                      [disabled]="disabled || item.disabled"
                      (change)="toggleTargetItem(item)"
                      tabindex="-1"
                    />
                  }
                  <span class="ui-transfer-list__item-label">{{ item.label }}</span>
                </div>
              }
            }
          </div>
        </div>
        
        <div class="ui-transfer-list__footer">
          {{ getTargetSelectedCount() }} of {{ filteredTargetItems().length }} selected
        </div>
      </div>
    </div>
  `,
  styleUrl: './transfer-list.component.scss'
})
export class TransferListComponent {
  // FontAwesome icons
  faChevronRight = faChevronRight;
  faChevronLeft = faChevronLeft;
  faAnglesRight = faAnglesRight;
  faAnglesLeft = faAnglesLeft;
  faSearch = faSearch;
  faTimes = faTimes;

  // Component inputs
  @Input() sourceItems: TransferListItem[] = [];
  @Input() targetItems: TransferListItem[] = [];
  @Input() sourceTitle = 'Available';
  @Input() targetTitle = 'Selected';
  @Input() size: TransferListSize = 'md';
  @Input() disabled = false;
  @Input() showSearch = true;
  @Input() showSelectAll = true;
  @Input() showCheckboxes = true;
  @Input() showMoveAll = true;
  @Input() searchPlaceholder = 'Search items...';
  @Input() ariaLabel?: string;

  // Component outputs
  @Output() sourceChange = new EventEmitter<TransferListItem[]>();
  @Output() targetChange = new EventEmitter<TransferListItem[]>();
  @Output() itemMove = new EventEmitter<{
    item: TransferListItem;
    from: 'source' | 'target';
    to: 'source' | 'target';
  }>();

  // Internal signals for reactive state management
  private sourceItemsSignal = signal<TransferListItem[]>([]);
  private targetItemsSignal = signal<TransferListItem[]>([]);
  private selectedSourceIds = signal<Set<string | number>>(new Set());
  private selectedTargetIds = signal<Set<string | number>>(new Set());
  
  // Search terms
  sourceSearchTerm = signal<string>('');
  targetSearchTerm = signal<string>('');

  // Computed filtered items
  filteredSourceItems = computed(() => {
    const items = this.sourceItemsSignal();
    const searchTerm = this.sourceSearchTerm().toLowerCase().trim();
    
    if (!searchTerm) return items;
    
    return items.filter(item => 
      item.label.toLowerCase().includes(searchTerm)
    );
  });

  filteredTargetItems = computed(() => {
    const items = this.targetItemsSignal();
    const searchTerm = this.targetSearchTerm().toLowerCase().trim();
    
    if (!searchTerm) return items;
    
    return items.filter(item => 
      item.label.toLowerCase().includes(searchTerm)
    );
  });

  // Computed selected items
  selectedSourceItems = computed(() => {
    const selectedIds = this.selectedSourceIds();
    return this.sourceItemsSignal().filter(item => selectedIds.has(item.id));
  });

  selectedTargetItems = computed(() => {
    const selectedIds = this.selectedTargetIds();
    return this.targetItemsSignal().filter(item => selectedIds.has(item.id));
  });

  ngOnInit() {
    this.sourceItemsSignal.set([...this.sourceItems]);
    this.targetItemsSignal.set([...this.targetItems]);
  }

  ngOnChanges() {
    this.sourceItemsSignal.set([...this.sourceItems]);
    this.targetItemsSignal.set([...this.targetItems]);
  }

  // Search methods
  updateSourceSearch() {
    // Clear selection when searching to avoid confusion
    this.selectedSourceIds.set(new Set());
  }

  updateTargetSearch() {
    // Clear selection when searching to avoid confusion
    this.selectedTargetIds.set(new Set());
  }

  clearSourceSearch() {
    this.sourceSearchTerm.set('');
    this.selectedSourceIds.set(new Set());
  }

  clearTargetSearch() {
    this.targetSearchTerm.set('');
    this.selectedTargetIds.set(new Set());
  }

  // Selection methods
  isSourceItemSelected(id: string | number): boolean {
    return this.selectedSourceIds().has(id);
  }

  isTargetItemSelected(id: string | number): boolean {
    return this.selectedTargetIds().has(id);
  }

  toggleSourceItem(item: TransferListItem) {
    if (this.disabled || item.disabled) return;

    const currentSelected = new Set(this.selectedSourceIds());
    if (currentSelected.has(item.id)) {
      currentSelected.delete(item.id);
    } else {
      currentSelected.add(item.id);
    }
    this.selectedSourceIds.set(currentSelected);
  }

  toggleTargetItem(item: TransferListItem) {
    if (this.disabled || item.disabled) return;

    const currentSelected = new Set(this.selectedTargetIds());
    if (currentSelected.has(item.id)) {
      currentSelected.delete(item.id);
    } else {
      currentSelected.add(item.id);
    }
    this.selectedTargetIds.set(currentSelected);
  }

  // Select all methods
  getSourceSelectedCount(): number {
    return this.selectedSourceIds().size;
  }

  getTargetSelectedCount(): number {
    return this.selectedTargetIds().size;
  }

  isAllSourceSelected(): boolean {
    const availableItems = this.filteredSourceItems().filter(item => !item.disabled);
    return availableItems.length > 0 && 
           availableItems.every(item => this.selectedSourceIds().has(item.id));
  }

  isAllTargetSelected(): boolean {
    const availableItems = this.filteredTargetItems().filter(item => !item.disabled);
    return availableItems.length > 0 && 
           availableItems.every(item => this.selectedTargetIds().has(item.id));
  }

  isSourceIndeterminate(): boolean {
    const availableItems = this.filteredSourceItems().filter(item => !item.disabled);
    const selectedCount = availableItems.filter(item => this.selectedSourceIds().has(item.id)).length;
    return selectedCount > 0 && selectedCount < availableItems.length;
  }

  isTargetIndeterminate(): boolean {
    const availableItems = this.filteredTargetItems().filter(item => !item.disabled);
    const selectedCount = availableItems.filter(item => this.selectedTargetIds().has(item.id)).length;
    return selectedCount > 0 && selectedCount < availableItems.length;
  }

  toggleAllSource(event: Event) {
    if (this.disabled) return;

    const target = event.target as HTMLInputElement;
    const availableItems = this.filteredSourceItems().filter(item => !item.disabled);
    
    if (target.checked) {
      const newSelected = new Set(this.selectedSourceIds());
      availableItems.forEach(item => newSelected.add(item.id));
      this.selectedSourceIds.set(newSelected);
    } else {
      const newSelected = new Set(this.selectedSourceIds());
      availableItems.forEach(item => newSelected.delete(item.id));
      this.selectedSourceIds.set(newSelected);
    }
  }

  toggleAllTarget(event: Event) {
    if (this.disabled) return;

    const target = event.target as HTMLInputElement;
    const availableItems = this.filteredTargetItems().filter(item => !item.disabled);
    
    if (target.checked) {
      const newSelected = new Set(this.selectedTargetIds());
      availableItems.forEach(item => newSelected.add(item.id));
      this.selectedTargetIds.set(newSelected);
    } else {
      const newSelected = new Set(this.selectedTargetIds());
      availableItems.forEach(item => newSelected.delete(item.id));
      this.selectedTargetIds.set(newSelected);
    }
  }

  // Transfer methods
  moveSelectedToTarget() {
    if (this.disabled) return;

    const itemsToMove = this.selectedSourceItems();
    if (itemsToMove.length === 0) return;

    const newSourceItems = this.sourceItemsSignal().filter(
      item => !this.selectedSourceIds().has(item.id)
    );
    const newTargetItems = [...this.targetItemsSignal(), ...itemsToMove];

    this.sourceItemsSignal.set(newSourceItems);
    this.targetItemsSignal.set(newTargetItems);
    this.selectedSourceIds.set(new Set());

    // Emit events
    this.sourceChange.emit(newSourceItems);
    this.targetChange.emit(newTargetItems);
    
    itemsToMove.forEach(item => {
      this.itemMove.emit({ item, from: 'source', to: 'target' });
    });
  }

  moveSelectedToSource() {
    if (this.disabled) return;

    const itemsToMove = this.selectedTargetItems();
    if (itemsToMove.length === 0) return;

    const newTargetItems = this.targetItemsSignal().filter(
      item => !this.selectedTargetIds().has(item.id)
    );
    const newSourceItems = [...this.sourceItemsSignal(), ...itemsToMove];

    this.sourceItemsSignal.set(newSourceItems);
    this.targetItemsSignal.set(newTargetItems);
    this.selectedTargetIds.set(new Set());

    // Emit events
    this.sourceChange.emit(newSourceItems);
    this.targetChange.emit(newTargetItems);
    
    itemsToMove.forEach(item => {
      this.itemMove.emit({ item, from: 'target', to: 'source' });
    });
  }

  moveAllToTarget() {
    if (this.disabled) return;

    const itemsToMove = this.filteredSourceItems().filter(item => !item.disabled);
    if (itemsToMove.length === 0) return;

    const newSourceItems = this.sourceItemsSignal().filter(item => item.disabled);
    const newTargetItems = [...this.targetItemsSignal(), ...itemsToMove];

    this.sourceItemsSignal.set(newSourceItems);
    this.targetItemsSignal.set(newTargetItems);
    this.selectedSourceIds.set(new Set());

    // Emit events
    this.sourceChange.emit(newSourceItems);
    this.targetChange.emit(newTargetItems);
    
    itemsToMove.forEach(item => {
      this.itemMove.emit({ item, from: 'source', to: 'target' });
    });
  }

  moveAllToSource() {
    if (this.disabled) return;

    const itemsToMove = this.filteredTargetItems().filter(item => !item.disabled);
    if (itemsToMove.length === 0) return;

    const newTargetItems = this.targetItemsSignal().filter(item => item.disabled);
    const newSourceItems = [...this.sourceItemsSignal(), ...itemsToMove];

    this.sourceItemsSignal.set(newSourceItems);
    this.targetItemsSignal.set(newTargetItems);
    this.selectedTargetIds.set(new Set());

    // Emit events
    this.sourceChange.emit(newSourceItems);
    this.targetChange.emit(newTargetItems);
    
    itemsToMove.forEach(item => {
      this.itemMove.emit({ item, from: 'target', to: 'source' });
    });
  }

  // Keyboard navigation
  handleSourceKeydown(event: KeyboardEvent) {
    this.handleListKeydown(event, this.filteredSourceItems(), 'source');
  }

  handleTargetKeydown(event: KeyboardEvent) {
    this.handleListKeydown(event, this.filteredTargetItems(), 'target');
  }

  handleItemKeydown(event: KeyboardEvent, item: TransferListItem, list: 'source' | 'target') {
    if (event.key === ' ' || event.key === 'Enter') {
      event.preventDefault();
      if (list === 'source') {
        this.toggleSourceItem(item);
      } else {
        this.toggleTargetItem(item);
      }
    }
  }

  private handleListKeydown(event: KeyboardEvent, items: TransferListItem[], list: 'source' | 'target') {
    const currentFocus = document.activeElement as HTMLElement;
    const listItems = Array.from(currentFocus.parentElement?.querySelectorAll('.ui-transfer-list__item[tabindex="0"]') || []) as HTMLElement[];
    
    if (listItems.length === 0) return;

    const currentIndex = listItems.indexOf(currentFocus);
    let nextIndex = currentIndex;

    switch (event.key) {
      case 'ArrowDown':
        event.preventDefault();
        nextIndex = Math.min(currentIndex + 1, listItems.length - 1);
        break;
      case 'ArrowUp':
        event.preventDefault();
        nextIndex = Math.max(currentIndex - 1, 0);
        break;
      case 'Home':
        event.preventDefault();
        nextIndex = 0;
        break;
      case 'End':
        event.preventDefault();
        nextIndex = listItems.length - 1;
        break;
    }

    if (nextIndex !== currentIndex) {
      listItems[nextIndex]?.focus();
    }
  }
}