import {
  customElement,
  html,
  css,
  cssManager,
  property,
  state,
  type TemplateResult,
} from '@design.estate/dees-element';
import { DeesInputBase } from '../dees-input-base/dees-input-base.js';
import '../../dees-icon/dees-icon.js';
import '../../00group-button/dees-button/dees-button.js';
import { demoFunc } from './dees-input-list.demo.js';
import { themeDefaultStyles } from '../../00theme.js';

declare global {
  interface HTMLElementTagNameMap {
    'dees-input-list': DeesInputList;
  }
}

@customElement('dees-input-list')
export class DeesInputList extends DeesInputBase<DeesInputList> {
  // STATIC
  public static demo = demoFunc;
  public static demoGroup = 'Input';

  // INSTANCE
  @property({ type: Array })
  accessor value: string[] = [];

  @property({ type: String })
  accessor placeholder: string = 'Add new item...';

  @property({ type: Number })
  accessor maxItems: number = 0; // 0 means unlimited

  @property({ type: Number })
  accessor minItems: number = 0;

  @property({ type: Boolean })
  accessor allowDuplicates: boolean = false;

  @property({ type: Boolean })
  accessor sortable: boolean = false;

  @property({ type: Boolean })
  accessor confirmDelete: boolean = false;

  @property({ type: String })
  accessor validationText: string = '';

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

  @state()
  accessor editingIndex: number = -1;

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

  @state()
  accessor draggedIndex: number = -1;

  @state()
  accessor dragOverIndex: number = -1;

  // Enhanced drag state for interactive reordering
  @state()
  accessor dragStartY: number = 0;

  @state()
  accessor dragCurrentY: number = 0;

  @state()
  accessor targetIndex: number = -1;

  @state()
  accessor itemHeight: number = 0;

  // Bound event handlers for cleanup
  private boundHandleGlobalDragOver: ((e: DragEvent) => void) | null = null;
  private boundHandleGlobalDragEnd: (() => void) | null = null;

  // Store original item positions for accurate hit detection (before transforms)
  private originalItemRects: DOMRect[] = [];

