import { DecimalPipe } from '@angular/common';
import { Component, OnInit, computed, inject, signal } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { TranslatePipe, TranslateService } from '@ngx-translate/core';
import { MealPlanService } from '../../core/services/meal-plan.service';
import { ShoppingListItem } from '../../core/models/meal-plan.models';
import {
  addDaysIso,
  endOfWeekIso,
  startOfWeekIso,
  todayIso,
} from '../../core/models/diet.models';
import { ErrorStateComponent } from '../../shared/components/error-state.component';
import { SkeletonComponent } from '../../shared/components/skeleton.component';
import { extractApiError } from '../../core/utils/api-error.util';

const CHECKLIST_KEY = 'dm_shopping_checklist';

@Component({
  selector: 'app-shopping-list',
  standalone: true,
  imports: [DecimalPipe, FormsModule, TranslatePipe, ErrorStateComponent, SkeletonComponent],
  template: `
    <div class="space-y-6">
      <header>
        <h1 class="text-2xl font-extrabold tracking-tight sm:text-3xl">{{ 'shoppingList.title' | translate }}</h1>
        <p class="mt-1 text-slate-500 dark:text-slate-400">{{ 'shoppingList.subtitle' | translate }}</p>
      </header>

      <div class="card flex flex-wrap items-end gap-4 p-5">
        <label class="block text-sm">
          <span class="font-medium">{{ 'shoppingList.from' | translate }}</span>
          <input type="date" class="input mt-1" [(ngModel)]="fromDate" />
        </label>
        <label class="block text-sm">
          <span class="font-medium">{{ 'shoppingList.to' | translate }}</span>
          <input type="date" class="input mt-1" [(ngModel)]="toDate" />
        </label>
        <button type="button" class="btn-secondary" (click)="loadList()">{{ 'shoppingList.load' | translate }}</button>
        <button type="button" class="btn-secondary !text-xs" (click)="clearChecks()">{{ 'shoppingList.clearChecks' | translate }}</button>
      </div>

      @if (loading()) {
        <app-skeleton [className]="'h-48 w-full'" />
      } @else if (error()) {
        <app-error-state [message]="error()!" [showRetry]="true" (retry)="loadList()" />
      } @else if (items().length === 0 && loaded()) {
        <p class="text-sm text-slate-400">{{ 'shoppingList.empty' | translate }}</p>
      } @else {
        <ul class="card divide-y divide-slate-200 dark:divide-slate-800">
          @for (item of items(); track itemKey(item)) {
            <li class="flex items-start gap-3 p-4">
              <input
                type="checkbox"
                class="mt-1 h-4 w-4 rounded border-slate-300"
                [checked]="isChecked(item)"
                (change)="toggleCheck(item)"
              />
              <div [class.opacity-50]="isChecked(item)" [class.line-through]="isChecked(item)">
                <p class="font-medium">{{ item.name }}</p>
                <p class="text-sm text-slate-500">
                  @if (item.totalGrams != null) {
                    {{ item.totalGrams | number: '1.0-1' }}g
                  } @else if (item.totalAmount != null) {
                    {{ item.totalAmount | number: '1.0-1' }} {{ item.unit ?? '' }}
                  }
                </p>
                @if (item.breakdown.length > 0) {
                  <ul class="mt-1 text-xs text-slate-400">
                    @for (line of item.breakdown; track line) {
                      <li>{{ line }}</li>
                    }
                  </ul>
                }
              </div>
            </li>
          }
        </ul>
        <p class="text-xs text-slate-400">{{ 'shoppingList.checklistHint' | translate }}</p>
      }
    </div>
  `,
})
export class ShoppingListComponent implements OnInit {
  private readonly mealPlan = inject(MealPlanService);
  private readonly translate = inject(TranslateService);

  fromDate = startOfWeekIso(todayIso());
  toDate = endOfWeekIso(todayIso());
  items = signal<ShoppingListItem[]>([]);
  checkedKeys = signal<Set<string>>(new Set());
  loading = signal(false);
  loaded = signal(false);
  error = signal<string | null>(null);

  readonly rangeKey = computed(() => `${this.fromDate}_${this.toDate}`);

  ngOnInit(): void {
    this.restoreChecks();
    this.loadList();
  }

  itemKey(item: ShoppingListItem): string {
    return `${item.name}|${item.unit ?? ''}`;
  }

  isChecked(item: ShoppingListItem): boolean {
    return this.checkedKeys().has(this.itemKey(item));
  }

  toggleCheck(item: ShoppingListItem): void {
    const key = this.itemKey(item);
    this.checkedKeys.update((set) => {
      const next = new Set(set);
      if (next.has(key)) next.delete(key);
      else next.add(key);
      return next;
    });
    this.persistChecks();
  }

  clearChecks(): void {
    this.checkedKeys.set(new Set());
    this.persistChecks();
  }

  loadList(): void {
    this.loading.set(true);
    this.error.set(null);
    this.restoreChecks();
    this.mealPlan.getShoppingList(this.fromDate, this.toDate).subscribe({
      next: (list) => {
        this.items.set(list);
        this.loaded.set(true);
        this.loading.set(false);
      },
      error: (err) => {
        this.error.set(extractApiError(err, this.translate.instant('errors.loadShoppingListFailed')));
        this.loading.set(false);
      },
    });
  }

  private storageKey(): string {
    return `${CHECKLIST_KEY}_${this.rangeKey()}`;
  }

  private restoreChecks(): void {
    try {
      const raw = localStorage.getItem(this.storageKey());
      if (!raw) {
        this.checkedKeys.set(new Set());
        return;
      }
      const parsed = JSON.parse(raw) as string[];
      this.checkedKeys.set(new Set(parsed));
    } catch {
      this.checkedKeys.set(new Set());
    }
  }

  private persistChecks(): void {
    localStorage.setItem(this.storageKey(), JSON.stringify([...this.checkedKeys()]));
  }
}
