import { useMemo, useState } from "react";
import { useTranslation } from "react-i18next";
import { Link } from "react-router-dom";
import { CheckCircle2, Loader2, RefreshCw, Sparkles, Trash2 } from "lucide-react";
import {
  commitRecipes,
  createRecipeSession,
  generateRecipeDrafts,
  regenerateRecipePart,
  removeRecipeDraft,
} from "@/api/recipe-generator.api";
import { extractApiError } from "@/api/axiosInstance";
import { useMealCategoryLabels } from "@/i18n/useMealCategoryLabel";
import { MealCategory } from "@/types/recipe.types";
import type { CommitRecipeResult, GeneratedRecipeDraft, RecipeGeneratorConstraints } from "@/types/generator.types";

type Step = "constraints" | "review" | "done";

export function RecipeGeneratorPage() {
  const { t } = useTranslation();
  const categoryLabels = useMealCategoryLabels();
  const [step, setStep] = useState<Step>("constraints");
  const [sessionId, setSessionId] = useState<number | null>(null);
  const [drafts, setDrafts] = useState<GeneratedRecipeDraft[]>([]);
  const [selectedIds, setSelectedIds] = useState<Set<string>>(new Set());
  const [savedRecipes, setSavedRecipes] = useState<CommitRecipeResult[]>([]);
  const [recipeCount, setRecipeCount] = useState(3);
  const [pending, setPending] = useState(false);
  const [error, setError] = useState<string | null>(null);

  const [constraints, setConstraints] = useState<RecipeGeneratorConstraints>({
    prompt: "",
    mealCategory: MealCategory.Breakfast,
    targetCalories: null,
    calorieToleranceKcal: 10,
    maxPrepTimeMinutes: 30,
    cuisineStyle: "",
    dietStyle: "",
    exclusions: "",
  });

  const calorieTolerance = constraints.calorieToleranceKcal ?? 10;

  function isWithinCalorieTarget(calories?: number | null): boolean {
    if (!constraints.targetCalories || calories == null) return true;
    return Math.abs(calories - constraints.targetCalories) <= calorieTolerance;
  }

  const allSelected = useMemo(
    () => drafts.length > 0 && drafts.every((d) => selectedIds.has(d.draftId)),
    [drafts, selectedIds],
  );

  function syncDrafts(next: GeneratedRecipeDraft[]) {
    setDrafts(next);
    setSelectedIds(new Set(next.map((d) => d.draftId)));
  }

  const runGenerate = async () => {
    setError(null);
    setPending(true);
    try {
      const session = sessionId
        ? await generateRecipeDrafts(sessionId, recipeCount)
        : await (async () => {
            const created = await createRecipeSession(constraints);
            setSessionId(created.id);
            return generateRecipeDrafts(created.id, recipeCount);
          })();

      if (!sessionId) setSessionId(session.id);
      syncDrafts(session.drafts ?? []);
      setStep("review");
    } catch (e) {
      setError(extractApiError(e, t("generators.recipe.error")));
    } finally {
      setPending(false);
    }
  };

  const regen = async (draftId: string, mode: "ingredients" | "steps" | "full") => {
    if (!sessionId) return;
    setPending(true);
    setError(null);
    try {
      const session = await regenerateRecipePart(sessionId, draftId, mode, constraints.prompt);
      syncDrafts(session.drafts ?? []);
    } catch (e) {
      setError(extractApiError(e, t("generators.recipe.error")));
    } finally {
      setPending(false);
    }
  };

  const removeDraft = async (draftId: string) => {
    if (!sessionId) return;
    setPending(true);
    setError(null);
    try {
      const session = await removeRecipeDraft(sessionId, draftId);
      const next = session.drafts ?? [];
      syncDrafts(next);
      if (next.length === 0) setStep("constraints");
    } catch (e) {
      setError(extractApiError(e, t("generators.recipe.error")));
    } finally {
      setPending(false);
    }
  };

  const saveSelected = async () => {
    if (!sessionId || selectedIds.size === 0) return;
    setPending(true);
    setError(null);
    try {
      const result = await commitRecipes(sessionId, [...selectedIds]);
      setSavedRecipes(result.saved);
      const remaining = drafts.filter((d) => !selectedIds.has(d.draftId));
      if (remaining.length === 0) {
        setStep("done");
      } else {
        syncDrafts(remaining);
      }
    } catch (e) {
      setError(extractApiError(e, t("generators.recipe.error")));
    } finally {
      setPending(false);
    }
  };

  const toggleSelected = (draftId: string) => {
    setSelectedIds((prev) => {
      const next = new Set(prev);
      if (next.has(draftId)) next.delete(draftId);
      else next.add(draftId);
      return next;
    });
  };

  const toggleAll = () => {
    setSelectedIds(allSelected ? new Set() : new Set(drafts.map((d) => d.draftId)));
  };

  return (
    <div className="space-y-6">
      <header>
        <h1 className="flex items-center gap-2 text-2xl font-extrabold sm:text-3xl">
          <Sparkles className="h-7 w-7 text-brand-600" />
          {t("generators.recipe.title")}
        </h1>
        <p className="mt-1 text-slate-500">{t("generators.recipe.subtitle")}</p>
      </header>

      {error ? (
        <div role="alert" className="rounded-xl bg-red-50 p-3 text-sm text-red-700 dark:bg-red-950/40 dark:text-red-300">
          {error}
        </div>
      ) : null}

      {step === "constraints" ? (
        <section className="card space-y-4 p-6">
          <h2 className="text-lg font-bold">{t("generators.recipe.constraintsTitle")}</h2>
          <label className="block text-sm">
            {t("generators.recipe.prompt")}
            <textarea className="input mt-1 w-full" rows={3} value={constraints.prompt}
              placeholder={t("generators.recipe.promptPlaceholder")}
              onChange={(e) => setConstraints({ ...constraints, prompt: e.target.value })} />
          </label>
          <label className="block text-sm">
            {t("generators.recipe.targetCalories")}
            <input type="number" min={50} max={3000} className="input mt-1 w-full"
              value={constraints.targetCalories ?? ""}
              placeholder={t("generators.recipe.targetCaloriesOptional")}
              onChange={(e) => setConstraints({
                ...constraints,
                targetCalories: e.target.value ? Number(e.target.value) : null,
              })} />
            <span className="mt-1 block text-xs text-slate-500">{t("generators.recipe.targetCaloriesHint")}</span>
          </label>
          <label className="block text-sm">
            {t("generators.recipe.recipeCount")}
            <input type="number" min={1} max={8} className="input mt-1 w-full" value={recipeCount}
              onChange={(e) => setRecipeCount(Math.min(8, Math.max(1, Number(e.target.value) || 1)))} />
          </label>
          <label className="block text-sm">
            {t("common.category")}
            <select className="select mt-1 w-full" value={constraints.mealCategory}
              onChange={(e) => setConstraints({ ...constraints, mealCategory: Number(e.target.value) })}>
              {[MealCategory.Breakfast, MealCategory.SecondBreakfast, MealCategory.Lunch, MealCategory.Dinner].map((cat) => (
                <option key={cat} value={cat}>{categoryLabels[cat]}</option>
              ))}
            </select>
          </label>
          <label className="block text-sm">
            {t("generators.recipe.maxPrep")}
            <input type="number" className="input mt-1 w-full" value={constraints.maxPrepTimeMinutes ?? ""}
              onChange={(e) => setConstraints({ ...constraints, maxPrepTimeMinutes: Number(e.target.value) })} />
          </label>
          <label className="block text-sm">
            {t("generators.recipe.exclusions")}
            <input className="input mt-1 w-full" value={constraints.exclusions ?? ""}
              onChange={(e) => setConstraints({ ...constraints, exclusions: e.target.value })} />
          </label>
          <button type="button" className="btn-primary" disabled={pending || !constraints.prompt.trim()}
            onClick={() => void runGenerate()}>
            {pending ? <Loader2 className="h-4 w-4 animate-spin" /> : null}
            {t("generators.recipe.generate")}
          </button>
        </section>
      ) : null}

      {step === "review" && drafts.length > 0 ? (
        <section className="space-y-4">
          <div className="flex flex-wrap items-center justify-between gap-2">
            <p className="text-sm text-slate-500">{t("generators.recipe.reviewHint", { count: drafts.length })}</p>
            <label className="flex items-center gap-2 text-sm">
              <input type="checkbox" checked={allSelected} onChange={toggleAll} />
              {t("generators.recipe.selectAll")}
            </label>
          </div>

          {drafts.map((draft) => (
            <div key={draft.draftId} className="card space-y-3 p-6">
              <div className="flex flex-wrap items-start justify-between gap-3">
                <label className="flex items-start gap-2">
                  <input
                    type="checkbox"
                    className="mt-1"
                    checked={selectedIds.has(draft.draftId)}
                    onChange={() => toggleSelected(draft.draftId)}
                  />
                  <div>
                    <h2 className="text-xl font-bold">{draft.name}</h2>
                    {draft.calories != null ? (
                      <p className={`text-sm ${constraints.targetCalories && !isWithinCalorieTarget(draft.calories) ? "text-amber-700" : "text-slate-500"}`}>
                        {constraints.targetCalories
                          ? t("generators.recipe.caloriesWithTarget", {
                              actual: draft.calories,
                              target: constraints.targetCalories,
                            })
                          : `${draft.calories} kcal`}
                        {" · "}
                        P {draft.protein ?? 0}g · F {draft.fat ?? 0}g · C {draft.carbs ?? 0}g
                      </p>
                    ) : null}
                  </div>
                </label>
                <button type="button" className="btn-secondary !px-2 !py-1 text-xs" disabled={pending}
                  onClick={() => void removeDraft(draft.draftId)}>
                  <Trash2 className="h-3 w-3" /> {t("generators.recipe.remove")}
                </button>
              </div>

              {draft.unlinkedIngredientCount > 0 ? (
                <p className="text-sm text-amber-700">{t("manage.unlinkedIngredientsWarning", { count: draft.unlinkedIngredientCount })}</p>
              ) : null}

              <h3 className="font-semibold">{t("recipes.ingredients")}</h3>
              <ul className="space-y-1 text-sm">
                {draft.ingredients.map((ing, i) => (
                  <li key={i} className={!ing.isLinked && ing.amountGrams ? "text-amber-700" : ""}>
                    {ing.name} — {ing.amountGrams ?? "?"}g {ing.unit ?? ""}
                  </li>
                ))}
              </ul>
              <h3 className="font-semibold">{t("manage.preparationSteps")}</h3>
              <ol className="list-decimal space-y-1 pl-5 text-sm">
                {draft.steps.map((s) => (
                  <li key={s.stepNumber}>{s.description}</li>
                ))}
              </ol>

              <div className="flex flex-wrap gap-2">
                <button type="button" className="btn-secondary !px-2 !py-1 text-xs" disabled={pending}
                  onClick={() => void regen(draft.draftId, "ingredients")}>
                  <RefreshCw className="h-3 w-3" /> {t("generators.recipe.regenIngredients")}
                </button>
                <button type="button" className="btn-secondary !px-2 !py-1 text-xs" disabled={pending}
                  onClick={() => void regen(draft.draftId, "steps")}>
                  {t("generators.recipe.regenSteps")}
                </button>
                <button type="button" className="btn-secondary !px-2 !py-1 text-xs" disabled={pending}
                  onClick={() => void regen(draft.draftId, "full")}>
                  {t("generators.recipe.regenFull")}
                </button>
              </div>
            </div>
          ))}

          <div className="flex flex-wrap gap-2">
            <button type="button" className="btn-secondary" onClick={() => setStep("constraints")}>
              {t("common.back")}
            </button>
            <button type="button" className="btn-primary" disabled={pending || selectedIds.size === 0}
              onClick={() => void saveSelected()}>
              {t("generators.recipe.saveSelected", { count: selectedIds.size })}
            </button>
          </div>
        </section>
      ) : null}

      {step === "done" && savedRecipes.length > 0 ? (
        <div className="card space-y-3 p-6">
          <div className="flex items-center gap-3">
            <CheckCircle2 className="h-6 w-6 text-brand-600" />
            <p className="font-semibold">{t("generators.recipe.doneMultiple", { count: savedRecipes.length })}</p>
          </div>
          <ul className="space-y-2">
            {savedRecipes.map((r) => (
              <li key={r.recipeId}>
                <Link to={`/recipes/${r.recipeId}`} className="text-brand-600 hover:underline">
                  {r.recipeName}
                </Link>
              </li>
            ))}
          </ul>
          <button type="button" className="btn-secondary" onClick={() => {
            setStep("constraints");
            setDrafts([]);
            setSelectedIds(new Set());
            setSavedRecipes([]);
            setSessionId(null);
          }}>
            {t("generators.recipe.generateMore")}
          </button>
        </div>
      ) : null}
    </div>
  );
}
