import { Component, Input, Output, EventEmitter, ChangeDetectionStrategy, ContentChild, TemplateRef } from '@angular/core';
import { CommonModule } from '@angular/common';

export type TableVariant = 'default' | 'striped' | 'bordered' | 'minimal';
export type TableSize = 'compact' | 'default' | 'comfortable';
export type TableColumnAlign = 'left' | 'center' | 'right';

export interface TableColumn {
  key: string;
  label: string;
  sortable?: boolean;
  align?: TableColumnAlign;
  width?: string;
  sticky?: boolean;
}

export interface TableSortEvent {
  column: string;
  direction: 'asc' | 'desc' | null;
}

@Component({
  selector: 'ui-table',
  standalone: true,
  imports: [CommonModule],
  changeDetection: ChangeDetectionStrategy.OnPush,
  template: `
    <div [class]="tableContainerClasses">
      <table [class]="tableClasses">
        <!-- Table Header -->
        @if (showHeader && columns.length > 0) {
          <thead class="ui-table__header">
            <tr class="ui-table__header-row">
              @for (column of columns; track column.key) {
                <th 
                  [class]="getHeaderCellClasses(column)"
                  [style.width]="column.width"
                  [attr.aria-sort]="getSortAttribute(column.key)"
                  (click)="handleSort(column)"
                >
                  <div class="ui-table__header-content">
                    <span class="ui-table__header-text">{{ column.label }}</span>
                    @if (column.sortable && sortColumn === column.key) {
                      <span class="ui-table__sort-indicator" [attr.data-direction]="sortDirection">
                        @if (sortDirection === 'asc') {
                          ↑
                        } @else if (sortDirection === 'desc') {
                          ↓
                        }
                      </span>
                    }
                  </div>
                </th>
              }
            </tr>
          </thead>
        }

        <!-- Table Body -->
        <tbody class="ui-table__body">
          @if (data.length === 0 && showEmptyState) {
            <tr class="ui-table__empty-row">
              <td [attr.colspan]="columns.length" class="ui-table__empty-cell">
                <div class="ui-table__empty-content">
                  @if (emptyTemplate) {
                    <ng-container [ngTemplateOutlet]="emptyTemplate"></ng-container>
                  } @else {
                    <div class="ui-table__empty-text">{{ emptyMessage }}</div>
                  }
                </div>
              </td>
            </tr>
          } @else {
            @for (row of data; track trackByFn ? trackByFn($index, row) : $index; let rowIndex = $index) {
              <tr 
                [class]="getRowClasses(row, rowIndex)"
                (click)="handleRowClick(row, rowIndex)"
                [attr.aria-rowindex]="rowIndex + 1"
              >
                @for (column of columns; track column.key) {
                  <td [class]="getBodyCellClasses(column, row)">
                    @if (getCellTemplate(column.key)) {
                      <ng-container 
                        [ngTemplateOutlet]="getCellTemplate(column.key)!" 
                        [ngTemplateOutletContext]="{
                          $implicit: getCellValue(row, column.key),
                          row: row,
                          column: column,
                          index: rowIndex
                        }"
                      ></ng-container>
                    } @else {
                      <span class="ui-table__cell-content">
                        {{ getCellValue(row, column.key) }}
                      </span>
                    }
                  </td>
                }
              </tr>
            }
          }
        </tbody>
      </table>

      <!-- Loading Overlay -->
      @if (loading) {
        <div class="ui-table__loading-overlay">
          <div class="ui-table__loading-spinner"></div>
          <div class="ui-table__loading-text">{{ loadingMessage }}</div>
        </div>
      }
    </div>
  `,
  styleUrl: './table.component.scss'
})
export class TableComponent {
  @Input() data: any[] = [];
  @Input() columns: TableColumn[] = [];
  @Input() variant: TableVariant = 'default';
  @Input() size: TableSize = 'default';
  @Input() showHeader: boolean = true;
  @Input() showEmptyState: boolean = true;
  @Input() emptyMessage: string = 'No data available';
  @Input() loading: boolean = false;
  @Input() loadingMessage: string = 'Loading...';
  @Input() hoverable: boolean = true;
  @Input() selectable: boolean = false;
  @Input() stickyHeader: boolean = false;
  @Input() maxHeight: string = '';
  @Input() sortColumn: string = '';
  @Input() sortDirection: 'asc' | 'desc' | null = null;
  @Input() trackByFn?: (index: number, item: any) => any;
  @Input() cellTemplates: Record<string, TemplateRef<any>> = {};
  @Input() class: string = '';

