import { Component, Input, Output, EventEmitter, ChangeDetectionStrategy, computed, signal } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
import { faChevronLeft, faChevronRight, faEllipsisH } from '@fortawesome/free-solid-svg-icons';

export interface PageChangeEvent {
  page: number;
  previousPage: number;
}

type PaginationSize = 'sm' | 'md' | 'lg';
type PaginationAlignment = 'left' | 'center' | 'right';

@Component({
  selector: 'ui-pagination',
  standalone: true,
  imports: [CommonModule, FontAwesomeModule],
  changeDetection: ChangeDetectionStrategy.OnPush,
  template: `
    <nav [class]="wrapperClasses()" [attr.aria-label]="ariaLabel">
      <ul class="pagination-list" role="list">
        <!-- Previous Button -->
        <li>
          <button
            type="button"
            [class]="getItemClasses(false, false, !hasPrevious())"
            [disabled]="!hasPrevious()"
            [attr.aria-label]="previousAriaLabel"
            (click)="goToPrevious()"
          >
            <fa-icon [icon]="prevIcon" />
            @if (showLabels) {
              <span>{{ previousLabel }}</span>
            }
          </button>
        </li>

        <!-- Page Numbers -->
        @for (page of visiblePages(); track page.value) {
          <li>
            @if (page.type === 'page') {
              <button
                type="button"
                [class]="getItemClasses(page.value === currentPage(), false, false)"
                [attr.aria-label]="getPageAriaLabel(page.value)"
                [attr.aria-current]="page.value === currentPage() ? 'page' : null"
                (click)="goToPage(page.value)"
              >
                {{ page.display }}
              </button>
            } @else {
              <span [class]="getItemClasses(false, true, false)" aria-hidden="true">
                <fa-icon [icon]="ellipsisIcon" />
              </span>
            }
          </li>
        }

        <!-- Next Button -->
        <li>
          <button
            type="button"
            [class]="getItemClasses(false, false, !hasNext())"
            [disabled]="!hasNext()"
            [attr.aria-label]="nextAriaLabel"
            (click)="goToNext()"
          >
            @if (showLabels) {
              <span>{{ nextLabel }}</span>
            }
            <fa-icon [icon]="nextIcon" />
          </button>
        </li>
      </ul>

      <!-- Page Info -->
      @if (showInfo) {
        <div [class]="getInfoClasses()">
          {{ getInfoText() }}
        </div>
      }
    </nav>
  `,
  styleUrl: './pagination.component.scss'
})
export class PaginationComponent {
  @Input() currentPage = signal(1);
  @Input() totalPages = signal(1);
  @Input() totalItems?: number;
  @Input() itemsPerPage?: number;
  @Input() size: PaginationSize = 'md';
  @Input() alignment: PaginationAlignment = 'center';
  @Input() compact = false;
  @Input() showInfo = true;
  @Input() showLabels = false;
  @Input() maxVisible = 7;
  @Input() ariaLabel = 'Pagination navigation';
  @Input() previousLabel = 'Previous';
  @Input() nextLabel = 'Next';
  @Input() previousAriaLabel = 'Go to previous page';
  @Input() nextAriaLabel = 'Go to next page';
  @Input() disabled = false;

  @Output() pageChange = new EventEmitter<PageChangeEvent>();

  // Icons
  prevIcon = faChevronLeft;
  nextIcon = faChevronRight;
  ellipsisIcon = faEllipsisH;

  // Computed properties using signals
  hasPrevious = computed(() => this.currentPage() > 1 && !this.disabled);
  hasNext = computed(() => this.currentPage() < this.totalPages() && !this.disabled);

  visiblePages = computed(() => {
    const current = this.currentPage();
    const total = this.totalPages();
    const max = this.maxVisible;

    if (total <= max) {
      // Show all pages if total is within max visible
      return Array.from({ length: total }, (_, i) => ({
        value: i + 1,
        display: (i + 1).toString(),
        type: 'page' as const
      }));
    }

    const pages: Array<{ value: number; display: string; type: 'page' | 'ellipsis' }> = [];
    const sidePages = Math.floor((max - 3) / 2); // Reserve space for first, last, and ellipses

    // Always show first page
    pages.push({ value: 1, display: '1', type: 'page' });

    if (current <= sidePages + 2) {
      // Current is near the beginning
      for (let i = 2; i <= Math.min(max - 1, total - 1); i++) {
        pages.push({ value: i, display: i.toString(), type: 'page' });
      }
      if (total > max - 1) {
        pages.push({ value: -1, display: '...', type: 'ellipsis' });
      }
    } else if (current >= total - sidePages - 1) {
      // Current is near the end
      if (total > max - 1) {
        pages.push({ value: -1, display: '...', type: 'ellipsis' });
      }
      for (let i = Math.max(total - max + 2, 2); i <= total - 1; i++) {
        pages.push({ value: i, display: i.toString(), type: 'page' });
      }
    } else {
      // Current is in the middle
      pages.push({ value: -1, display: '...', type: 'ellipsis' });
      const start = Math.max(2, current - sidePages);
      const end = Math.min(total - 1, current + sidePages);
      for (let i = start; i <= end; i++) {
        pages.push({ value: i, display: i.toString(), type: 'page' });
      }
      pages.push({ value: -2, display: '...', type: 'ellipsis' });
    }

    // Always show last page if more than 1 page
    if (total > 1) {
      pages.push({ value: total, display: total.toString(), type: 'page' });
    }

    return pages;
  });

  wrapperClasses = computed(() => {
    return [
      'ui-pagination',
      `ui-pagination--${this.size}`,
      `ui-pagination--${this.alignment}`,
      this.compact ? 'ui-pagination--compact' : '',
      this.disabled ? 'ui-pagination--disabled' : ''
    ].filter(Boolean).join(' ');
  });

  getItemClasses(isCurrent: boolean, isEllipsis: boolean, isDisabled: boolean): string {
    return [
      'pagination-item',
      isCurrent ? 'pagination-item--current' : '',
      isEllipsis ? 'pagination-item--ellipsis' : '',
      isDisabled ? 'pagination-item--disabled' : '',
      !isCurrent && !isEllipsis ? 'pagination-item--nav' : ''
    ].filter(Boolean).join(' ');
  }

  getInfoClasses(): string {
    return [
      'pagination-info',
      `pagination-info--${this.size}`
    ].filter(Boolean).join(' ');
  }

  getPageAriaLabel(page: number): string {
    return page === this.currentPage() 
      ? `Page ${page}, current page`
      : `Go to page ${page}`;
  }

  getInfoText(): string {
    const current = this.currentPage();
    const total = this.totalPages();
    
    if (this.totalItems && this.itemsPerPage) {
      const startItem = (current - 1) * this.itemsPerPage + 1;
      const endItem = Math.min(current * this.itemsPerPage, this.totalItems);
      return `${startItem}–${endItem} of ${this.totalItems} items`;
    }
    
    return `Page ${current} of ${total}`;
  }

  goToPage(page: number): void {
    if (page !== this.currentPage() && page >= 1 && page <= this.totalPages() && !this.disabled) {
      const previousPage = this.currentPage();
      this.currentPage.set(page);
      this.pageChange.emit({ page, previousPage });
    }
  }

  goToPrevious(): void {
    if (this.hasPrevious()) {
      this.goToPage(this.currentPage() - 1);
    }
  }

  goToNext(): void {
    if (this.hasNext()) {
      this.goToPage(this.currentPage() + 1);
    }
  }

  // Public methods for programmatic navigation
  first(): void {
    this.goToPage(1);
  }

  last(): void {
    this.goToPage(this.totalPages());
  }
}