  public static styles = [
    themeDefaultStyles,
    ...DeesInputBase.baseStyles,
    cssManager.defaultStyles,
    css`
      /* TODO: Migrate hardcoded values to --dees-* CSS variables */
      :host {
        display: block;
        font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif;
      }

      .input-wrapper {
        width: 100%;
      }

      .list-container {
        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%)')};
        border-radius: 6px;
        overflow: hidden;
        transition: all 0.15s ease;
      }

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

      .list-container:focus-within {
        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)')};
      }

      .list-container.disabled {
        opacity: 0.6;
        cursor: not-allowed;
      }

      .list-items {
        max-height: 400px;
        overflow-y: auto;
      }

      .list-item {
        display: flex;
        align-items: center;
        gap: 8px;
        padding: 12px 16px;
        border-bottom: 1px solid ${cssManager.bdTheme('hsl(0 0% 89.8%)', 'hsl(0 0% 14.9%)')};
        background: ${cssManager.bdTheme('hsl(0 0% 100%)', 'hsl(0 0% 3.9%)')};
        transition: transform 0.2s ease, background 0.15s ease, box-shadow 0.15s ease;
        position: relative;
        overflow: hidden; /* Prevent animation from affecting scroll bounds */
      }

      .list-item:last-of-type {
        border-bottom: none;
      }

      .list-items:not(.is-dragging) .list-item:hover:not(.disabled) {
        background: ${cssManager.bdTheme('hsl(0 0% 97.5%)', 'hsl(0 0% 6.9%)')};
      }

      /* Dragging item - follows cursor */
      .list-item.dragging {
        position: relative;
        z-index: 100;
        background: ${cssManager.bdTheme('hsl(210 40% 98%)', 'hsl(215 20.2% 12%)')};
        box-shadow: 0 4px 12px ${cssManager.bdTheme('rgba(0, 0, 0, 0.15)', 'rgba(0, 0, 0, 0.4)')};
        border-radius: 6px;
        transition: box-shadow 0.15s ease, background 0.15s ease;
      }

      /* Items that need to move up to make space */
      .list-item.move-up {
        transform: translateY(calc(-1 * var(--item-height, 48px)));
      }

      /* Items that need to move down to make space */
      .list-item.move-down {
        transform: translateY(var(--item-height, 48px));
      }


      .drag-handle {
        display: flex;
        align-items: center;
        cursor: move;
        color: ${cssManager.bdTheme('hsl(0 0% 63.9%)', 'hsl(0 0% 45.1%)')};
        transition: color 0.15s ease;
      }

      .drag-handle:hover {
        color: ${cssManager.bdTheme('hsl(0 0% 45.1%)', 'hsl(0 0% 63.9%)')};
      }

      .drag-handle dees-icon {
        width: 16px;
        height: 16px;
      }

      .item-content {
        flex: 1;
        display: flex;
        align-items: center;
        min-width: 0;
      }

      .item-text {
        flex: 1;
        color: ${cssManager.bdTheme('hsl(0 0% 9%)', 'hsl(0 0% 95%)')};
        font-size: 14px;
        line-height: 20px;
        word-break: break-word;
      }

      .item-edit-input {
        flex: 1;
        padding: 4px 8px;
        font-size: 14px;
        font-family: inherit;
        background: ${cssManager.bdTheme('hsl(0 0% 100%)', 'hsl(0 0% 9%)')};
        border: 1px solid ${cssManager.bdTheme('hsl(222.2 47.4% 51.2%)', 'hsl(217.2 91.2% 59.8%)')};
        border-radius: 4px;
        outline: none;
        color: ${cssManager.bdTheme('hsl(0 0% 9%)', 'hsl(0 0% 95%)')};
      }

      .item-actions {
        display: flex;
        gap: 4px;
        align-items: center;
      }

      .action-button {
        display: flex;
        align-items: center;
        justify-content: center;
        width: 28px;
        height: 28px;
        border-radius: 4px;
        background: transparent;
        border: none;
        cursor: pointer;
        transition: all 0.15s ease;
        color: ${cssManager.bdTheme('hsl(0 0% 45.1%)', 'hsl(0 0% 63.9%)')};
      }

      .action-button: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%)')};
      }

      .action-button.save {
        color: ${cssManager.bdTheme('hsl(142.1 76.2% 36.3%)', 'hsl(142.1 70.6% 45.3%)')};
      }

      .action-button.save:hover {
        background: ${cssManager.bdTheme('hsl(142.1 76.2% 36.3% / 0.1)', 'hsl(142.1 70.6% 45.3% / 0.1)')};
      }

      .action-button.cancel {
        color: ${cssManager.bdTheme('hsl(0 72.2% 50.6%)', 'hsl(0 62.8% 50.6%)')};
      }

      .action-button.cancel:hover {
        background: ${cssManager.bdTheme('hsl(0 72.2% 50.6% / 0.1)', 'hsl(0 62.8% 50.6% / 0.1)')};
      }

      .action-button.delete {
        color: ${cssManager.bdTheme('hsl(0 72.2% 50.6%)', 'hsl(0 62.8% 50.6%)')};
      }

      .action-button.delete:hover {
        background: ${cssManager.bdTheme('hsl(0 72.2% 50.6% / 0.1)', 'hsl(0 62.8% 50.6% / 0.1)')};
      }

      .action-button dees-icon {
        width: 14px;
        height: 14px;
      }

      .add-item-container {
        display: flex;
        gap: 8px;
        padding: 12px 16px;
        background: ${cssManager.bdTheme('hsl(0 0% 97.5%)', 'hsl(0 0% 6.9%)')};
        border-top: 1px solid ${cssManager.bdTheme('hsl(0 0% 89.8%)', 'hsl(0 0% 14.9%)')};
      }

      .add-input {
        flex: 1;
        padding: 8px 12px;
        font-size: 14px;
        font-family: inherit;
        background: ${cssManager.bdTheme('hsl(0 0% 100%)', 'hsl(0 0% 9%)')};
        border: 1px solid ${cssManager.bdTheme('hsl(0 0% 89.8%)', 'hsl(0 0% 14.9%)')};
        border-radius: 4px;
        outline: none;
        color: ${cssManager.bdTheme('hsl(0 0% 9%)', 'hsl(0 0% 95%)')};
        transition: all 0.15s ease;
      }

      .add-input:focus {
        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)')};
      }

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

      .add-input:disabled {
        cursor: not-allowed;
        opacity: 0.5;
      }

      .add-button {
        padding: 8px 16px;
      }

      .empty-state {
        padding: 32px 16px;
        text-align: center;
        color: ${cssManager.bdTheme('hsl(0 0% 63.9%)', 'hsl(0 0% 45.1%)')};
        font-size: 14px;
        font-style: italic;
      }

      .validation-message {
        color: ${cssManager.bdTheme('hsl(0 72.2% 50.6%)', 'hsl(0 62.8% 30.6%)')};
        font-size: 13px;
        margin-top: 6px;
        line-height: 1.5;
      }

      .description {
        color: ${cssManager.bdTheme('hsl(215.4 16.3% 56.9%)', 'hsl(215 20.2% 55.1%)')};
        font-size: 13px;
        margin-top: 6px;
        line-height: 1.5;
      }

      /* Scrollbar styling */
      .list-items::-webkit-scrollbar {
        width: 8px;
      }

      .list-items::-webkit-scrollbar-track {
        background: transparent;
      }

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

      .list-items::-webkit-scrollbar-thumb:hover {
        background: ${cssManager.bdTheme('hsl(0 0% 79.8%)', 'hsl(0 0% 34.9%)')};
      }

      /* Disable transitions during drop to prevent flash */
      .list-items.dropping .list-item {
        transition: none !important;
      }
    `,
  ];

