import { Component, Input, inject, signal } from '@angular/core';
import { TranslatePipe, TranslateService } from '@ngx-translate/core';
import { forkJoin } from 'rxjs';
import { RecipeService } from '../../core/services/recipe.service';
import {
  MealCategory,
  MEAL_CATEGORY_I18N_KEYS,
  RecipeDetail,
} from '../../core/models/recipe.models';
import { MealPlanEntry } from '../../core/models/meal-plan.models';
import {
  buildShoppingList,
  formatBreakdown,
  formatQuantity,
  generatePdf,
  scaleRecipeDetail,
  ShoppingItem,
} from '../../core/utils/pdf-export.util';
import { formatIngredientAmount } from '../../core/utils/ingredient-quantity.util';
import { extractApiError } from '../../core/utils/api-error.util';

const PLANNER_CATEGORIES = [
  MealCategory.Breakfast,
  MealCategory.SecondBreakfast,
  MealCategory.Lunch,
  MealCategory.Dinner,
] as const;

type Phase = 'idle' | 'loading' | 'rendering';

interface ExportRecipe {
  recipe: RecipeDetail;
  slotLabel: string;
  portions: number;
}

const PAGE_STYLE: Record<string, string> = {
  width: '794px',
  minHeight: '1123px',
  boxSizing: 'border-box',
  padding: '48px',
  fontFamily: 'Inter, Arial, sans-serif',
  color: '#0f172a',
  background: '#ffffff',
};

@Component({
  selector: 'app-meal-plan-day-pdf-export',
  standalone: true,
  imports: [TranslatePipe],
  template: `
    <button
      type="button"
      class="text-xs font-semibold text-brand-600 hover:underline disabled:opacity-50"
      [disabled]="phase() !== 'idle'"
      [title]="'mealPlanner.exportDay' | translate"
      (click)="handleGenerate()"
    >
      @if (phase() !== 'idle') {
        …
      } @else {
        PDF
      }
    </button>

    @if (error()) {
      <p class="mt-1 text-xs text-red-600">{{ error() }}</p>
    }

    @if (phase() === 'rendering') {
      <div [id]="renderAreaId">
        <div class="pdf-page" [style]="pageStyle">
          <div>
            <div style="border-bottom: 3px solid #16774c; padding-bottom: 16px; margin-bottom: 24px">
              <h1 style="font-size: 28px; font-weight: 800; margin: 0">
                {{ 'pdf.dayPlanTitle' | translate: { date: dateLabel() } }}
              </h1>
            </div>
            <ul style="margin: 0; padding: 0; list-style: none">
              @for (slot of overviewSlots(); track slot.label) {
                <li style="display: flex; justify-content: space-between; padding: 10px 0; border-bottom: 1px solid #f1f5f9; font-size: 14px">
                  <span style="font-weight: 700; color: #475569">{{ slot.label }}</span>
                  <span>
                    @if (slot.recipeName) {
                      {{ slot.recipeName }} ({{ slot.portions }}×)
                    } @else {
                      {{ 'pdf.emptySlot' | translate }}
                    }
                  </span>
                </li>
              }
            </ul>
          </div>
        </div>

        @for (item of exportRecipes(); track item.recipe.id + item.slotLabel) {
          <div class="pdf-page" [style]="pageStyle">
            <div>
              <div style="border-bottom: 3px solid #16774c; padding-bottom: 16px; margin-bottom: 24px">
                <span style="display: inline-block; background: #d6f1e0; color: #125f3f; border-radius: 999px; padding: 4px 12px; font-size: 12px; font-weight: 700">
                  {{ categoryLabel(item.recipe.mealCategory) }}
                </span>
                <h1 style="font-size: 28px; font-weight: 800; margin: 12px 0 0">{{ item.recipe.name }}</h1>
                <p style="color: #64748b; margin: 6px 0 0; font-size: 14px">
                  {{ 'pdf.plannedMealMeta' | translate: { slot: item.slotLabel, portions: item.portions } }}
                </p>
              </div>
              <h2 style="font-size: 18px; font-weight: 700; margin: 0 0 12px">{{ 'recipes.ingredients' | translate }}</h2>
              <ul style="margin: 0 0 28px; padding: 0; list-style: none">
                @for (ing of item.recipe.ingredients; track ing.id) {
                  <li style="display: flex; justify-content: space-between; padding: 7px 0; border-bottom: 1px solid #f1f5f9; font-size: 14px">
                    <span>{{ ing.name }}</span>
                    <span style="color: #64748b">{{ formatIngredientAmount(ing.amountGrams, ing.unit) }}</span>
                  </li>
                }
              </ul>
              <h2 style="font-size: 18px; font-weight: 700; margin: 0 0 12px">{{ 'recipes.preparation' | translate }}</h2>
              <ol style="margin: 0; padding-left: 20px; font-size: 14px; line-height: 1.6">
                @for (step of item.recipe.steps; track step.id) {
                  <li style="margin-bottom: 8px">{{ step.description }}</li>
                }
              </ol>
            </div>
          </div>
        }

        <div class="pdf-page" [style]="pageStyle">
          <div style="display: flex; flex-direction: column; min-height: 1027px">
            <div style="border-bottom: 3px solid #16774c; padding-bottom: 16px; margin-bottom: 24px">
              <h1 style="font-size: 28px; font-weight: 800; margin: 0">{{ 'pdf.shoppingList' | translate }}</h1>
              <p style="color: #64748b; margin: 6px 0 0; font-size: 14px">
                {{ 'pdf.dayShoppingSubtitle' | translate: { date: dateLabel(), count: exportRecipes().length } }}
              </p>
            </div>
            @if (shoppingList().length === 0) {
              <p style="color: #94a3b8; font-size: 14px">{{ 'pdf.emptyShoppingList' | translate }}</p>
            } @else {
              <ul style="flex: 1; margin: 0; padding: 0; list-style: none">
                @for (item of shoppingList(); track item.name + (item.unit ?? 'g')) {
                  <li style="display: flex; align-items: baseline; padding: 8px 0; border-bottom: 1px solid #f1f5f9; font-size: 14px">
                    <span style="flex: 0 0 240px; font-weight: 600">{{ item.name }}</span>
                    <span style="flex: 0 0 110px">— {{ formatQty(item) }}</span>
                    @if (formatBreak(item); as breakdown) {
                      <span style="color: #94a3b8; font-size: 12px">({{ breakdown }})</span>
                    }
                  </li>
                }
              </ul>
            }
          </div>
        </div>
      </div>
    }
  `,
})
export class MealPlanDayPdfExportComponent {
  private readonly recipes = inject(RecipeService);
  private readonly translate = inject(TranslateService);

