import { useEffect, useMemo, useRef, useState } from "react";
import { useTranslation } from "react-i18next";
import { FileDown, Loader2 } from "lucide-react";
import { fetchRecipeById } from "@/api/recipes.api";
import { extractApiError } from "@/api/axiosInstance";
import {
  DayOverviewPdfPage,
  PDF_PAGE_STYLE,
  RecipePdfPage,
  ShoppingListPdfPage,
  buildShoppingList,
} from "@/components/pdf/pdfPageComponents";
import { generatePdf, scaleRecipeDetail } from "@/utils/pdfExport";
import { useMealCategoryLabels } from "@/i18n/useMealCategoryLabel";
import type { MealPlanEntry } from "@/types/meal-plan.types";
import { MealCategory } from "@/types/recipe.types";
import { formatDisplayDate } from "@/utils/date.util";

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

interface MealPlanDayPdfExportProps {
  date: string;
  entries: MealPlanEntry[];
  className?: string;
}

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

interface ExportRecipe {
  recipe: ReturnType<typeof scaleRecipeDetail>;
  slotLabel: string;
  portions: number;
}

export function MealPlanDayPdfExport({ date, entries, className }: MealPlanDayPdfExportProps) {
  const { t, i18n } = useTranslation();
  const categoryLabels = useMealCategoryLabels();
  const [phase, setPhase] = useState<Phase>("idle");
  const [exportRecipes, setExportRecipes] = useState<ExportRecipe[]>([]);
  const [error, setError] = useState<string | null>(null);
  const renderAreaRef = useRef<HTMLDivElement | null>(null);

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

  const overviewSlots = useMemo(
    () =>
      PLANNER_CATEGORIES.map((cat) => {
        const slotEntries = dayEntries.filter((e) => e.mealCategory === cat);
        const first = slotEntries[0];
        return {
          label: categoryLabels[cat],
          recipeName: first?.recipeName ?? null,
          portions: first?.portions ?? null,
        };
      }),
    [dayEntries, categoryLabels],
  );

  const renderAreaId = `pdf-render-area-${date}`;

  async function handleGenerate() {
    if (phase !== "idle") return;
    setError(null);
    setPhase("loading");
    try {
      if (dayEntries.length === 0) {
        setExportRecipes([]);
        setPhase("rendering");
        return;
      }

      const details = await Promise.all(dayEntries.map((entry) => fetchRecipeById(entry.recipeId)));
      setExportRecipes(
        details.map((recipe, index) => {
          const entry = dayEntries[index];
          const slotLabel = categoryLabels[entry.mealCategory as MealCategory];
          return {
            slotLabel,
            portions: entry.portions,
            recipe: scaleRecipeDetail(recipe, entry.portions),
          };
        }),
      );
      setPhase("rendering");
    } catch (err) {
      setError(extractApiError(err, t("errors.pdfLoadFailed")));
      setPhase("idle");
    }
  }

  useEffect(() => {
    if (phase !== "rendering") return;

    let cancelled = false;
    const run = async () => {
      await document.fonts?.ready?.catch(() => undefined);
      await new Promise((r) => requestAnimationFrame(() => requestAnimationFrame(r)));
      if (cancelled) return;
      try {
        const safeDate = date.replace(/[^\d-]/g, "");
        await generatePdf(`dailymeals-${safeDate}.pdf`, renderAreaId);
      } catch (err) {
        setError(extractApiError(err, t("errors.pdfGenerateFailed")));
      } finally {
        if (!cancelled) {
          setPhase("idle");
          setExportRecipes([]);
        }
      }
    };
    void run();
    return () => {
      cancelled = true;
    };
  }, [phase, date, t]);

  const scaledRecipes = exportRecipes.map((item) => item.recipe);
  const shoppingList = scaledRecipes.length > 0 ? buildShoppingList(scaledRecipes) : [];
  const dateLabel = formatDisplayDate(date, i18n.language);
  const generatedOn = new Date().toLocaleDateString(i18n.language, {
    year: "numeric",
    month: "long",
    day: "numeric",
  });

  return (
    <>
      <button
        type="button"
        onClick={() => void handleGenerate()}
        disabled={phase !== "idle"}
        className={className ?? "text-xs font-semibold text-brand-600 hover:underline disabled:opacity-50"}
        title={t("mealPlanner.exportDay")}
      >
        {phase !== "idle" ? <Loader2 className="inline h-3 w-3 animate-spin" /> : <FileDown className="inline h-3 w-3" />}
        <span className="sr-only">{t("mealPlanner.exportDay")}</span>
        PDF
      </button>

      {error && <p className="mt-1 text-xs text-red-600 dark:text-red-400">{error}</p>}

      {phase === "rendering" && (
        <div id={renderAreaId} ref={renderAreaRef}>
          <div className="pdf-page" style={PDF_PAGE_STYLE}>
            <DayOverviewPdfPage dateLabel={dateLabel} slots={overviewSlots} t={t} />
          </div>
          {exportRecipes.map(({ recipe, slotLabel, portions }) => (
            <div className="pdf-page" style={PDF_PAGE_STYLE} key={`${recipe.id}-${slotLabel}`}>
              <RecipePdfPage
                recipe={recipe}
                categoryLabels={categoryLabels}
                t={t}
                subtitle={t("pdf.plannedMealMeta", { slot: slotLabel, portions })}
              />
            </div>
          ))}
          <div className="pdf-page" style={PDF_PAGE_STYLE}>
            <ShoppingListPdfPage
              items={shoppingList}
              recipes={scaledRecipes}
              generatedOn={generatedOn}
              categoryLabels={categoryLabels}
              t={t}
              subtitle={t("pdf.dayShoppingSubtitle", { date: dateLabel, count: scaledRecipes.length })}
            />
          </div>
        </div>
      )}
    </>
  );
}
