import { useMemo, useState } from "react";
import { useQuery, useQueryClient } from "@tanstack/react-query";
import { useTranslation } from "react-i18next";
import { Link, useNavigate } from "react-router-dom";
import { CheckCircle2, Eye, Loader2, RefreshCw, Sparkles } from "lucide-react";
import {
  acceptDietMacros,
  commitDietPlan,
  createDietSession,
  fetchDietSession,
  generateDietPlan,
  proposeDietMacros,
  regenerateDietMeal,
  saveDietProfile,
  toggleDietMealLock,
  fetchDietProfile,
} from "@/api/diet-generator.api";
import { extractApiError } from "@/api/axiosInstance";
import { DietMealPreviewModal } from "@/components/recipes/DietMealPreviewModal";
import { useMealCategoryLabels } from "@/i18n/useMealCategoryLabel";
import type { DietGeneratorDraftMeal, DietGeneratorSession, DietUserProfile } from "@/types/generator.types";
import { MealCategory } from "@/types/recipe.types";

type Step = "profile" | "macros" | "plan" | "done";

function formatDraftMealMacros(meal: DietGeneratorDraftMeal): string {
  const parts = [`${meal.calories ?? "?"} kcal`];
  if (meal.proteinG != null) parts.push(`P ${meal.proteinG}g`);
  if (meal.fatG != null) parts.push(`F ${meal.fatG}g`);
  if (meal.carbsG != null) parts.push(`C ${meal.carbsG}g`);
  return parts.join(" · ");
}

function isNoAlternativeMealsError(error: unknown): boolean {
  if (typeof error !== "object" || error === null || !("response" in error)) return false;
  const response = (error as { response?: { status?: number } }).response;
  return response?.status === 400;
}

const defaultProfile: DietUserProfile = {
  heightCm: 175,
  weightKg: 75,
  age: 30,
  sex: "male",
  activityLevel: "moderate",
  goal: "maintain",
  mealsPerDayMask: 15,
  allergiesNotes: "",
  dislikedFoods: "",
};