  @Output() rowClick = new EventEmitter<{row: any, index: number}>();
  @Output() sort = new EventEmitter<TableSortEvent>();
  @Output() selectionChange = new EventEmitter<any[]>();

  @ContentChild('emptyTemplate') emptyTemplate?: TemplateRef<any>;

  selectedRows: Set<any> = new Set();

  get tableContainerClasses(): string {
    return [
      'ui-table-container',
      this.stickyHeader ? 'ui-table-container--sticky-header' : '',
      this.maxHeight ? 'ui-table-container--max-height' : '',
      this.loading ? 'ui-table-container--loading' : '',
      this.class
    ].filter(Boolean).join(' ');
  }

  get tableClasses(): string {
    return [
      'ui-table',
      `ui-table--${this.variant}`,
      `ui-table--${this.size}`,
      this.hoverable ? 'ui-table--hoverable' : '',
      this.selectable ? 'ui-table--selectable' : '',
    ].filter(Boolean).join(' ');
  }

  getHeaderCellClasses(column: TableColumn): string {
    return [
      'ui-table__header-cell',
      `ui-table__header-cell--${column.align || 'left'}`,
      column.sortable ? 'ui-table__header-cell--sortable' : '',
      column.sticky ? 'ui-table__header-cell--sticky' : '',
      this.sortColumn === column.key ? 'ui-table__header-cell--sorted' : ''
    ].filter(Boolean).join(' ');
  }

  getBodyCellClasses(column: TableColumn, row: any): string {
    return [
      'ui-table__body-cell',
      `ui-table__body-cell--${column.align || 'left'}`,
      column.sticky ? 'ui-table__body-cell--sticky' : ''
    ].filter(Boolean).join(' ');
  }

  getRowClasses(row: any, index: number): string {
    return [
      'ui-table__body-row',
      this.selectedRows.has(row) ? 'ui-table__body-row--selected' : '',
      index % 2 === 1 && this.variant === 'striped' ? 'ui-table__body-row--striped' : ''
    ].filter(Boolean).join(' ');
  }

  handleSort(column: TableColumn): void {
    if (!column.sortable) return;

    let newDirection: 'asc' | 'desc' | null;
    
    if (this.sortColumn === column.key) {
      // Toggle through: asc -> desc -> null -> asc
      if (this.sortDirection === 'asc') {
        newDirection = 'desc';
      } else if (this.sortDirection === 'desc') {
        newDirection = null;
      } else {
        newDirection = 'asc';
      }
    } else {
      newDirection = 'asc';
    }

    this.sort.emit({
      column: column.key,
      direction: newDirection
    });
  }

  handleRowClick(row: any, index: number): void {
    if (this.selectable) {
      this.toggleRowSelection(row);
    }
    
    this.rowClick.emit({ row, index });
  }

  toggleRowSelection(row: any): void {
    if (this.selectedRows.has(row)) {
      this.selectedRows.delete(row);
    } else {
      this.selectedRows.add(row);
    }
    
    this.selectionChange.emit(Array.from(this.selectedRows));
  }

  getCellValue(row: any, key: string): any {
    return key.split('.').reduce((obj, prop) => obj?.[prop], row) ?? '';
  }

  getCellTemplate(columnKey: string): TemplateRef<any> | null {
    return this.cellTemplates[columnKey] || null;
  }

  getSortAttribute(columnKey: string): string | null {
    if (this.sortColumn === columnKey) {
      return this.sortDirection === 'asc' ? 'ascending' : 'descending';
    }
    return null;
  }
}