  public render(): TemplateResult {
    return html`
      <div class="input-wrapper">
        ${this.label ? html`<dees-label .label=${this.label} .required=${this.required}></dees-label>` : ''}
        
        <div class="list-container ${this.disabled ? 'disabled' : ''}">
          <div class="list-items">
            ${this.value.length > 0 ? this.value.map((item, index) => html`
              <div
                class="list-item ${this.draggedIndex === index ? 'dragging' : ''}"
                draggable="${this.sortable && !this.disabled}"
                @dragstart=${(e: DragEvent) => this.handleDragStart(e, index)}
                @dragend=${this.handleDragEnd}
                @dragover=${(e: DragEvent) => this.handleDragOver(e, index)}
                @drop=${(e: DragEvent) => this.handleDrop(e, index)}
              >
                ${this.sortable && !this.disabled ? html`
                  <div class="drag-handle">
                    <dees-icon .icon=${'lucide:gripVertical'}></dees-icon>
                  </div>
                ` : ''}
                
                <div class="item-content">
                  ${this.editingIndex === index ? html`
                    <input
                      type="text"
                      class="item-edit-input"
                      .value=${this.editingValue}
                      @input=${(e: InputEvent) => this.editingValue = (e.target as HTMLInputElement).value}
                      @keydown=${(e: KeyboardEvent) => this.handleEditKeyDown(e, index)}
                      @blur=${() => this.saveEdit(index)}
                    />
                  ` : html`
                    <div class="item-text" @dblclick=${() => !this.disabled && this.startEdit(index)}>
                      ${item}
                    </div>
                  `}
                </div>
                
                <div class="item-actions">
                  ${this.editingIndex === index ? html`
                    <button class="action-button save" @click=${() => this.saveEdit(index)}>
                      <dees-icon .icon=${'lucide:check'}></dees-icon>
                    </button>
                    <button class="action-button cancel" @click=${() => this.cancelEdit()}>
                      <dees-icon .icon=${'lucide:x'}></dees-icon>
                    </button>
                  ` : html`
                    ${!this.disabled ? html`
                      <button class="action-button" @click=${() => this.startEdit(index)}>
                        <dees-icon .icon=${'lucide:pencil'}></dees-icon>
                      </button>
                      <button class="action-button delete" @click=${() => this.removeItem(index)}>
                        <dees-icon .icon=${'lucide:trash2'}></dees-icon>
                      </button>
                    ` : ''}
                  `}
                </div>
              </div>
            `) : html`
              <div class="empty-state">
                No items added yet
              </div>
            `}
          </div>
          
          ${!this.disabled && (!this.maxItems || this.value.length < this.maxItems) ? html`
            <div class="add-item-container">
              <input
                type="text"
                class="add-input"
                .placeholder=${this.placeholder}
                .value=${this.inputValue}
                @input=${this.handleInput}
                @keydown=${this.handleAddKeyDown}
                ?disabled=${this.disabled}
              />
              <dees-button
                class="add-button"
                @click=${this.addItem}
                ?disabled=${!this.inputValue.trim()}
              >
                <dees-icon .icon=${'lucide:plus'}></dees-icon> Add
              </dees-button>
            </div>
          ` : ''}
        </div>

        ${this.validationText ? html`
          <div class="validation-message">${this.validationText}</div>
        ` : ''}
        
        ${this.description ? html`
          <div class="description">${this.description}</div>
        ` : ''}
      </div>
    `;
  }

