import { Component, Input, Output, EventEmitter, ChangeDetectionStrategy, ViewEncapsulation, ElementRef, OnDestroy, AfterViewInit, ViewChild } from '@angular/core';
import { CommonModule } from '@angular/common';

export type SplitDirection = 'horizontal' | 'vertical';
export type SplitSize = 'sm' | 'md' | 'lg';
export type PanelVariant = 'primary' | 'secondary' | 'elevated';

export interface PanelConfig {
  id: string;
  size?: number | string;
  minSize?: number;
  maxSize?: number;
  resizable?: boolean;
  variant?: PanelVariant;
  collapsed?: boolean;
}

export interface ResizeEvent {
  panelId: string;
  newSize: number;
  direction: SplitDirection;
}

@Component({
  selector: 'ui-split-view',
  standalone: true,
  imports: [CommonModule],
  changeDetection: ChangeDetectionStrategy.OnPush,
  encapsulation: ViewEncapsulation.None,
  template: `
    <div 
      #splitContainer
      class="ui-split-view"
      [class]="'ui-split-view ui-split-view--' + direction + ' ui-split-view--' + size"
      [class.ui-split-view--disabled]="disabled"
      [class.ui-split-view--resizing]="isResizing"
      [attr.aria-orientation]="direction"
      role="separator">
      
      @for (panel of panels; track panel.id; let i = $index) {
        <div 
          class="ui-split-view__panel"
          [class]="'ui-split-view__panel ui-split-view__panel--' + (panel.variant || 'primary')"
          [class.ui-split-view__panel--collapsed]="panel.collapsed"
          [style.flex-basis]="getPanelSize(panel, i)"
          [style.min-width]="direction === 'horizontal' ? (panel.minSize ? panel.minSize + 'px' : '100px') : 'auto'"
          [style.min-height]="direction === 'vertical' ? (panel.minSize ? panel.minSize + 'px' : '50px') : 'auto'"
          [style.max-width]="direction === 'horizontal' && panel.maxSize ? panel.maxSize + 'px' : 'none'"
          [style.max-height]="direction === 'vertical' && panel.maxSize ? panel.maxSize + 'px' : 'none'"
          [attr.data-panel-id]="panel.id"
          role="region"
          [attr.aria-label]="'Panel ' + (i + 1)">
          
          <div class="ui-split-view__panel-content">
            <ng-content [select]="'[slot=' + panel.id + ']'"></ng-content>
          </div>
        </div>
        
        @if (i < panels.length - 1 && (panel.resizable !== false) && !disabled) {
          <div 
            class="ui-split-view__resizer"
            [class]="'ui-split-view__resizer ui-split-view__resizer--' + (direction === 'horizontal' ? 'vertical' : 'horizontal')"
            [class.ui-split-view__resizer--disabled]="disabled"
            [attr.data-resizer-index]="i"
            [tabindex]="disabled ? -1 : 0"
            [attr.aria-label]="'Resize panels'"
            role="separator"
            [attr.aria-orientation]="direction"
            (mousedown)="startResize($event, i)"
            (touchstart)="startResize($event, i)"
            (keydown)="handleResizerKeydown($event, i)">
            
            <div class="ui-split-view__resizer-handle"></div>
          </div>
        }
      }
    </div>
  `,
  styleUrl: './split-view.component.scss'
})
export class SplitViewComponent implements AfterViewInit, OnDestroy {
  @Input() direction: SplitDirection = 'horizontal';
  @Input() size: SplitSize = 'md';
  @Input() disabled = false;
  @Input() panels: PanelConfig[] = [
    { id: 'panel-1', size: '50%' },
    { id: 'panel-2', size: '50%' }
  ];
  @Input() minPanelSize = 100;
  @Input() resizerSize = 4;
  
  @Output() panelResized = new EventEmitter<ResizeEvent>();
  @Output() resizeStart = new EventEmitter<{ panelId: string, direction: SplitDirection }>();
  @Output() resizeEnd = new EventEmitter<{ panelId: string, direction: SplitDirection }>();
  
  @ViewChild('splitContainer', { static: true }) splitContainer!: ElementRef<HTMLDivElement>;
  