  @Input({ required: true }) date!: string;
  @Input({ required: true }) entries: MealPlanEntry[] = [];

  readonly pageStyle = PAGE_STYLE;
  readonly phase = signal<Phase>('idle');
  readonly error = signal<string | null>(null);
  readonly exportRecipes = signal<ExportRecipe[]>([]);
  readonly shoppingList = signal<ShoppingItem[]>([]);
  readonly dateLabel = signal('');
  readonly overviewSlots = signal<Array<{ label: string; recipeName: string | null; portions: number | null }>>([]);

  get renderAreaId(): string {
    return `pdf-render-area-${this.date}`;
  }

  categoryLabel(cat: MealCategory): string {
    return this.translate.instant(MEAL_CATEGORY_I18N_KEYS[cat]);
  }

  formatQty(item: ShoppingItem): string {
    return formatQuantity(item, this.translate.instant('pdf.toTaste'));
  }

  formatBreak(item: ShoppingItem): string | null {
    return formatBreakdown(item);
  }

  readonly formatIngredientAmount = formatIngredientAmount;

  handleGenerate(): void {
    if (this.phase() !== 'idle') return;
    this.error.set(null);
    this.phase.set('loading');

    const dayEntries = this.entries
      .filter((e) => e.planDate === this.date)
      .sort((a, b) => a.mealCategory - b.mealCategory || a.id - b.id);

    this.dateLabel.set(
      new Date(`${this.date}T12:00:00`).toLocaleDateString(undefined, {
        weekday: 'short',
        month: 'short',
        day: 'numeric',
      }),
    );

    this.overviewSlots.set(
      PLANNER_CATEGORIES.map((cat) => {
        const first = dayEntries.find((e) => e.mealCategory === cat);
        return {
          label: this.categoryLabel(cat),
          recipeName: first?.recipeName ?? null,
          portions: first?.portions ?? null,
        };
      }),
    );

    if (dayEntries.length === 0) {
      this.exportRecipes.set([]);
      this.shoppingList.set([]);
      this.phase.set('rendering');
      void this.runPdf();
      return;
    }

    forkJoin(dayEntries.map((entry) => this.recipes.getRecipeById(entry.recipeId))).subscribe({
      next: (details) => {
        const scaled = details.map((recipe, index) => {
          const entry = dayEntries[index];
          return {
            slotLabel: this.categoryLabel(entry.mealCategory as MealCategory),
            portions: entry.portions,
            recipe: scaleRecipeDetail(recipe, entry.portions),
          };
        });
        this.exportRecipes.set(scaled);
        this.shoppingList.set(buildShoppingList(scaled.map((s) => s.recipe)));
        this.phase.set('rendering');
        void this.runPdf();
      },
      error: (err) => {
        this.error.set(extractApiError(err, this.translate.instant('errors.pdfLoadFailed')));
        this.phase.set('idle');
      },
    });
  }

  private async runPdf(): Promise<void> {
    await document.fonts?.ready?.catch(() => undefined);
    await new Promise((r) => requestAnimationFrame(() => requestAnimationFrame(r)));
    try {
      const safeDate = this.date.replace(/[^\d-]/g, '');
      await generatePdf(this.translate, `dailymeals-${safeDate}.pdf`, this.renderAreaId);
    } catch (err) {
      this.error.set(extractApiError(err, this.translate.instant('errors.pdfGenerateFailed')));
    } finally {
      this.phase.set('idle');
      this.exportRecipes.set([]);
      this.shoppingList.set([]);
    }
  }
}