  private handleInput(e: InputEvent) {
    this.inputValue = (e.target as HTMLInputElement).value;
  }

  private handleAddKeyDown(e: KeyboardEvent) {
    if (e.key === 'Enter' && this.inputValue.trim()) {
      e.preventDefault();
      this.addItem();
    }
  }

  private handleEditKeyDown(e: KeyboardEvent, index: number) {
    if (e.key === 'Enter') {
      e.preventDefault();
      this.saveEdit(index);
    } else if (e.key === 'Escape') {
      e.preventDefault();
      this.cancelEdit();
    }
  }

  private addItem() {
    const trimmedValue = this.inputValue.trim();
    if (!trimmedValue) return;

    if (!this.allowDuplicates && this.value.includes(trimmedValue)) {
      this.validationText = 'This item already exists in the list';
      setTimeout(() => this.validationText = '', 3000);
      return;
    }

    if (this.maxItems && this.value.length >= this.maxItems) {
      this.validationText = `Maximum ${this.maxItems} items allowed`;
      setTimeout(() => this.validationText = '', 3000);
      return;
    }

    this.value = [...this.value, trimmedValue];
    this.inputValue = '';
    this.validationText = '';
    
    // Clear the input
    const input = this.shadowRoot?.querySelector('.add-input') as HTMLInputElement;
    if (input) {
      input.value = '';
      input.focus();
    }

    this.emitChange();
  }

  private startEdit(index: number) {
    this.editingIndex = index;
    this.editingValue = this.value[index];
    
    // Focus the input after render
    this.updateComplete.then(() => {
      const input = this.shadowRoot?.querySelector('.item-edit-input') as HTMLInputElement;
      if (input) {
        input.focus();
        input.select();
      }
    });
  }

  private saveEdit(index: number) {
    const trimmedValue = this.editingValue.trim();
    
    if (!trimmedValue) {
      this.cancelEdit();
      return;
    }

    if (!this.allowDuplicates && trimmedValue !== this.value[index] && this.value.includes(trimmedValue)) {
      this.validationText = 'This item already exists in the list';
      setTimeout(() => this.validationText = '', 3000);
      return;
    }

    const newValue = [...this.value];
    newValue[index] = trimmedValue;
    this.value = newValue;
    
    this.editingIndex = -1;
    this.editingValue = '';
    this.validationText = '';
    this.emitChange();
  }