  isResizing = false;
  private currentResizerIndex = -1;
  private startPosition = 0;
  private startSizes: number[] = [];
  private boundMouseMove = this.handleMouseMove.bind(this);
  private boundMouseUp = this.handleMouseUp.bind(this);
  private boundTouchMove = this.handleTouchMove.bind(this);
  private boundTouchEnd = this.handleTouchEnd.bind(this);
  
  ngAfterViewInit(): void {
    // Initialize panel sizes if not set
    this.initializePanelSizes();
  }
  
  ngOnDestroy(): void {
    this.removeGlobalListeners();
  }
  
  private initializePanelSizes(): void {
    // Ensure panels have proper sizes
    const totalPanels = this.panels.length;
    const defaultSize = `${100 / totalPanels}%`;
    
    this.panels.forEach((panel, index) => {
      if (!panel.size) {
        panel.size = defaultSize;
      }
    });
  }
  
  getPanelSize(panel: PanelConfig, index: number): string {
    if (panel.collapsed) return '0';
    return typeof panel.size === 'number' ? `${panel.size}px` : panel.size || '1fr';
  }
  
  startResize(event: MouseEvent | TouchEvent, resizerIndex: number): void {
    if (this.disabled) return;
    
    event.preventDefault();
    event.stopPropagation();
    
    this.isResizing = true;
    this.currentResizerIndex = resizerIndex;
    
    const clientPos = this.getClientPosition(event);
    this.startPosition = this.direction === 'horizontal' ? clientPos.x : clientPos.y;
    
    // Store current panel sizes
    this.startSizes = this.getCurrentPanelSizes();
    
    // Add global listeners
    this.addGlobalListeners();
    
    // Emit resize start event
    const panelId = this.panels[resizerIndex].id;
    this.resizeStart.emit({ panelId, direction: this.direction });
  }
  
  private handleMouseMove(event: MouseEvent): void {
    this.handleMove(this.getClientPosition(event));
  }
  
  private handleTouchMove(event: TouchEvent): void {
    this.handleMove(this.getClientPosition(event));
  }
  
  private handleMove(clientPos: { x: number, y: number }): void {
    if (!this.isResizing || this.currentResizerIndex === -1) return;
    
    const currentPosition = this.direction === 'horizontal' ? clientPos.x : clientPos.y;
    const delta = currentPosition - this.startPosition;
    
    const containerRect = this.splitContainer.nativeElement.getBoundingClientRect();
    const containerSize = this.direction === 'horizontal' ? containerRect.width : containerRect.height;
    
    const leftPanelIndex = this.currentResizerIndex;
    const rightPanelIndex = this.currentResizerIndex + 1;
    
    if (leftPanelIndex >= 0 && rightPanelIndex < this.panels.length) {
      const leftPanel = this.panels[leftPanelIndex];
      const rightPanel = this.panels[rightPanelIndex];
      
      // Calculate new sizes
      const leftStartSize = this.startSizes[leftPanelIndex];
      const rightStartSize = this.startSizes[rightPanelIndex];
      
      let newLeftSize = leftStartSize + delta;
      let newRightSize = rightStartSize - delta;
      
      // Apply minimum size constraints
      const minSize = leftPanel.minSize || this.minPanelSize;
      const rightMinSize = rightPanel.minSize || this.minPanelSize;
      
      if (newLeftSize < minSize) {
        newLeftSize = minSize;
        newRightSize = leftStartSize + rightStartSize - newLeftSize;
      }
      
      if (newRightSize < rightMinSize) {
        newRightSize = rightMinSize;
        newLeftSize = leftStartSize + rightStartSize - newRightSize;
      }
      
      // Apply maximum size constraints
      if (leftPanel.maxSize && newLeftSize > leftPanel.maxSize) {
        newLeftSize = leftPanel.maxSize;
        newRightSize = leftStartSize + rightStartSize - newLeftSize;
      }
      
      if (rightPanel.maxSize && newRightSize > rightPanel.maxSize) {
        newRightSize = rightPanel.maxSize;
        newLeftSize = leftStartSize + rightStartSize - newRightSize;
      }
      
      // Convert to percentages
      const leftPercentage = (newLeftSize / containerSize) * 100;
      const rightPercentage = (newRightSize / containerSize) * 100;
      
      // Update panel sizes
      leftPanel.size = `${leftPercentage}%`;
      rightPanel.size = `${rightPercentage}%`;
      
      // Emit resize event
      this.panelResized.emit({
        panelId: leftPanel.id,
        newSize: newLeftSize,
        direction: this.direction
      });
    }
  }
  
