import { DecimalPipe } from '@angular/common';
import { Component, OnDestroy, OnInit, computed, inject, signal } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { TranslatePipe, TranslateService } from '@ngx-translate/core';
import { Subject, debounceTime, takeUntil } from 'rxjs';
import { IngredientCatalogService } from '../../core/services/ingredient-catalog.service';
import { LanguageService } from '../../core/services/language.service';
import {
  IngredientCategory,
  IngredientNutritionItem,
  UpsertIngredientNutritionItemInput,
} from '../../core/models/ingredient-catalog.models';
import { ErrorStateComponent } from '../../shared/components/error-state.component';
import { EmptyStateComponent } from '../../shared/components/empty-state.component';
import { SkeletonComponent } from '../../shared/components/skeleton.component';
import { extractApiError } from '../../core/utils/api-error.util';
import { nextSort, sortBy, sortIndicator, type SortDirection } from '../../core/utils/sort.util';

type IngredientSortColumn = 'name' | 'category' | 'calories' | 'protein' | 'fat' | 'carbs' | 'fiber';

const EMPTY_FORM: UpsertIngredientNutritionItemInput = {
  categoryId: 0,
  name: '',
  namePl: '',
  caloriesPer100G: 0,
  proteinGPer100G: 0,
  fatGPer100G: 0,
  carbsGPer100G: 0,
  fiberGPer100G: null,
  sortOrder: 0,
  isActive: true,
};