  private cancelEdit() {
    this.editingIndex = -1;
    this.editingValue = '';
  }

  private async removeItem(index: number) {
    if (this.confirmDelete) {
      const confirmed = await this.showConfirmDialog(`Delete "${this.value[index]}"?`);
      if (!confirmed) return;
    }

    this.value = this.value.filter((_, i) => i !== index);
    this.emitChange();
  }

  private async showConfirmDialog(message: string): Promise<boolean> {
    // For now, use native confirm. In production, this should use a proper modal
    return confirm(message);
  }

  // Drag and drop handlers - Interactive implementation
  private handleDragStart(e: DragEvent, index: number) {
    if (!this.sortable || this.disabled) return;

    this.draggedIndex = index;
    this.targetIndex = index;
    e.dataTransfer!.effectAllowed = 'move';
    e.dataTransfer!.setData('text/plain', index.toString());

    // Hide the default drag image
    const emptyImg = new Image();
    emptyImg.src = 'data:image/gif;base64,R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs=';
    e.dataTransfer!.setDragImage(emptyImg, 0, 0);

    // Store initial mouse position
    this.dragStartY = e.clientY;
    this.dragCurrentY = e.clientY;

    // Measure item height and store all original positions before any transforms
    const listItems = this.shadowRoot?.querySelector('.list-items');
    const allItems = Array.from(listItems?.querySelectorAll('.list-item') || []) as HTMLElement[];

    if (allItems[index]) {
      this.itemHeight = allItems[index].offsetHeight;
    }

    // Store original positions for accurate hit detection (before any transforms are applied)
    this.originalItemRects = allItems.map(item => item.getBoundingClientRect());

    // Add class to container
    listItems?.classList.add('is-dragging');

    // Set up global event listeners
    this.boundHandleGlobalDragOver = this.handleGlobalDragOver.bind(this);
    this.boundHandleGlobalDragEnd = this.handleGlobalDragEnd.bind(this);
    document.addEventListener('dragover', this.boundHandleGlobalDragOver);
    document.addEventListener('dragend', this.boundHandleGlobalDragEnd);
  }

  private handleGlobalDragOver(e: DragEvent) {
    e.preventDefault();
    if (this.draggedIndex === -1) return;

    this.dragCurrentY = e.clientY;

    // Calculate which position the item should move to
    const listItems = this.shadowRoot?.querySelector('.list-items');
    if (!listItems) return;

    const items = Array.from(listItems.querySelectorAll('.list-item')) as HTMLElement[];
    const draggedElement = items[this.draggedIndex];
    if (!draggedElement) return;

    // Apply transform to dragged item
    const deltaY = this.dragCurrentY - this.dragStartY;
    draggedElement.style.transform = `translateY(${deltaY}px)`;

    // Calculate the dragged item's current center position
    const draggedRect = this.originalItemRects[this.draggedIndex];
    if (!draggedRect) return;
    const draggedCenter = draggedRect.top + draggedRect.height / 2 + deltaY;

    // Determine target index: swap when dragged item's center crosses another item's center
    // Account for items that have already shifted (their visual position changed)
    let newTargetIndex = this.draggedIndex;

    for (let i = 0; i < items.length; i++) {
      if (i === this.draggedIndex) continue;

      const rect = this.originalItemRects[i];
      if (!rect) continue;

      // Adjust item center based on whether it has shifted
      let itemCenter = rect.top + rect.height / 2;

      // If item has moved, use its shifted position
      if (items[i].classList.contains('move-up')) {
        itemCenter -= this.itemHeight;
      } else if (items[i].classList.contains('move-down')) {
        itemCenter += this.itemHeight;
      }

      if (draggedCenter < itemCenter && i < this.draggedIndex) {
        newTargetIndex = i;
        break;
      } else if (draggedCenter > itemCenter && i > this.draggedIndex) {
        newTargetIndex = i;
      }
    }

    // Update target index and apply move classes
    if (newTargetIndex !== this.targetIndex) {
      this.targetIndex = newTargetIndex;
      this.updateItemPositions(items);
    }
  }

