import { ChangeDetectionStrategy, Component, input, output, signal } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { TranslocoDirective } from '@jsverse/transloco';
import { NgIcon, provideIcons } from '@ng-icons/core';
import { lucideFilter, lucideX } from '@ng-icons/lucide';
import { HlmButtonImports } from '@spartan-ng/helm/button';
import { HlmIconImports } from '@spartan-ng/helm/icon';
import { HlmInputImports } from '@spartan-ng/helm/input';
import { HlmPopoverImports } from '@spartan-ng/helm/popover';
import { HlmSelectImports } from '@spartan-ng/helm/select';
import { HlmSeparatorImports } from '@spartan-ng/helm/separator';

import type { ColumnFilter, LabeledColumn } from '../types';

const OPERATOR_TRANSLATION_KEYS: Record<string, string> = {
  contains: 'Contains',
  equals: 'Equals',
  startsWith: 'StartsWith',
  endsWith: 'EndsWith',
  greaterThan: 'GreaterThan',
  lessThan: 'LessThan',
};

@Component({
  selector: 'au-table-filters',
  changeDetection: ChangeDetectionStrategy.OnPush,
  imports: [
    FormsModule,
    NgIcon,
    TranslocoDirective,
    HlmButtonImports,
    HlmIconImports,
    HlmInputImports,
    HlmPopoverImports,
    HlmSelectImports,
    HlmSeparatorImports,
  ],
  providers: [provideIcons({ lucideFilter, lucideX })],
  host: { class: 'block' },
  template: `
    <hlm-popover
      *transloco="let t"
      align="end"
    >
      <button
        class="relative"
        hlmPopoverTrigger
        hlmBtn
        variant="outline"
        size="sm"
      >
        <ng-icon
          name="lucideFilter"
          class="sm:mr-1"
          hlm
          size="sm"
        />
        <span class="hidden sm:inline">{{ t('Filters') }}</span>
        @if (activeFilters().length) {
          <span
            class="bg-primary text-primary-foreground ml-1.5 inline-flex size-5 items-center justify-center rounded-full text-[10px] font-bold"
          >
            {{ activeFilters().length }}
          </span>
        }
      </button>
      <hlm-popover-content
        *hlmPopoverPortal
        class="w-80 p-4"
      >
        <div class="space-y-3">
          <h4 class="text-sm font-medium">{{ t('AddFilter') }}</h4>
          <div class="space-y-2">
            <hlm-select
              class="w-full"
              [ngModel]="filterColumn()"
              (ngModelChange)="filterColumn.set($event)"
            >
              <hlm-select-trigger
                class="h-9 w-full"
                size="sm"
              >
                <hlm-select-value [placeholder]="t('SelectColumn')" />
              </hlm-select-trigger>
              <hlm-select-content *hlmSelectPortal>
                <hlm-select-group>
                  @for (col of columns(); track col.key) {
                    <hlm-select-item [value]="col.key">{{ col.label }}</hlm-select-item>
                  }
                </hlm-select-group>
              </hlm-select-content>
            </hlm-select>
            <hlm-select
              class="w-full"
              [ngModel]="filterOperator()"
              (ngModelChange)="filterOperator.set($event)"
            >
              <hlm-select-trigger
                class="h-9 w-full"
                size="sm"
              >
                <span class="truncate">{{ t(operatorKey()) }}</span>
              </hlm-select-trigger>
              <hlm-select-content *hlmSelectPortal>
                <hlm-select-group>
                  <hlm-select-item value="contains">{{ t('Contains') }}</hlm-select-item>
                  <hlm-select-item value="equals">{{ t('Equals') }}</hlm-select-item>
                  <hlm-select-item value="startsWith">{{ t('StartsWith') }}</hlm-select-item>
                  <hlm-select-item value="endsWith">{{ t('EndsWith') }}</hlm-select-item>
                  <hlm-select-item value="greaterThan">{{ t('GreaterThan') }}</hlm-select-item>
                  <hlm-select-item value="lessThan">{{ t('LessThan') }}</hlm-select-item>
                </hlm-select-group>
              </hlm-select-content>
            </hlm-select>
            <input
              class="h-8 w-full"
              [ngModel]="filterValue()"
              [placeholder]="t('Value')"
              hlmInput
              (ngModelChange)="filterValue.set($event)"
            />
            <button
              class="mt-2 w-full"
              [disabled]="!filterColumn() || !filterValue()"
              hlmBtn
              size="sm"
              (click)="addFilter()"
            >
              {{ t('AddFilter') }}
            </button>
          </div>
          @if (activeFilters().length) {
            <hlm-separator />
            <div class="space-y-2">
              <h4 class="text-sm font-medium">{{ t('ActiveFilters') }}</h4>
              @for (filter of activeFilters(); track $index) {
                <div
                  class="flex items-center justify-between gap-2 rounded-md border px-2 py-1.5 text-xs"
                >
                  <span class="truncate">
                    <span class="font-medium">{{ filter.columnLabel }}</span>
                    {{ t(operatorTranslationKey(filter.operator)) }}
                    <span class="font-medium">{{ filter.value }}</span>
                  </span>
                  <button
                    hlmBtn
                    variant="ghost"
                    size="icon-xs"
                    (click)="removeFilter($index)"
                  >
                    <ng-icon
                      name="lucideX"
                      hlm
                      size="xs"
                    />
                  </button>
                </div>
              }
              <button
                class="w-full"
                hlmBtn
                variant="outline"
                size="sm"
                (click)="clearFilters()"
              >
                {{ t('ClearFilters') }}
              </button>
            </div>
          }
        </div>
      </hlm-popover-content>
    </hlm-popover>
  `,
})
export class TableFilters {
  // inputs
  readonly columns = input.required<LabeledColumn[]>();

  // outputs
  readonly filtersChange = output<ColumnFilter[]>();

  // signals
  readonly activeFilters = signal<ColumnFilter[]>([]);
  readonly filterColumn = signal('');
  readonly filterOperator = signal('contains');
  readonly filterValue = signal('');

  readonly operatorKey = () =>
    OPERATOR_TRANSLATION_KEYS[this.filterOperator()] ?? this.filterOperator();

  operatorTranslationKey(op: string): string {
    return OPERATOR_TRANSLATION_KEYS[op] ?? op;
  }

  addFilter() {
    const col = this.filterColumn();
    const colDef = this.columns().find((c) => c.key === col);
    if (!col || !this.filterValue() || !colDef) return;

    this.activeFilters.update((f) => [
      ...f,
      {
        column: col,
        columnLabel: colDef.label,
        operator: this.filterOperator(),
        value: this.filterValue(),
      },
    ]);

    this.filterColumn.set('');
    this.filterValue.set('');
    this.filterOperator.set('contains');
    this.filtersChange.emit(this.activeFilters());
  }

  removeFilter(index: number) {
    this.activeFilters.update((f) => f.filter((_, i) => i !== index));
    this.filtersChange.emit(this.activeFilters());
  }

  clearFilters() {
    this.activeFilters.set([]);
    this.filtersChange.emit([]);
  }
}