@Component({
  selector: 'app-ingredient-catalog',
  standalone: true,
  imports: [DecimalPipe, FormsModule, TranslatePipe, ErrorStateComponent, EmptyStateComponent, SkeletonComponent],
  template: `
    <div class="space-y-6">
      <header class="flex flex-wrap items-end justify-between gap-4">
        <div>
          <h1 class="text-2xl font-extrabold tracking-tight sm:text-3xl">
            {{ 'ingredientCatalog.title' | translate }}
          </h1>
          <p class="mt-1 text-slate-500 dark:text-slate-400">{{ 'ingredientCatalog.subtitle' | translate }}</p>
        </div>
        <button type="button" class="btn-secondary" (click)="openCreateForm()">
          + {{ 'ingredientCatalog.addIngredient' | translate }}
        </button>
      </header>

      @if (showForm()) {
        <section class="card space-y-4 p-5">
          <h2 class="text-lg font-bold">
            {{ editingId() ? ('ingredientCatalog.editIngredient' | translate) : ('ingredientCatalog.addIngredient' | translate) }}
          </h2>
          @if (formError()) {
            <p class="text-sm text-red-600">{{ formError() }}</p>
          }
          <div class="grid gap-4 sm:grid-cols-2">
            <label class="block text-sm sm:col-span-2">
              <span class="font-medium">{{ 'ingredientCatalog.columns.category' | translate }}</span>
              <select class="select mt-1 w-full" [(ngModel)]="form.categoryId">
                <option [ngValue]="0" disabled>{{ 'ingredientCatalog.selectCategory' | translate }}</option>
                @for (cat of categories(); track cat.id) {
                  <option [ngValue]="cat.id">{{ ('ingredientCatalog.categories.' + cat.code) | translate }}</option>
                }
              </select>
            </label>
            <label class="block text-sm">
              <span class="font-medium">{{ 'ingredientCatalog.nameEn' | translate }}</span>
              <input class="input mt-1 w-full" [(ngModel)]="form.name" />
            </label>
            <label class="block text-sm">
              <span class="font-medium">{{ 'ingredientCatalog.namePlLabel' | translate }}</span>
              <input class="input mt-1 w-full" [(ngModel)]="form.namePl" />
            </label>
            <label class="block text-sm">
              <span class="font-medium">{{ 'ingredientCatalog.columns.calories' | translate }}</span>
              <input type="number" min="0" class="input mt-1 w-full" [(ngModel)]="form.caloriesPer100G" />
            </label>
            <label class="block text-sm">
              <span class="font-medium">{{ 'ingredientCatalog.columns.protein' | translate }}</span>
              <input type="number" min="0" step="0.1" class="input mt-1 w-full" [(ngModel)]="form.proteinGPer100G" />
            </label>
            <label class="block text-sm">
              <span class="font-medium">{{ 'ingredientCatalog.columns.fat' | translate }}</span>
              <input type="number" min="0" step="0.1" class="input mt-1 w-full" [(ngModel)]="form.fatGPer100G" />
            </label>
            <label class="block text-sm">
              <span class="font-medium">{{ 'ingredientCatalog.columns.carbs' | translate }}</span>
              <input type="number" min="0" step="0.1" class="input mt-1 w-full" [(ngModel)]="form.carbsGPer100G" />
            </label>
            <label class="block text-sm">
              <span class="font-medium">{{ 'ingredientCatalog.columns.fiber' | translate }}</span>
              <input type="number" min="0" step="0.1" class="input mt-1 w-full" [(ngModel)]="form.fiberGPer100G" />
            </label>
          </div>
          <div class="flex gap-2">
            <button type="button" class="btn-primary" [disabled]="saving()" (click)="saveForm()">
              {{ 'common.save' | translate }}
            </button>
            <button type="button" class="btn-secondary" (click)="closeForm()">{{ 'common.cancel' | translate }}</button>
          </div>
        </section>
      }

      <div class="flex flex-wrap gap-2">
        <button type="button" (click)="setCategory('')" class="rounded-xl px-4 py-2 text-sm font-semibold transition" [class.bg-brand-600]="category() === ''" [class.text-white]="category() === ''" [class.bg-slate-100]="category() !== ''" [class.text-slate-600]="category() !== ''" [class.dark:bg-slate-800]="category() !== ''">
          {{ 'ingredientCatalog.allCategories' | translate }} ({{ totalItems() }})
        </button>
        @for (cat of categories(); track cat.code) {
          <button type="button" (click)="setCategory(cat.code)" class="rounded-xl px-4 py-2 text-sm font-semibold transition" [class.bg-brand-600]="category() === cat.code" [class.text-white]="category() === cat.code" [class.bg-slate-100]="category() !== cat.code" [class.text-slate-600]="category() !== cat.code" [class.dark:bg-slate-800]="category() !== cat.code">
            {{ ('ingredientCatalog.categories.' + cat.code) | translate }} ({{ cat.itemCount }})
          </button>
        }
      </div>

      <label class="block max-w-md text-sm">
        <span class="font-medium">{{ 'common.search' | translate }}</span>
        <input class="input mt-1 w-full" [(ngModel)]="search" (ngModelChange)="onSearch($event)" [placeholder]="'ingredientCatalog.searchPlaceholder' | translate" />
      </label>

      @if (loading()) {
        <app-skeleton [className]="'h-64 w-full'" />
      } @else if (error()) {
        <app-error-state [message]="error()!" [showRetry]="true" (retry)="fetchItems()" />
      } @else if (items().length === 0) {
        <app-empty-state [title]="'ingredientCatalog.noResultsTitle' | translate" [description]="'ingredientCatalog.noResultsDescription' | translate" />
      } @else {
        <div class="card overflow-hidden">
          <div class="overflow-x-auto">
            <table class="min-w-full text-left text-sm">
              <thead class="border-b border-slate-200 bg-slate-50 text-xs uppercase tracking-wide text-slate-500 dark:border-slate-700 dark:bg-slate-800/50">
                <tr>
                  <th class="px-4 py-3">
                    <button type="button" class="inline-flex items-center gap-1 font-inherit uppercase hover:text-slate-700 dark:hover:text-slate-200" (click)="toggleSort('name')">
                      {{ 'ingredientCatalog.columns.name' | translate }}{{ indicator('name') }}
                    </button>
                  </th>
                  <th class="px-4 py-3">
                    <button type="button" class="inline-flex items-center gap-1 font-inherit uppercase hover:text-slate-700 dark:hover:text-slate-200" (click)="toggleSort('category')">
                      {{ 'ingredientCatalog.columns.category' | translate }}{{ indicator('category') }}
                    </button>
                  </th>
                  <th class="px-4 py-3">
                    <button type="button" class="inline-flex items-center gap-1 font-inherit uppercase hover:text-slate-700 dark:hover:text-slate-200" (click)="toggleSort('calories')">
                      {{ 'ingredientCatalog.columns.calories' | translate }}{{ indicator('calories') }}
                    </button>
                  </th>
                  <th class="px-4 py-3">
                    <button type="button" class="inline-flex items-center gap-1 font-inherit uppercase hover:text-slate-700 dark:hover:text-slate-200" (click)="toggleSort('protein')">
                      {{ 'ingredientCatalog.columns.protein' | translate }}{{ indicator('protein') }}
                    </button>
                  </th>
                  <th class="px-4 py-3">
                    <button type="button" class="inline-flex items-center gap-1 font-inherit uppercase hover:text-slate-700 dark:hover:text-slate-200" (click)="toggleSort('fat')">
                      {{ 'ingredientCatalog.columns.fat' | translate }}{{ indicator('fat') }}
                    </button>
                  </th>
                  <th class="px-4 py-3">
                    <button type="button" class="inline-flex items-center gap-1 font-inherit uppercase hover:text-slate-700 dark:hover:text-slate-200" (click)="toggleSort('carbs')">
                      {{ 'ingredientCatalog.columns.carbs' | translate }}{{ indicator('carbs') }}
                    </button>
                  </th>
                  <th class="px-4 py-3">
                    <button type="button" class="inline-flex items-center gap-1 font-inherit uppercase hover:text-slate-700 dark:hover:text-slate-200" (click)="toggleSort('fiber')">
                      {{ 'ingredientCatalog.columns.fiber' | translate }}{{ indicator('fiber') }}
                    </button>
                  </th>
                  <th class="px-4 py-3"></th>
                </tr>
              </thead>
              <tbody class="divide-y divide-slate-100 dark:divide-slate-800">
                @for (item of sortedItems(); track item.id) {
                  <tr class="hover:bg-slate-50 dark:hover:bg-slate-800/30">
                    <td class="px-4 py-3 font-medium">{{ displayName(item) }}</td>
                    <td class="px-4 py-3 text-slate-500">{{ ('ingredientCatalog.categories.' + item.categoryCode) | translate }}</td>
                    <td class="px-4 py-3">{{ item.caloriesPer100G }}</td>
                    <td class="px-4 py-3">{{ item.proteinGPer100G | number: '1.1-1' }}</td>
                    <td class="px-4 py-3">{{ item.fatGPer100G | number: '1.1-1' }}</td>
                    <td class="px-4 py-3">{{ item.carbsGPer100G | number: '1.1-1' }}</td>
                    <td class="px-4 py-3">{{ item.fiberGPer100G != null ? (item.fiberGPer100G | number: '1.1-1') : '—' }}</td>
                    <td class="px-4 py-3 text-right">
                      <button type="button" class="mr-2 text-brand-600" (click)="openEditForm(item)">{{ 'common.edit' | translate }}</button>
                      <button type="button" class="text-red-500" (click)="deleteItem(item.id)">{{ 'common.delete' | translate }}</button>
                    </td>
                  </tr>
                }
              </tbody>
            </table>
          </div>
          <p class="border-t border-slate-200 px-4 py-3 text-xs text-slate-400 dark:border-slate-700">{{ 'ingredientCatalog.per100gNote' | translate }}</p>
        </div>
      }
    </div>
  `,
})
export class IngredientCatalogComponent implements OnInit, OnDestroy {
  private readonly catalog = inject(IngredientCatalogService);
  private readonly translate = inject(TranslateService);
  private readonly language = inject(LanguageService);
  private readonly destroy$ = new Subject<void>();
  private readonly search$ = new Subject<string>();