  private updateItemPositions(items: HTMLElement[]) {
    const draggedIdx = this.draggedIndex;
    const targetIdx = this.targetIndex;

    // Set CSS variable for item height
    const listItems = this.shadowRoot?.querySelector('.list-items') as HTMLElement;
    if (listItems) {
      listItems.style.setProperty('--item-height', `${this.itemHeight}px`);
    }

    items.forEach((item, i) => {
      if (i === draggedIdx) return; // Skip dragged item

      item.classList.remove('move-up', 'move-down');
      item.style.setProperty('--item-height', `${this.itemHeight}px`);

      if (draggedIdx < targetIdx) {
        // Dragging down: items between draggedIdx and targetIdx move up
        if (i > draggedIdx && i <= targetIdx) {
          item.classList.add('move-up');
        }
      } else if (draggedIdx > targetIdx) {
        // Dragging up: items between targetIdx and draggedIdx move down
        if (i >= targetIdx && i < draggedIdx) {
          item.classList.add('move-down');
        }
      }
    });
  }

  private handleGlobalDragEnd() {
    // Clean up event listeners
    if (this.boundHandleGlobalDragOver) {
      document.removeEventListener('dragover', this.boundHandleGlobalDragOver);
      this.boundHandleGlobalDragOver = null;
    }
    if (this.boundHandleGlobalDragEnd) {
      document.removeEventListener('dragend', this.boundHandleGlobalDragEnd);
      this.boundHandleGlobalDragEnd = null;
    }

    const listItems = this.shadowRoot?.querySelector('.list-items');
    const items = listItems?.querySelectorAll('.list-item') as NodeListOf<HTMLElement>;
    const draggedElement = items?.[this.draggedIndex];

    // If no reorder needed, animate back and clean up
    if (this.draggedIndex === -1 || this.targetIndex === -1 || this.draggedIndex === this.targetIndex) {
      // Animate dragged item back to original position
      if (draggedElement && this.draggedIndex !== -1) {
        draggedElement.style.transition = 'transform 0.15s ease';
        draggedElement.style.transform = 'translateY(0)';

        let handled = false;
        const onReturn = () => {
          if (handled) return;
          handled = true;
          draggedElement.removeEventListener('transitionend', onReturn);
          this.cleanupDragState(listItems, items);
        };

        draggedElement.addEventListener('transitionend', onReturn, { once: true });
        setTimeout(onReturn, 200);
      } else {
        this.cleanupDragState(listItems, items);
      }
      return;
    }

    // Calculate final position for dragged item
    const draggedRect = this.originalItemRects[this.draggedIndex];
    const targetRect = this.originalItemRects[this.targetIndex];

    if (!draggedRect || !targetRect || !draggedElement) {
      this.cleanupDragState(listItems, items);
      return;
    }

    // Calculate where dragged item needs to go
    let finalY: number;
    if (this.targetIndex > this.draggedIndex) {
      // Moving down: go to bottom of target
      finalY = targetRect.bottom - draggedRect.bottom;
    } else {
      // Moving up: go to top of target
      finalY = targetRect.top - draggedRect.top;
    }

    // Animate dragged item to final position
    draggedElement.style.transition = 'transform 0.15s ease';
    draggedElement.style.transform = `translateY(${finalY}px)`;

    // After animation completes, update data
    let handled = false;
    const onTransitionEnd = () => {
      if (handled) return;
      handled = true;
      draggedElement.removeEventListener('transitionend', onTransitionEnd);

      // Disable all transitions
      listItems?.classList.add('dropping');

      // Force reflow so dropping class takes effect immediately
      void (listItems as HTMLElement)?.offsetHeight;

      // Clean up all element state
      items?.forEach(item => {
        item.classList.remove('move-up', 'move-down', 'dragging');
        item.style.removeProperty('transform');
        item.style.removeProperty('transition');
      });

      // Update data
      const newValue = [...this.value];
      const [draggedItem] = newValue.splice(this.draggedIndex, 1);
      newValue.splice(this.targetIndex, 0, draggedItem);
      this.value = newValue;
      this.emitChange();

      // Reset state
      this.draggedIndex = -1;
      this.dragOverIndex = -1;
      this.targetIndex = -1;
      this.dragStartY = 0;
      this.dragCurrentY = 0;
      this.originalItemRects = [];

      // After render, ensure no animation then re-enable transitions
      this.updateComplete.then(() => {
        // Set inline transition:none on fresh elements
        const freshItems = this.shadowRoot?.querySelectorAll('.list-item') as NodeListOf<HTMLElement>;
        freshItems?.forEach(item => {
          item.style.transition = 'none';
        });

        // Force reflow
        void (this.shadowRoot?.querySelector('.list-items') as HTMLElement)?.offsetHeight;

        // Now re-enable transitions
        requestAnimationFrame(() => {
          freshItems?.forEach(item => {
            item.style.removeProperty('transition');
          });
          listItems?.classList.remove('dropping', 'is-dragging');
        });
      });
    };

    draggedElement.addEventListener('transitionend', onTransitionEnd, { once: true });

    // Fallback timeout in case transitionend doesn't fire
    setTimeout(onTransitionEnd, 200);
  }