  private handleMouseUp(): void {
    this.endResize();
  }
  
  private handleTouchEnd(): void {
    this.endResize();
  }
  
  private endResize(): void {
    if (!this.isResizing) return;
    
    this.isResizing = false;
    const panelId = this.panels[this.currentResizerIndex]?.id;
    this.currentResizerIndex = -1;
    
    this.removeGlobalListeners();
    
    // Emit resize end event
    if (panelId) {
      this.resizeEnd.emit({ panelId, direction: this.direction });
    }
  }
  
  private getCurrentPanelSizes(): number[] {
    const containerRect = this.splitContainer.nativeElement.getBoundingClientRect();
    const containerSize = this.direction === 'horizontal' ? containerRect.width : containerRect.height;
    
    return this.panels.map((panel) => {
      if (typeof panel.size === 'string' && panel.size.endsWith('%')) {
        const percentage = parseFloat(panel.size.replace('%', ''));
        return (percentage / 100) * containerSize;
      } else if (typeof panel.size === 'number') {
        return panel.size;
      }
      return containerSize / this.panels.length; // Default equal distribution
    });
  }
  
  private getClientPosition(event: MouseEvent | TouchEvent): { x: number, y: number } {
    if (event instanceof MouseEvent) {
      return { x: event.clientX, y: event.clientY };
    } else {
      const touch = event.touches[0] || event.changedTouches[0];
      return { x: touch.clientX, y: touch.clientY };
    }
  }
  
  private addGlobalListeners(): void {
    document.addEventListener('mousemove', this.boundMouseMove);
    document.addEventListener('mouseup', this.boundMouseUp);
    document.addEventListener('touchmove', this.boundTouchMove, { passive: false });
    document.addEventListener('touchend', this.boundTouchEnd);
    document.addEventListener('selectstart', this.preventSelection);
  }
  
  private removeGlobalListeners(): void {
    document.removeEventListener('mousemove', this.boundMouseMove);
    document.removeEventListener('mouseup', this.boundMouseUp);
    document.removeEventListener('touchmove', this.boundTouchMove);
    document.removeEventListener('touchend', this.boundTouchEnd);
    document.removeEventListener('selectstart', this.preventSelection);
  }
  
  private preventSelection(event: Event): void {
    event.preventDefault();
  }
  
  handleResizerKeydown(event: KeyboardEvent, resizerIndex: number): void {
    const step = 10; // pixels
    let delta = 0;
    
    switch (event.key) {
      case 'ArrowLeft':
        if (this.direction === 'horizontal') delta = -step;
        break;
      case 'ArrowRight':
        if (this.direction === 'horizontal') delta = step;
        break;
      case 'ArrowUp':
        if (this.direction === 'vertical') delta = -step;
        break;
      case 'ArrowDown':
        if (this.direction === 'vertical') delta = step;
        break;
      case 'Home':
        delta = -1000; // Move to minimum
        break;
      case 'End':
        delta = 1000; // Move to maximum
        break;
      default:
        return;
    }
    
    event.preventDefault();
    
    // Simulate resize with keyboard
    this.currentResizerIndex = resizerIndex;
    this.startSizes = this.getCurrentPanelSizes();
    this.handleMove({ x: this.startPosition + delta, y: this.startPosition + delta });
    this.currentResizerIndex = -1;
  }
  
  // Public methods for programmatic control
  collapsePanel(panelId: string): void {
    const panel = this.panels.find(p => p.id === panelId);
    if (panel) {
      panel.collapsed = true;
    }
  }
  
  expandPanel(panelId: string): void {
    const panel = this.panels.find(p => p.id === panelId);
    if (panel) {
      panel.collapsed = false;
    }
  }
  
  setPanelSize(panelId: string, size: number | string): void {
    const panel = this.panels.find(p => p.id === panelId);
    if (panel) {
      panel.size = size;
    }
  }
  
  resetPanelSizes(): void {
    const equalSize = `${100 / this.panels.length}%`;
    this.panels.forEach(panel => {
      panel.size = equalSize;
      panel.collapsed = false;
    });
  }
}