import { Component, EventEmitter, Input, OnChanges, Output, SimpleChanges } from '@angular/core';
import { ChessPieceComponent } from '../chess-piece/chess-piece.component';

interface BoardSquare {
  coordinate: string;
  isLight: boolean;
  pieceCode: string | null;
}

type BoardTheme = 'arabian' | 'classic';

@Component({
  selector: 'app-chess-board',
  standalone: true,
  imports: [ChessPieceComponent],
  templateUrl: './chess-board.component.html',
  styleUrl: './chess-board.component.css'
})
export class ChessBoardComponent implements OnChanges {
  @Input({ required: true }) fen = '';
  @Input() selectedSquare: string | null = null;
  @Input() highlightedSquares: string[] = [];
  @Input() boardTheme: BoardTheme = 'arabian';
  @Output() squareSelected = new EventEmitter<string>();

  squares: BoardSquare[] = [];
  private highlightedSquareSet = new Set<string>();
  private draggingFromSquare: string | null = null;
  private dragOverSquare: string | null = null;
  private suppressNextClick = false;

  ngOnChanges(changes: SimpleChanges): void {
    if (changes['fen']) {
      this.squares = this.buildSquares(this.fen);
    }

    if (changes['highlightedSquares']) {
      this.highlightedSquareSet = new Set(this.highlightedSquares);
    }
  }

  trackByCoordinate(_index: number, square: BoardSquare): string {
    return square.coordinate;
  }

  onSquareClick(square: BoardSquare): void {
    if (this.suppressNextClick) {
      this.suppressNextClick = false;
      return;
    }

    this.squareSelected.emit(square.coordinate);
  }

  onPieceDragStart(event: DragEvent, square: BoardSquare): void {
    if (!square.pieceCode) {
      event.preventDefault();
      return;
    }

    this.draggingFromSquare = square.coordinate;
    if (event.dataTransfer) {
      event.dataTransfer.setData('text/plain', square.coordinate);
      event.dataTransfer.effectAllowed = 'move';
    }
    this.squareSelected.emit(square.coordinate);
  }

  onSquareDragOver(event: DragEvent, square: BoardSquare): void {
    if (!this.draggingFromSquare) {
      return;
    }

    event.preventDefault();
    if (event.dataTransfer) {
      event.dataTransfer.dropEffect = 'move';
    }
    this.dragOverSquare = square.coordinate === this.draggingFromSquare ? null : square.coordinate;
  }

  onSquareDrop(event: DragEvent, square: BoardSquare): void {
    event.preventDefault();
    if (!this.draggingFromSquare) {
      return;
    }

    const fromSquare = this.draggingFromSquare;
    this.clearDragState();

    if (fromSquare === square.coordinate) {
      return;
    }

    this.suppressNextClick = true;
    this.squareSelected.emit(square.coordinate);
  }

  onSquareDragEnd(): void {
    this.clearDragState();
  }

  isSelected(square: BoardSquare): boolean {
    return this.selectedSquare === square.coordinate;
  }

  isHighlighted(square: BoardSquare): boolean {
    return this.highlightedSquareSet.has(square.coordinate);
  }

  isDraggingSource(square: BoardSquare): boolean {
    return this.draggingFromSquare === square.coordinate;
  }

  isDragOver(square: BoardSquare): boolean {
    return this.dragOverSquare === square.coordinate;
  }

  private buildSquares(fen: string): BoardSquare[] {
    const placement = fen.split(' ')[0] ?? '';
    const rows = placement.split('/');
    if (rows.length !== 8) {
      return [];
    }

    const squares: BoardSquare[] = [];

    rows.forEach((row, rowIndex) => {
      let column = 0;

      for (const char of row) {
        if (char >= '1' && char <= '8') {
          const emptyCount = Number(char);
          for (let step = 0; step < emptyCount; step += 1) {
            squares.push(this.createSquare(rowIndex, column, null));
            column += 1;
          }
        } else {
          squares.push(this.createSquare(rowIndex, column, char));
          column += 1;
        }
      }
    });

    return squares;
  }

  private createSquare(rowIndex: number, column: number, pieceCode: string | null): BoardSquare {
    const file = String.fromCharCode(97 + column);
    const rank = String(8 - rowIndex);
    return {
      coordinate: `${file}${rank}`,
      isLight: (rowIndex + column) % 2 === 0,
      pieceCode
    };
  }

  private clearDragState(): void {
    this.draggingFromSquare = null;
    this.dragOverSquare = null;
  }
}
