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

export interface DataTableColumn {
  id: string;
  label: string;
  width?: string;
  template?: TemplateRef<unknown>;
  className?: string | ((row: Record<string, any>) => string);
  style?: Record<string, string> | ((row: Record<string, any>) => Record<string, string>); // Inline style
  onClick?: (row: Record<string, any>, value: any) => void; // Custom click handler
  link?: (row: Record<string, any>) => string; // For clickable URLs
  sortable?: boolean; // Enable header sorting for this column
  accessor?: (row: Record<string, any>) => unknown; // Optional custom accessor for sorting
  groupable?: boolean; // Enable grouping by this column
  parentHeader?: string; // Parent header label for multi-level headers
  colspan?: number; // Number of columns this header spans
  align?: 'left' | 'center' | 'right'; // Header alignment
  borders?: {
    left?: boolean;
    right?: boolean;
    top?: boolean;
    bottom?: boolean;
  }; // Individual border control for this column
}

@Component({
  selector: 'ccl-datatable',
  standalone: true,
  imports: [CommonModule],
  templateUrl: './datatable.html',
  styleUrls: ['./datatable.css'],
})
export class DataTableComponent {
  @Input() columns: DataTableColumn[] = [];
  @Input() rows: Record<string, unknown>[] = [];
  @Input() striped = false;
  @Input() bordered = false;
  @Input() compact = false;
  @Input() clientSort = true; // When true, component applies sorting locally
  @Input() groupBy?: string; // Column ID to group by
  @Input() groupCollapsible = true; // Allow collapsing/expanding groups
  @Input() groupHeaderTemplate?: TemplateRef<unknown>; // Custom group header template

  @Output() sortChange = new EventEmitter<{ id: string; direction: 'asc' | 'desc' | '' }>();
  @Output() groupToggle = new EventEmitter<{ groupKey: string; expanded: boolean }>();

  sortId: string = '';
  sortDirection: 'asc' | 'desc' | '' = '';
  expandedGroups = new Set<string>(); // Track which groups are expanded

  handleClick(col: DataTableColumn, row: any, value: any) {
    if (col.onClick) {
      col.onClick(row, value);
    } else if (col.link) {
      const url = col.link(row);
      if (url) window.location.href = url;
    }
  }

  getClass(col: DataTableColumn, row: any): string {
    return typeof col.className === 'function'
      ? col.className(row)
      : col.className || '';
  }

  getStyle(col: DataTableColumn, row: any): Record<string, string> {
    return typeof col.style === 'function'
      ? col.style(row)
      : col.style || {};
  }

  onHeaderClick(col: DataTableColumn) {
    if (!col.sortable) return;
    if (this.sortId !== col.id) {
      this.sortId = col.id;
      this.sortDirection = 'asc';
    } else {
      this.sortDirection = this.sortDirection === 'asc' ? 'desc' : this.sortDirection === 'desc' ? '' : 'asc';
      if (this.sortDirection === '') {
        this.sortId = '';
      }
    }
    this.sortChange.emit({ id: this.sortId, direction: this.sortDirection });
  }

  get rowsToRender(): Record<string, unknown>[] {
    if (!this.clientSort || !this.sortId || !this.sortDirection) return this.rows;
    const col = this.columns.find(c => c.id === this.sortId);
    if (!col) return this.rows;
    const accessor = col.accessor || ((row: Record<string, any>) => row[col.id]);
    const sorted = [...this.rows].sort((a, b) => {
      const va = accessor(a as any);
      const vb = accessor(b as any);
      if (va == null && vb == null) return 0;
      if (va == null) return -1;
      if (vb == null) return 1;
      if (va < vb) return -1;
      if (va > vb) return 1;
      return 0;
    });
    return this.sortDirection === 'asc' ? sorted : sorted.reverse();
  }

  get groupedRows(): Array<{ isGroup: boolean; groupKey?: string; groupValue?: any; rows?: Record<string, unknown>[] }> {
    if (!this.groupBy) return this.rowsToRender.map(row => ({ isGroup: false, rows: [row] }));
    
    const groups = new Map<string, Record<string, unknown>[]>();
    this.rowsToRender.forEach(row => {
      const groupKey = String(row[this.groupBy!] || 'Unknown');
      if (!groups.has(groupKey)) groups.set(groupKey, []);
      groups.get(groupKey)!.push(row);
    });
    
    const result: Array<{ isGroup: boolean; groupKey?: string; groupValue?: any; rows?: Record<string, unknown>[] }> = [];
    Array.from(groups.entries()).sort(([a], [b]) => a.localeCompare(b)).forEach(([groupKey, rows]) => {
      result.push({ isGroup: true, groupKey, groupValue: rows[0][this.groupBy!], rows });
    });
    
    return result;
  }

  toggleGroup(groupKey: string) {
    if (!this.groupCollapsible) return;
    const isExpanded = this.expandedGroups.has(groupKey);
    if (isExpanded) {
      this.expandedGroups.delete(groupKey);
    } else {
      this.expandedGroups.add(groupKey);
    }
    this.groupToggle.emit({ groupKey, expanded: !isExpanded });
  }

  isGroupExpanded(groupKey: string): boolean {
    return !this.groupCollapsible || this.expandedGroups.has(groupKey);
  }

  get parentHeaders(): Array<{ label: string; colspan: number; startIndex: number }> {
    const parentMap = new Map<string, { colspan: number; startIndex: number }>();
    
    this.columns.forEach((col, index) => {
      if (col.parentHeader) {
        if (!parentMap.has(col.parentHeader)) {
          parentMap.set(col.parentHeader, { colspan: 0, startIndex: index });
        }
        parentMap.get(col.parentHeader)!.colspan++;
      }
    });
    
    return Array.from(parentMap.entries()).map(([label, info]) => ({
      label,
      colspan: info.colspan,
      startIndex: info.startIndex
    }));
  }

  getParentHeaderAt(index: number): { label: string; colspan: number; startIndex: number } | undefined {
    return this.parentHeaders.find(p => p.startIndex === index);
  }

  getHeaderBorderClasses(col: DataTableColumn): string {
    if (!col.borders) return '';
    
    const classes: string[] = [];
    if (col.borders.left) classes.push('ccl-datatable__border-left');
    if (col.borders.right) classes.push('ccl-datatable__border-right');
    if (col.borders.top) classes.push('ccl-datatable__border-top');
    if (col.borders.bottom) classes.push('ccl-datatable__border-bottom');
    
    return classes.join(' ');
  }

  getCellBorderClasses(col: DataTableColumn): string {
    if (!col.borders) return '';
    
    const classes: string[] = [];
    if (col.borders.left) classes.push('ccl-datatable__cell-border-left');
    if (col.borders.right) classes.push('ccl-datatable__cell-border-right');
    if (col.borders.top) classes.push('ccl-datatable__cell-border-top');
    if (col.borders.bottom) classes.push('ccl-datatable__cell-border-bottom');
    
    return classes.join(' ');
  }
}