  categories = signal<IngredientCategory[]>([]);
  items = signal<IngredientNutritionItem[]>([]);
  category = signal('');
  loading = signal(true);
  error = signal<string | null>(null);
  showForm = signal(false);
  editingId = signal<number | null>(null);
  saving = signal(false);
  formError = signal<string | null>(null);
  search = '';
  form: UpsertIngredientNutritionItemInput = { ...EMPTY_FORM };
  sort = signal<{ column: IngredientSortColumn; direction: SortDirection }>({ column: 'name', direction: 'asc' });

  readonly sortedItems = computed(() => {
    const rows = this.items();
    const { column, direction } = this.sort();
    const lang = this.language.currentLanguage();
    return sortBy(rows, direction, (item) => {
      switch (column) {
        case 'name':
          return lang === 'pl' && item.namePl ? item.namePl : item.name;
        case 'category':
          return item.categoryCode;
        case 'calories':
          return item.caloriesPer100G;
        case 'protein':
          return Number(item.proteinGPer100G);
        case 'fat':
          return Number(item.fatGPer100G);
        case 'carbs':
          return Number(item.carbsGPer100G);
        case 'fiber':
          return item.fiberGPer100G != null ? Number(item.fiberGPer100G) : null;
      }
    });
  });

  ngOnInit(): void {
    this.loadCategories();
    this.search$.pipe(debounceTime(300), takeUntil(this.destroy$)).subscribe(() => this.fetchItems());
    this.fetchItems();
  }

