import {
  ChangeDetectionStrategy,
  Component,
  Input,
  computed,
  signal,
} from '@angular/core';
import { CommonModule } from '@angular/common';
import { MatTableModule } from '@angular/material/table';
import { MatChipsModule } from '@angular/material/chips';
import { MatIconModule } from '@angular/material/icon';
import { MatProgressBarModule } from '@angular/material/progress-bar';
import { MatTooltipModule } from '@angular/material/tooltip';
import { MatSortModule, Sort } from '@angular/material/sort';
import { FilamentFilterComponent, FilamentFilterState } from '../filament-filter/filament-filter.component';
import {
  Filament,
  StockLevel,
  getRemainingPercent,
  classifyStockLevel,
} from '../../models/filament.model';

/** Display column definitions for the filament table */
export type FilamentColumn =
  | 'color'
  | 'material'
  | 'brand'
  | 'serial'
  | 'remaining'
  | 'stockLevel'
  | 'status';

@Component({
  selector: 'app-filament-table',
  standalone: true,
  imports: [
    CommonModule,
    MatTableModule,
    MatChipsModule,
    MatIconModule,
    MatProgressBarModule,
    MatTooltipModule,
    MatSortModule,
    FilamentFilterComponent,
  ],
  templateUrl: './filament-table.component.html',
  styleUrl: './filament-table.component.scss',
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class FilamentTableComponent {
  /** Filament data input — reactive signal for live updates */
  readonly filaments = signal<Filament[]>([]);

  /** Columns to display — defaults to all columns */
  @Input()
  set displayedColumns(cols: FilamentColumn[]) {
    this._displayedColumns.set(cols);
  }
  get displayedColumns(): FilamentColumn[] {
    return this._displayedColumns();
  }
  private readonly _displayedColumns = signal<FilamentColumn[]>([
    'color',
    'material',
    'brand',
    'serial',
    'remaining',
    'stockLevel',
    'status',
  ]);

  /** Default columns for template binding */
  readonly columns = this._displayedColumns;

  /** Current filter state */
  readonly filterState = signal<FilamentFilterState>({
    materialBaseNames: [],
    colorSearch: '',
    lowStockOnly: false,
    activeOnly: false,
  });

  /** Sorted filament data */
  readonly sortedFilaments = signal<Filament[]>([]);

  /** Computed: filtered + sorted filament data for display */
  readonly filteredFilaments = computed(() => {
    const data = this.sortedFilaments();
    const filters = this.filterState();
    return data.filter((f) => this.matchesFilter(f, filters));
  });

  /** Computed: count of low/critical spools */
  readonly lowStockCount = computed(() =>
    this.filaments().filter(
      (f) => classifyStockLevel(f) === 'low' || classifyStockLevel(f) === 'critical'
    ).length
  );

  /** Computed: count of critical spools */
  readonly criticalCount = computed(() =>
    this.filaments().filter((f) => classifyStockLevel(f) === 'critical').length
  );

  constructor() {
    // Initialize sorted data from filaments
    // (MatSort handles sorting via sortChange; we start unsorted)

    // Development: seed with sample data for visual testing
    // TODO: Replace with service data from FilamentService / SignalR
    this.updateFilaments([
      {
        id: '1',
        materialBaseId: 'm1',
        materialBaseName: 'PLA',
        materialFinishId: 'f1',
        materialFinishName: 'Basic',
        materialModifierId: null,
        materialModifierName: null,
        brand: 'Bambu Lab',
        colorName: 'White',
        colorHex: '#F5F5F5',
        weightTotalGrams: 1000,
        weightRemainingGrams: 850,
        filamentDiameterMm: 1.75,
        spoolSerial: 'SN-001',
        purchasePrice: 25.00,
        purchaseDate: '2026-01-15T00:00:00Z',
        isActive: true,
        createdAt: '2026-01-15T00:00:00Z',
        updatedAt: '2026-04-20T00:00:00Z',
        qrCodeUrl: '',
      },
      {
        id: '2',
        materialBaseId: 'm2',
        materialBaseName: 'PETG',
        materialFinishId: 'f2',
        materialFinishName: 'Matte',
        materialModifierId: 'mod1',
        materialModifierName: 'Carbon Fiber',
        brand: 'Polymaker',
        colorName: 'Fire Engine Red',
        colorHex: '#FF0000',
        weightTotalGrams: 1000,
        weightRemainingGrams: 80,
        filamentDiameterMm: 1.75,
        spoolSerial: 'SN-002',
        purchasePrice: 35.00,
        purchaseDate: '2026-02-01T00:00:00Z',
        isActive: true,
        createdAt: '2026-02-01T00:00:00Z',
        updatedAt: '2026-04-25T00:00:00Z',
        qrCodeUrl: '',
      },
      {
        id: '3',
        materialBaseId: 'm1',
        materialBaseName: 'PLA',
        materialFinishId: 'f1',
        materialFinishName: 'Basic',
        materialModifierId: null,
        materialModifierName: null,
        brand: 'eSun',
        colorName: 'Sky Blue',
        colorHex: '#87CEEB',
        weightTotalGrams: 1000,
        weightRemainingGrams: 200,
        filamentDiameterMm: 1.75,
        spoolSerial: 'SN-003',
        purchasePrice: 20.00,
        purchaseDate: '2026-03-10T00:00:00Z',
        isActive: true,
        createdAt: '2026-03-10T00:00:00Z',
        updatedAt: '2026-04-26T00:00:00Z',
        qrCodeUrl: '',
      },
      {
        id: '4',
        materialBaseId: 'm3',
        materialBaseName: 'ABS',
        materialFinishId: 'f1',
        materialFinishName: 'Basic',
        materialModifierId: null,
        materialModifierName: null,
        brand: 'Hatchbox',
        colorName: 'Black',
        colorHex: '#1A1A1A',
        weightTotalGrams: 1000,
        weightRemainingGrams: 450,
        filamentDiameterMm: 1.75,
        spoolSerial: 'SN-004',
        purchasePrice: 22.00,
        purchaseDate: null,
        isActive: true,
        createdAt: '2026-01-20T00:00:00Z',
        updatedAt: '2026-04-18T00:00:00Z',
        qrCodeUrl: '',
      },
      {
        id: '5',
        materialBaseId: 'm1',
        materialBaseName: 'PLA',
        materialFinishId: 'f3',
        materialFinishName: 'Silk',
        materialModifierId: null,
        materialModifierName: null,
        brand: 'Overturn',
        colorName: 'Gold',
        colorHex: '#FFD700',
        weightTotalGrams: 500,
        weightRemainingGrams: 15,
        filamentDiameterMm: 1.75,
        spoolSerial: 'SN-005',
        purchasePrice: 28.00,
        purchaseDate: null,
        isActive: false,
        createdAt: '2025-12-01T00:00:00Z',
        updatedAt: '2026-04-01T00:00:00Z',
        qrCodeUrl: '',
      },
    ]);
  }

  /** Update filament data — called by parent or service */
  updateFilaments(data: Filament[]): void {
    this.filaments.set(data);
    this.sortedFilaments.set([...data]);
  }

  /** All filament data — for the filter component to derive material options */
  readonly allFilaments = this.filaments;

  /** Handle sort changes from MatSort */
  sortData(sort: Sort): void {
    const data = [...this.filaments()];
    if (!sort.active || sort.direction === '') {
      this.sortedFilaments.set(data);
      return;
    }
    const sorted = data.sort((a, b) => {
      const isAsc = sort.direction === 'asc';
      switch (sort.active as FilamentColumn) {
        case 'material':
          return compare(a.materialBaseName, b.materialBaseName, isAsc);
        case 'brand':
          return compare(a.brand, b.brand, isAsc);
        case 'serial':
          return compare(a.spoolSerial, b.spoolSerial, isAsc);
        case 'remaining':
          return compare(
            getRemainingPercent(a),
            getRemainingPercent(b),
            isAsc
          );
        case 'stockLevel':
          return compare(
            stockLevelOrder(classifyStockLevel(a)),
            stockLevelOrder(classifyStockLevel(b)),
            isAsc
          );
        case 'status':
          return compare(
            a.isActive ? 0 : 1,
            b.isActive ? 0 : 1,
            isAsc
          );
        default:
          return 0;
      }
    });
    this.sortedFilaments.set(sorted);
  }

  /** Handle filter changes from FilamentFilterComponent */
  onFilterChange(state: FilamentFilterState): void {
    this.filterState.set(state);
  }

  /** Check if a filament matches the current filter state */
  private matchesFilter(filament: Filament, filters: FilamentFilterState): boolean {
    // Material filter — empty means all
    if (
      filters.materialBaseNames.length > 0 &&
      !filters.materialBaseNames.includes(filament.materialBaseName)
    ) {
      return false;
    }

    // Color search — empty means all
    if (
      filters.colorSearch &&
      !filament.colorName.toLowerCase().includes(filters.colorSearch) &&
      !filament.colorHex.toLowerCase().includes(filters.colorSearch)
    ) {
      return false;
    }

    // Low stock filter — show only critical/low
    if (filters.lowStockOnly) {
      const level = classifyStockLevel(filament);
      if (level !== 'critical' && level !== 'low') {
        return false;
      }
    }

    // Active only filter
    if (filters.activeOnly && !filament.isActive) {
      return false;
    }

    return true;
  }

  /** Template helper: get remaining percent */
  getRemainingPercent = getRemainingPercent;

  /** Template helper: classify stock level */
  classifyStockLevel = classifyStockLevel;

  /** Template helper: stock level icon */
  stockLevelIcon(level: StockLevel): string {
    switch (level) {
      case 'critical':
        return 'error';
      case 'low':
        return 'warning';
      case 'moderate':
        return 'info';
      case 'healthy':
        return 'check_circle';
    }
  }

  /** Template helper: stock level label */
  stockLevelLabel(level: StockLevel): string {
    switch (level) {
      case 'critical':
        return 'Critical';
      case 'low':
        return 'Low';
      case 'moderate':
        return 'Moderate';
      case 'healthy':
        return 'Healthy';
    }
  }

  /** Template helper: format remaining weight */
  formatWeight(grams: number): string {
    if (grams >= 1000) {
      return `${(grams / 1000).toFixed(1)}kg`;
    }
    return `${Math.round(grams)}g`;
  }
}

/** Compare helper for sorting */
function compare(a: number | string, b: number | string, isAsc: boolean): number {
  return (a < b ? -1 : a > b ? 1 : 0) * (isAsc ? 1 : -1);
}

/** Stock level sort order (critical=0, healthy=3) */
function stockLevelOrder(level: StockLevel): number {
  switch (level) {
    case 'critical':
      return 0;
    case 'low':
      return 1;
    case 'moderate':
      return 2;
    case 'healthy':
      return 3;
  }
}