export function DietGeneratorPage() {
  const { t } = useTranslation();
  const navigate = useNavigate();
  const queryClient = useQueryClient();
  const categoryLabels = useMealCategoryLabels();
  const [step, setStep] = useState<Step>("profile");
  const [profile, setProfile] = useState<DietUserProfile>(defaultProfile);
  const [sessionId, setSessionId] = useState<number | null>(null);
  const [macros, setMacros] = useState({ calories: 2000, proteinG: 150, fatG: 65, carbsG: 200, rationale: "" });
  const [session, setSession] = useState<DietGeneratorSession | null>(null);
  const [commitResult, setCommitResult] = useState<string | null>(null);
  const [error, setError] = useState<string | null>(null);
  const [info, setInfo] = useState<string | null>(null);
  const [loading, setLoading] = useState(false);
  const [previewMeal, setPreviewMeal] = useState<DietGeneratorDraftMeal | null>(null);

  useQuery({
    queryKey: ["diet-generator-profile"],
    queryFn: async () => {
      const p = await fetchDietProfile();
      if (p) setProfile({ ...defaultProfile, ...p });
      return p;
    },
  });

  const refreshSession = async (id: number) => {
    const data = await fetchDietSession(id);
    setSession(data);
    return data;
  };

  const startSession = async () => {
    setError(null);
    setLoading(true);
    try {
      await saveDietProfile(profile);
      const session = await createDietSession({ planDayCount: 7, calorieToleranceKcal: 10 });
      setSessionId(session.id);
      if (session.proposedMacros) {
        setMacros({
          calories: session.proposedMacros.calories,
          proteinG: session.proposedMacros.proteinG,
          fatG: session.proposedMacros.fatG,
          carbsG: session.proposedMacros.carbsG,
          rationale: session.proposedMacros.rationale ?? "",
        });
      }
      const refined = await proposeDietMacros(session.id);
      if (refined.proposedMacros) {
        setMacros({
          calories: refined.proposedMacros.calories,
          proteinG: refined.proposedMacros.proteinG,
          fatG: refined.proposedMacros.fatG,
          carbsG: refined.proposedMacros.carbsG,
          rationale: refined.proposedMacros.rationale ?? "",
        });
      }
      setStep("macros");
    } catch (e) {
      setError(extractApiError(e, t("generators.diet.error")));
    } finally {
      setLoading(false);
    }
  };

  const acceptAndGenerate = async () => {
    if (!sessionId) return;
    setError(null);
    setLoading(true);
    try {
      await acceptDietMacros(sessionId, macros);
      const plan = await generateDietPlan(sessionId);
      setSession(plan);
      setStep("plan");
      queryClient.invalidateQueries({ queryKey: ["meal-plan"] });
    } catch (e) {
      setError(extractApiError(e, t("generators.diet.error")));
    } finally {
      setLoading(false);
    }
  };
  const mealsByDate = useMemo(() => {
    const map = new Map<string, typeof session extends undefined ? never : NonNullable<typeof session>["draftMeals"]>();
    for (const meal of session?.draftMeals ?? []) {
      const list = map.get(meal.planDate) ?? [];
      list.push(meal);
      map.set(meal.planDate, list);
    }
    return [...map.entries()].sort(([a], [b]) => a.localeCompare(b));
  }, [session?.draftMeals]);

  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.diet.title")}
        </h1>
        <p className="mt-1 text-slate-500">{t("generators.diet.subtitle")}</p>
      </header>

      {info ? (
        <div role="status" className="rounded-xl bg-sky-50 p-3 text-sm text-sky-800 dark:bg-sky-950/40 dark:text-sky-200">
          {info}
        </div>
      ) : null}

      {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 === "profile" ? (
        <section className="card space-y-4 p-6">
          <h2 className="text-lg font-bold">{t("generators.diet.profileTitle")}</h2>
          <div className="grid gap-4 sm:grid-cols-2">
            <label className="block text-sm">
              {t("generators.diet.heightCm")}
              <input type="number" className="input mt-1 w-full" value={profile.heightCm}
                onChange={(e) => setProfile({ ...profile, heightCm: Number(e.target.value) })} />
            </label>
            <label className="block text-sm">
              {t("generators.diet.weightKg")}
              <input type="number" className="input mt-1 w-full" value={profile.weightKg}
                onChange={(e) => setProfile({ ...profile, weightKg: Number(e.target.value) })} />
            </label>
            <label className="block text-sm">
              {t("generators.diet.age")}
              <input type="number" className="input mt-1 w-full" value={profile.age}
                onChange={(e) => setProfile({ ...profile, age: Number(e.target.value) })} />
            </label>
            <label className="block text-sm">
              {t("generators.diet.sex")}
              <select className="select mt-1 w-full" value={profile.sex}
                onChange={(e) => setProfile({ ...profile, sex: e.target.value as DietUserProfile["sex"] })}>
                <option value="male">{t("generators.diet.male")}</option>
                <option value="female">{t("generators.diet.female")}</option>
              </select>
            </label>
            <label className="block text-sm sm:col-span-2">
              {t("generators.diet.activity")}
              <select className="select mt-1 w-full" value={profile.activityLevel}
                onChange={(e) => setProfile({ ...profile, activityLevel: e.target.value as DietUserProfile["activityLevel"] })}>
                <option value="sedentary">{t("generators.diet.sedentary")}</option>
                <option value="light">{t("generators.diet.light")}</option>
                <option value="moderate">{t("generators.diet.moderate")}</option>
                <option value="active">{t("generators.diet.active")}</option>
                <option value="very_active">{t("generators.diet.veryActive")}</option>
              </select>
            </label>
            <label className="block text-sm sm:col-span-2">
              {t("generators.diet.goal")}
              <select className="select mt-1 w-full" value={profile.goal}
                onChange={(e) => setProfile({ ...profile, goal: e.target.value as DietUserProfile["goal"] })}>
                <option value="lose_weight">{t("generators.diet.loseWeight")}</option>
                <option value="maintain">{t("generators.diet.maintain")}</option>
                <option value="gain_muscle">{t("generators.diet.gainMuscle")}</option>
                <option value="recomp">{t("generators.diet.recomp")}</option>
              </select>
            </label>
            <label className="block text-sm sm:col-span-2">
              {t("generators.diet.allergies")}
              <textarea className="input mt-1 w-full" rows={2} value={profile.allergiesNotes ?? ""}
                onChange={(e) => setProfile({ ...profile, allergiesNotes: e.target.value })} />
            </label>
          </div>
          <button type="button" className="btn-primary" onClick={() => void startSession()}>
            {t("generators.diet.continue")}
          </button>
        </section>
      ) : null}

      {step === "macros" ? (
        <section className="card space-y-4 p-6">
          <h2 className="text-lg font-bold">{t("generators.diet.macrosTitle")}</h2>
          {macros.rationale ? <p className="text-sm text-slate-500">{macros.rationale}</p> : null}
          <div className="grid gap-4 sm:grid-cols-2">
            <label className="block text-sm">
              {t("manage.caloriesKcal")}
              <input type="number" className="input mt-1 w-full" value={macros.calories}
                onChange={(e) => setMacros({ ...macros, calories: Number(e.target.value) })} />
            </label>
            <label className="block text-sm">
              {t("manage.proteinG")}
              <input type="number" className="input mt-1 w-full" value={macros.proteinG}
                onChange={(e) => setMacros({ ...macros, proteinG: Number(e.target.value) })} />
            </label>
            <label className="block text-sm">
              {t("manage.fatG")}
              <input type="number" className="input mt-1 w-full" value={macros.fatG}
                onChange={(e) => setMacros({ ...macros, fatG: Number(e.target.value) })} />
            </label>
            <label className="block text-sm">
              {t("manage.carbsG")}
              <input type="number" className="input mt-1 w-full" value={macros.carbsG}
                onChange={(e) => setMacros({ ...macros, carbsG: Number(e.target.value) })} />
            </label>
          </div>
          <div className="flex flex-wrap gap-2">
            <button type="button" className="btn-secondary" onClick={() => setStep("profile")}>
              {t("common.back")}
            </button>
            <button type="button" className="btn-primary" onClick={() => void acceptAndGenerate()}>
              {t("generators.diet.acceptAndGenerate")}
            </button>
          </div>
        </section>
      ) : null}

      {step === "plan" && session ? (
        <section className="space-y-4">
          <div className="card p-4">
            <p className="text-sm text-slate-500">{t("generators.diet.planHint")}</p>
          </div>
          {mealsByDate.map(([date, meals]) => {
            const summary = session.daySummaries.find((d) => d.planDate === date);
            return (
              <div key={date} className="card p-4">
                <div className="mb-3 flex flex-wrap items-center justify-between gap-2">
                  <h3 className="font-bold">{date}</h3>
                  <span className={`text-sm ${summary?.withinTolerance ? "text-brand-700" : "text-amber-700"}`}>
                    {summary?.totalCalories ?? 0} / {summary?.targetCalories ?? 0} kcal
                    {summary?.withinTolerance ? " ✓" : ""}
                  </span>
                </div>
                <ul className="space-y-2">
                  {meals.map((meal) => (
                    <li key={meal.id} className="flex flex-wrap items-center justify-between gap-2 rounded-lg bg-slate-50 p-3 dark:bg-slate-900/40">
                      <div>
                        <p className="text-xs uppercase text-slate-400">
                          {categoryLabels[meal.mealCategory as MealCategory] ?? meal.mealCategory}
                        </p>
                        <p className="font-medium">{meal.recipeName}</p>
                        <p className="text-xs text-slate-500">{formatDraftMealMacros(meal)}</p>
                      </div>
                      <div className="flex gap-2">
                        <button
                          type="button"
                          className="btn-secondary inline-flex items-center gap-1 !px-2 !py-1 text-xs"
                          onClick={() => setPreviewMeal(meal)}
                        >
                          <Eye className="h-3 w-3" />
                          {t("generators.diet.viewRecipe")}
                        </button>
                        <button type="button" className="btn-secondary !px-2 !py-1 text-xs"
                          onClick={() => void toggleDietMealLock(sessionId!, meal.id, !meal.isLocked).then(() => refreshSession(sessionId!))}>
                          {meal.isLocked ? t("generators.diet.unlock") : t("generators.diet.lock")}
                        </button>
                        <button type="button" className="btn-secondary !px-2 !py-1 text-xs" disabled={meal.isLocked}
                          onClick={() => void regenerateDietMeal(sessionId!, meal.planDate, meal.mealCategory)
                            .then((s) => {
                              setSession(s);
                              setError(null);
                              setInfo(null);
                            })
                            .catch((e) => {
                              if (isNoAlternativeMealsError(e)) {
                                setInfo(t("generators.diet.noAlternativeMeals"));
                                setError(null);
                              } else {
                                setError(extractApiError(e, t("generators.diet.error")));
                                setInfo(null);
                              }
                            })}>
                          <RefreshCw className="h-3 w-3" />
                        </button>
                      </div>
                    </li>
                  ))}
                </ul>
              </div>
            );
          })}
          <div className="flex flex-wrap gap-2">
            <button type="button" className="btn-primary"
              onClick={() => void commitDietPlan(sessionId!).then((r) => {
                setCommitResult(`${r.planStartDate} → ${r.planEndDate}`);
                setStep("done");
                queryClient.invalidateQueries({ queryKey: ["meal-plan"] });
              }).catch((e) => setError(extractApiError(e, t("generators.diet.error"))))}>
              {t("generators.diet.commit")}
            </button>
          </div>
        </section>
      ) : null}

      {step === "done" ? (
        <div className="card flex items-center gap-3 p-6 text-brand-800 dark:text-brand-200">
          <CheckCircle2 className="h-6 w-6 shrink-0" />
          <div>
            <p className="font-semibold">{t("generators.diet.done")}</p>
            {commitResult ? <p className="text-sm">{commitResult}</p> : null}
            <div className="mt-3 flex gap-2">
              <Link to="/meal-planner" className="btn-primary">{t("nav.mealPlanner")}</Link>
              <button type="button" className="btn-secondary" onClick={() => navigate("/diet-generator")}>
                {t("generators.diet.newPlan")}
              </button>
            </div>
          </div>
        </div>
      ) : null}

      {loading && step !== "done" ? (
        <div className="flex items-center gap-2 text-sm text-slate-400">
          <Loader2 className="h-4 w-4 animate-spin" /> {t("common.loading")}
        </div>
      ) : null}

      <DietMealPreviewModal meal={previewMeal} onClose={() => setPreviewMeal(null)} />
    </div>
  );
}