  ngOnDestroy(): void {
    this.destroy$.next();
    this.destroy$.complete();
  }

  loadCategories(): void {
    this.catalog.getCategories().subscribe({
      next: (cats) => this.categories.set(cats),
      error: () => this.categories.set([]),
    });
  }

  totalItems(): number {
    return this.categories().reduce((sum, c) => sum + c.itemCount, 0);
  }

  setCategory(code: string): void {
    this.category.set(code);
    this.fetchItems();
  }

  onSearch(value: string): void {
    this.search = value;
    this.search$.next(value);
  }

  fetchItems(): void {
    this.loading.set(true);
    this.error.set(null);
    this.catalog.getItems(this.category() || undefined, this.search.trim() || undefined).pipe(takeUntil(this.destroy$)).subscribe({
      next: (rows) => {
        this.items.set(rows);
        this.loading.set(false);
      },
      error: (err) => {
        this.error.set(extractApiError(err, this.translate.instant('errors.loadIngredientCatalogFailed')));
        this.loading.set(false);
      },
    });
  }

  openCreateForm(): void {
    this.editingId.set(null);
    this.form = { ...EMPTY_FORM, categoryId: this.categories()[0]?.id ?? 0 };
    this.formError.set(null);
    this.showForm.set(true);
  }

  openEditForm(item: IngredientNutritionItem): void {
    this.editingId.set(item.id);
    this.form = {
      categoryId: item.categoryId,
      name: item.name,
      namePl: item.namePl ?? '',
      caloriesPer100G: item.caloriesPer100G,
      proteinGPer100G: item.proteinGPer100G,
      fatGPer100G: item.fatGPer100G,
      carbsGPer100G: item.carbsGPer100G,
      fiberGPer100G: item.fiberGPer100G,
      sortOrder: 0,
      isActive: true,
    };
    this.formError.set(null);
    this.showForm.set(true);
  }

  closeForm(): void {
    this.showForm.set(false);
    this.editingId.set(null);
    this.formError.set(null);
  }

  saveForm(): void {
    if (!this.form.categoryId || !this.form.name.trim()) {
      this.formError.set(this.translate.instant('ingredientCatalog.formInvalid'));
      return;
    }
    this.saving.set(true);
    this.formError.set(null);
    const payload = {
      ...this.form,
      name: this.form.name.trim(),
      namePl: this.form.namePl?.trim() || null,
      fiberGPer100G: this.form.fiberGPer100G ?? null,
    };
    const req = this.editingId()
      ? this.catalog.updateItem(this.editingId()!, payload)
      : this.catalog.createItem(payload);
    req.pipe(takeUntil(this.destroy$)).subscribe({
      next: () => {
        this.saving.set(false);
        this.closeForm();
        this.loadCategories();
        this.fetchItems();
      },
      error: (err) => {
        this.saving.set(false);
        this.formError.set(extractApiError(err, this.translate.instant('errors.saveIngredientFailed')));
      },
    });
  }

  deleteItem(id: number): void {
    if (!confirm(this.translate.instant('ingredientCatalog.deleteConfirm'))) return;
    this.catalog.deleteItem(id).pipe(takeUntil(this.destroy$)).subscribe({
      next: () => {
        this.loadCategories();
        this.fetchItems();
      },
    });
  }

  displayName(item: IngredientNutritionItem): string {
    if (this.language.currentLanguage() === 'pl' && item.namePl) return item.namePl;
    return item.name;
  }

  toggleSort(column: IngredientSortColumn): void {
    this.sort.update((current) => nextSort(current, column));
  }

  indicator(column: IngredientSortColumn): string {
    return sortIndicator(this.sort(), column);
  }
}
