import { Component, Input, OnDestroy, effect, 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 {
  buildShoppingList,
  formatBreakdown,
  formatQuantity,
  generatePdf,
  ShoppingItem,
} from '../../core/utils/pdf-export.util';
import { formatIngredientAmount } from '../../core/utils/ingredient-quantity.util';
import { extractApiError } from '../../core/utils/api-error.util';

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

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-pdf-generator',
  standalone: true,
  imports: [TranslatePipe],
  template: `
    <button
      type="button"
      (click)="handleGenerate()"
      [disabled]="disabled || selectedIds.length === 0 || phase() !== 'idle'"
      class="btn-primary"
    >
      @if (phase() !== 'idle') {
        <span class="inline-block h-4 w-4 animate-spin rounded-full border-2 border-white border-t-transparent"></span>
      } @else {
        ↓
      }
      {{
        phase() === 'loading'
          ? ('pdf.preparing' | translate)
          : phase() === 'rendering'
            ? ('pdf.generating' | translate)
            : ('pdf.generate' | translate)
      }}
    </button>

    @if (error()) {
      <p class="mt-2 text-sm text-red-600 dark:text-red-400">{{ error() }}</p>
    }

    @if (phase() === 'rendering') {
      <div id="pdf-render-area">
        @for (recipe of recipes(); track recipe.id) {
          <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(recipe.mealCategory) }}
                </span>
                <h1 style="font-size: 28px; font-weight: 800; margin: 12px 0 0">{{ recipe.name }}</h1>
                @if (recipe.prepTimeMinutes != null) {
                  <p style="color: #64748b; margin: 6px 0 0; font-size: 14px">
                    {{ 'pdf.prepTime' | translate: { count: recipe.prepTimeMinutes } }}
                  </p>
                }
              </div>

              <div style="display: flex; gap: 12px; margin-bottom: 28px">
                @for (macro of macros(recipe); track macro.label) {
                  <div
                    style="
                      flex: 1;
                      border: 1px solid #e2e8f0;
                      border-radius: 12px;
                      padding: 12px;
                      text-align: center;
                    "
                  >
                    <div style="font-size: 20px; font-weight: 800">
                      {{ macro.value != null ? macro.value + ' ' + macro.suffix : '—' }}
                    </div>
                    <div
                      style="
                        font-size: 11px;
                        text-transform: uppercase;
                        color: #64748b;
                        margin-top: 2px;
                      "
                    >
                      {{ macro.label }}
                    </div>
                  </div>
                }
              </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 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 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">
                {{ generatedOnLabel() }}
              </p>
            </div>

            <ul style="flex: 1; margin: 0; padding: 0; list-style: none">
              @for (item of shoppingList(); track itemKey(item)) {
                <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; color: #0f172a">— {{ quantityLabel(item) }}</span>
                  @if (breakdownLabel(item); as breakdown) {
                    <span style="color: #94a3b8; font-size: 12px">({{ breakdown }})</span>
                  }
                </li>
              }
            </ul>

            <div style="margin-top: 32px; border-top: 1px solid #e2e8f0; padding-top: 16px">
              <h3
                style="
                  font-size: 13px;
                  font-weight: 700;
                  text-transform: uppercase;
                  color: #64748b;
                  margin: 0 0 10px;
                "
              >
                {{ 'pdf.recipesInExport' | translate }}
              </h3>
              <ol style="margin: 0; padding-left: 20px; font-size: 12px; line-height: 1.7; color: #475569">
                @for (r of recipes(); track r.id) {
                  <li>
                    {{ r.name }} — {{ categoryLabel(r.mealCategory) }}
                    @if (r.calories != null) {
                      · {{ r.calories }} kcal
                    }
                  </li>
                }
              </ol>
            </div>
          </div>
        </div>
      </div>
    }
  `,
})
export class PdfGeneratorComponent implements OnDestroy {
  private readonly recipeService = inject(RecipeService);
  private readonly translate = inject(TranslateService);
  private renderCancelled = false;

  @Input() selectedIds: number[] = [];
  @Input() disabled = false;

  readonly phase = signal<Phase>('idle');
  readonly recipes = signal<RecipeDetail[]>([]);
  readonly error = signal<string | null>(null);
  readonly pageStyle = PAGE_STYLE;
  readonly formatIngredientAmount = formatIngredientAmount;

  readonly shoppingList = signal<ShoppingItem[]>([]);
  private generatedOn = '';

  constructor() {
    effect(() => {
      if (this.phase() === 'rendering' && this.recipes().length > 0) {
        void this.runPdfGeneration();
      }
    });
  }

  ngOnDestroy(): void {
    this.renderCancelled = true;
  }

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

  macros(recipe: RecipeDetail) {
    return [
      { label: this.translate.instant('recipes.calories'), value: recipe.calories, suffix: 'kcal' },
      { label: this.translate.instant('recipes.protein'), value: recipe.protein, suffix: 'g' },
      { label: this.translate.instant('recipes.fat'), value: recipe.fat, suffix: 'g' },
      { label: this.translate.instant('recipes.carbs'), value: recipe.carbs, suffix: 'g' },
    ];
  }

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

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

  itemKey(item: ShoppingItem): string {
    return `${item.name}-${item.unit ?? 'g'}-${item.quantified}`;
  }

  generatedOnLabel(): string {
    const count = this.recipes().length;
    const lang = this.translate.getCurrentLang() ?? this.translate.getFallbackLang() ?? 'en';
    let suffix: string;
    if (lang.startsWith('pl')) {
      const mod10 = count % 10;
      const mod100 = count % 100;
      if (count === 1) suffix = 'one';
      else if (mod10 >= 2 && mod10 <= 4 && (mod100 < 12 || mod100 > 14)) suffix = 'few';
      else suffix = 'many';
    } else {
      suffix = count === 1 ? 'one' : 'other';
    }
    return this.translate.instant(`pdf.generatedOn_${suffix}`, {
      date: this.generatedOn,
      count,
    });
  }

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

    forkJoin(this.selectedIds.map((id) => this.recipeService.getRecipeById(id))).subscribe({
      next: (details) => {
        this.generatedOn = new Date().toLocaleDateString(
          this.translate.getCurrentLang() ?? 'en', {
          year: 'numeric',
          month: 'long',
          day: 'numeric',
        });
        this.shoppingList.set(buildShoppingList(details));
        this.recipes.set(details);
        this.phase.set('rendering');
      },
      error: (err) => {
        this.error.set(extractApiError(err, this.translate.instant('errors.pdfLoadFailed')));
        this.phase.set('idle');
      },
    });
  }

  private async runPdfGeneration(): Promise<void> {
    this.renderCancelled = false;
    await document.fonts?.ready?.catch(() => undefined);
    await new Promise((r) => requestAnimationFrame(() => requestAnimationFrame(r)));
    if (this.renderCancelled) return;

    try {
      await generatePdf(this.translate, 'dailymeals-plan.pdf');
    } catch (err) {
      this.error.set(extractApiError(err, this.translate.instant('errors.pdfGenerateFailed')));
    } finally {
      if (!this.renderCancelled) {
        this.phase.set('idle');
        this.recipes.set([]);
        this.shoppingList.set([]);
      }
    }
  }
}