  private cleanupDragState(listItems: Element | null | undefined, items: NodeListOf<HTMLElement> | undefined) {
    listItems?.classList.add('dropping');

    // Force reflow so dropping class takes effect immediately
    void (listItems as HTMLElement)?.offsetHeight;

    items?.forEach(item => {
      item.classList.remove('move-up', 'move-down', 'dragging');
      item.style.removeProperty('transform');
      item.style.removeProperty('transition');
    });

    this.draggedIndex = -1;
    this.dragOverIndex = -1;
    this.targetIndex = -1;
    this.dragStartY = 0;
    this.dragCurrentY = 0;
    this.originalItemRects = [];

    this.updateComplete.then(() => {
      const freshItems = this.shadowRoot?.querySelectorAll('.list-item') as NodeListOf<HTMLElement>;
      freshItems?.forEach(item => {
        item.style.transition = 'none';
      });

      void (this.shadowRoot?.querySelector('.list-items') as HTMLElement)?.offsetHeight;

      requestAnimationFrame(() => {
        freshItems?.forEach(item => {
          item.style.removeProperty('transition');
        });
        listItems?.classList.remove('dropping', 'is-dragging');
      });
    });
  }

  private handleDragEnd() {
    // This is called by the native dragend on the element
    // The actual cleanup is done in handleGlobalDragEnd
    this.handleGlobalDragEnd();
  }

  private handleDragOver(e: DragEvent, index: number) {
    if (!this.sortable || this.disabled) return;
    e.preventDefault();
    e.dataTransfer!.dropEffect = 'move';
    // We handle positioning in handleGlobalDragOver now
  }

  private handleDragLeave() {
    // No longer needed for visual feedback - handled by transform
  }

  private handleDrop(e: DragEvent, dropIndex: number) {
    if (!this.sortable || this.disabled) return;
    e.preventDefault();
    // The actual reorder happens in handleGlobalDragEnd
  }

  private emitChange() {
    this.dispatchEvent(new CustomEvent('change', {
      detail: { value: this.value },
      bubbles: true,
      composed: true
    }));
    this.changeSubject.next(this);
  }

  public getValue(): string[] {
    return this.value;
  }

  public setValue(value: string[]): void {
    this.value = value || [];
  }

  public async validate(): Promise<boolean> {
    if (this.required && (!this.value || this.value.length === 0)) {
      this.validationText = 'At least one item is required';
      return false;
    }
    
    if (this.minItems && this.value.length < this.minItems) {
      this.validationText = `At least ${this.minItems} items required`;
      return false;
    }
    
    this.validationText = '';
    return true;
  }
}