"use client";

import { useState, useCallback, useEffect, useRef } from "react";
import Link from "next/link";
import { Plus, Trash2, Sparkles, ChefHat, Check } from "lucide-react";
import { toast } from "sonner";
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription } from "@/components/ui/dialog";
import {
  AlertDialog,
  AlertDialogAction,
  AlertDialogCancel,
  AlertDialogContent,
  AlertDialogDescription,
  AlertDialogFooter,
  AlertDialogHeader,
  AlertDialogTitle,
} from "@/components/ui/alert-dialog";
import { FakeProgressBar } from "@/components/ui/fake-progress-bar";
import { Input } from "@/components/ui/input";
import { Button } from "@/components/ui/button";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
import { useTranslations } from "next-intl";
import { BatchCookGenerateDialog } from "@/components/recipe/batch-cook-generate-dialog";

type Day = "mon" | "tue" | "wed" | "thu" | "fri" | "sat" | "sun";
type MealType = "breakfast" | "lunch" | "dinner" | "snack";

type Recipe = { id: string; title: string };
type BatchDish = { id: string; name: string };
type Entry = {
  id: string;
  day: Day;
  mealType: MealType;
  servings: number;
  recipe: Recipe | null;
  batchDish: BatchDish | null;
  note: string | null;
};

type UserRecipe = { id: string; title: string; isBatchCook: boolean; batchDishes: BatchDish[] };

function AddEntryModal({
  weekStart,
  day,
  mealType,
  userRecipes,
  onAdded,
  onClose,
  dayLabel,
  mealLabel,
}: {
  weekStart: string;
  day: Day;
  mealType: MealType;
  userRecipes: UserRecipe[];
  onAdded: (entry: Entry) => void;
  onClose: () => void;
  dayLabel: string;
  mealLabel: string;
}) {
  const [search, setSearch] = useState("");
  const [servings, setServings] = useState("2");
  const [saving, setSaving] = useState(false);
  const [pickingDishFor, setPickingDishFor] = useState<UserRecipe | null>(null);
  const t = useTranslations("mealPlan");

  const filtered = userRecipes.filter((r) =>
    r.title.toLowerCase().includes(search.toLowerCase())
  );

  async function add(recipe: UserRecipe, batchDish?: BatchDish) {
    setSaving(true);
    try {
      const res = await fetch(`/api/v1/meal-plans/${weekStart}/entries`, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({
          day,
          mealType,
          recipeId: recipe.id,
          batchDishId: batchDish?.id,
          servings: parseInt(servings) || 2,
        }),
      });
      if (!res.ok) { toast.error(t("addFailed")); return; }
      const { id } = await res.json() as { id: string };
      onAdded({ id, day, mealType, servings: parseInt(servings) || 2, recipe, batchDish: batchDish ?? null, note: null });
      onClose();
    } finally {
      setSaving(false);
    }
  }

  function selectRecipe(recipe: UserRecipe) {
    if (recipe.isBatchCook && recipe.batchDishes.length > 0) {
      setPickingDishFor(recipe);
      return;
    }
    void add(recipe);
  }

  if (pickingDishFor) {
    return (
      <Dialog open onOpenChange={() => onClose()}>
        <DialogContent className="max-w-md">
          <DialogHeader>
            <DialogTitle>{t("pickDishTitle", { recipe: pickingDishFor.title })}</DialogTitle>
            <DialogDescription>{t("pickDishDescription")}</DialogDescription>
          </DialogHeader>
          <div className="max-h-56 overflow-y-auto space-y-1">
            {pickingDishFor.batchDishes.map((dish) => (
              <button
                key={dish.id}
                onClick={() => { void add(pickingDishFor, dish); }}
                disabled={saving}
                className="w-full text-left px-3 py-2 rounded-lg text-sm hover:bg-muted transition-colors"
              >
                {dish.name}
              </button>
            ))}
          </div>
          <Button variant="ghost" size="sm" onClick={() => setPickingDishFor(null)} disabled={saving}>
            {t("back")}
          </Button>
        </DialogContent>
      </Dialog>
    );
  }

  return (
    <Dialog open onOpenChange={() => onClose()}>
      <DialogContent className="max-w-md">
        <DialogHeader>
          <DialogTitle>{t("addTo", { day: dayLabel, meal: mealLabel })}</DialogTitle>
        </DialogHeader>
        <div className="space-y-3">
          <Input
            placeholder={t("searchRecipes")}
            value={search}
            onChange={(e) => setSearch(e.target.value)}
            autoFocus
          />
          <Input
            type="number"
            min={1}
            max={50}
            value={servings}
            onChange={(e) => setServings(e.target.value)}
            placeholder={t("servings")}
          />
          <div className="max-h-56 overflow-y-auto space-y-1">
            {filtered.length === 0 ? (
              <p className="text-sm text-muted-foreground py-4 text-center">{t("noRecipes")}</p>
            ) : (
              filtered.map((recipe) => (
                <button
                  key={recipe.id}
                  onClick={() => selectRecipe(recipe)}
                  disabled={saving}
                  className="w-full flex items-center justify-between gap-2 text-left px-3 py-2 rounded-lg text-sm hover:bg-muted transition-colors"
                >
                  <span>{recipe.title}</span>
                  {recipe.isBatchCook && (
                    <span className="shrink-0 text-[10px] uppercase tracking-wide text-muted-foreground border rounded-full px-2 py-0.5">
                      {t("batchCookBadge")}
                    </span>
                  )}
                </button>
              ))
            )}
          </div>
        </div>
      </DialogContent>
    </Dialog>
  );
}

export function MealPlanner({
  weekStart,
  initialEntries,
  userRecipes,
  hasNutritionGoals = false,
}: {
  weekStart: string;
  initialEntries: Entry[];
  userRecipes: UserRecipe[];
  hasNutritionGoals?: boolean;
}) {
  const [entries, setEntries] = useState<Entry[]>(initialEntries);
  const [cookedIds, setCookedIds] = useState<Set<string>>(new Set());
  const [markingCookedIds, setMarkingCookedIds] = useState<Set<string>>(new Set());
  const [adding, setAdding] = useState<{ day: Day; mealType: MealType } | null>(null);
  const [showAiModal, setShowAiModal] = useState(false);
  const [showBatchModal, setShowBatchModal] = useState(false);
  const [aiGenerating, setAiGenerating] = useState(false);
  const [aiPhase, setAiPhase] = useState("");
  const [dietaryPrefs, setDietaryPrefs] = useState("");
  const [aiServings, setAiServings] = useState("2");
  const [usePantry, setUsePantry] = useState(true);
  const [pantryMode, setPantryMode] = useState(false);
  const [aiDifficulty, setAiDifficulty] = useState<"" | "easy" | "medium" | "hard">("");
  const [targetNutritionGoals, setTargetNutritionGoals] = useState(false);
  const [clearTarget, setClearTarget] = useState<{ type: "day"; day: Day; label: string } | { type: "week" } | null>(null);
  const [clearing, setClearing] = useState(false);
  const t = useTranslations("mealPlan");
  const tRecipe = useTranslations("recipe");
  const tCommon = useTranslations("common");

  // Live updates: a collaborator can edit this same plan through the shared
  // view (a different URL/component) — poll so those changes show up here
  // without a manual refresh, same pattern as shopping-list-view.tsx.
  const dirtyUntilRef = useRef<Map<string, number>>(new Map());
  const pendingDeleteIdsRef = useRef<Set<string>>(new Set());
  const DIRTY_MS = 4000;

  function markDirty(...ids: string[]) {
    const until = Date.now() + DIRTY_MS;
    for (const id of ids) dirtyUntilRef.current.set(id, until);
  }

  useEffect(() => {
    const interval = setInterval(() => {
      fetch(`/api/v1/meal-plans/${weekStart}/entries`)
        .then((res) => (res.ok ? res.json() : null))
        .then((data: { entries: Entry[] } | null) => {
          if (!data) return;
          const now = Date.now();
          setEntries((prev) => {
            const prevById = new Map(prev.map((e) => [e.id, e]));
            return data.entries
              .filter((s) => !pendingDeleteIdsRef.current.has(s.id))
              .map((s) => {
                const dirty = (dirtyUntilRef.current.get(s.id) ?? 0) > now;
                return dirty ? (prevById.get(s.id) ?? s) : s;
              });
          });
        })
        .catch(() => {});
    }, 4000);
    return () => clearInterval(interval);
  }, [weekStart]);

  async function generateWithAi() {
    setAiGenerating(true);
    setAiPhase(t("aiPhaseAnalyzing"));
    const phases = [
      [1500, t("aiPhasePlanning")],
      [5000, t("aiPhaseSelecting")],
      [10000, t("aiPhaseBalancing")],
      [16000, t("aiPhaseFinalizing")],
    ] as const;
    const timers = phases.map(([delay, label]) =>
      setTimeout(() => setAiPhase(label), delay)
    );
    try {
      const res = await fetch("/api/v1/ai/meal-plan/generate", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({
          weekStart,
          dietaryPrefs: dietaryPrefs.trim() || undefined,
          servings: parseInt(aiServings) || 2,
          usePantry,
          pantryMode,
          difficulty: aiDifficulty || undefined,
          targetNutritionGoals: hasNutritionGoals && targetNutritionGoals,
        }),
      });
      if (!res.ok) {
        const data = await res.json() as { error?: string };
        throw new Error(data.error ?? t("generationFailed"));
      }
      const data = await res.json() as {
        entries: Array<{ id: string; day: string; mealType: string; recipeId: string; recipeTitle: string }>;
      };
      // Merge generated entries into state
      setEntries((prev) => {
        const updated = [...prev];
        for (const e of data.entries) {
          const idx = updated.findIndex((u) => u.day === e.day && u.mealType === e.mealType);
          const newEntry: Entry = {
            id: e.id,
            day: e.day as Day,
            mealType: e.mealType as MealType,
            servings: parseInt(aiServings) || 2,
            recipe: { id: e.recipeId, title: e.recipeTitle },
            batchDish: null,
            note: null,
          };
          if (idx >= 0) updated[idx] = newEntry;
          else updated.push(newEntry);
        }
        return updated;
      });
      setShowAiModal(false);
      toast.success(t("aiGenerated"));
    } catch (err) {
      toast.error(err instanceof Error ? err.message : t("generationFailed"));
    } finally {
      timers.forEach(clearTimeout);
      setAiGenerating(false);
      setAiPhase("");
    }
  }

  const DAYS: { key: Day; label: string }[] = [
    { key: "mon", label: t("days.mon") },
    { key: "tue", label: t("days.tue") },
    { key: "wed", label: t("days.wed") },
    { key: "thu", label: t("days.thu") },
    { key: "fri", label: t("days.fri") },
    { key: "sat", label: t("days.sat") },
    { key: "sun", label: t("days.sun") },
  ];

  const MEAL_TYPES: { key: MealType; label: string }[] = [
    { key: "breakfast", label: t("meals.breakfast") },
    { key: "lunch", label: t("meals.lunch") },
    { key: "dinner", label: t("meals.dinner") },
    { key: "snack", label: t("meals.snack") },
  ];

  const getEntry = (day: Day, mealType: MealType) =>
    entries.find((e) => e.day === day && e.mealType === mealType);

  const handleAdded = useCallback((entry: Entry) => {
    markDirty(entry.id);
    setEntries((prev) => [
      ...prev.filter((e) => !(e.day === entry.day && e.mealType === entry.mealType)),
      entry,
    ]);
  }, []);

  async function removeEntry(entry: Entry) {
    pendingDeleteIdsRef.current.add(entry.id);
    const res = await fetch(`/api/v1/meal-plans/${weekStart}/entries/${entry.id}`, { method: "DELETE" });
    if (res.ok) {
      setEntries((prev) => prev.filter((e) => e.id !== entry.id));
    } else {
      pendingDeleteIdsRef.current.delete(entry.id);
      toast.error(t("removeFailed"));
    }
  }

  async function confirmClear() {
    if (!clearTarget) return;
    const ids = (
      clearTarget.type === "day" ? entries.filter((e) => e.day === clearTarget.day) : entries
    ).map((e) => e.id);
    if (ids.length === 0) { setClearTarget(null); return; }

    for (const id of ids) pendingDeleteIdsRef.current.add(id);
    setClearing(true);
    try {
      const res = await fetch(`/api/v1/meal-plans/${weekStart}/entries/bulk`, {
        method: "DELETE",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ ids }),
      });
      if (!res.ok) {
        for (const id of ids) pendingDeleteIdsRef.current.delete(id);
        toast.error(t("removeFailed"));
        return;
      }
      setEntries((prev) => prev.filter((e) => !ids.includes(e.id)));
      toast.success(t("clearedSuccess", { count: ids.length }));
    } finally {
      setClearing(false);
      setClearTarget(null);
    }
  }

  async function markCooked(entry: Entry) {
    if (!entry.recipe || markingCookedIds.has(entry.id)) return;
    setMarkingCookedIds((prev) => new Set(prev).add(entry.id));
    try {
      const res = await fetch(`/api/v1/recipes/${entry.recipe.id}/cooked`, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ servings: entry.servings, deductFromPantry: true }),
      });
      if (!res.ok) {
        toast.error(t("markCookedFailed"));
        return;
      }
      setCookedIds((prev) => new Set(prev).add(entry.id));
      toast.success(t("markCookedSuccess"));
    } catch {
      toast.error(t("markCookedFailed"));
    } finally {
      setMarkingCookedIds((prev) => {
        const next = new Set(prev);
        next.delete(entry.id);
        return next;
      });
    }
  }

  const addingDay = adding ? DAYS.find((d) => d.key === adding.day) : null;
  const addingMeal = adding ? MEAL_TYPES.find((m) => m.key === adding.mealType) : null;

  return (
    <>
      {/* AI Generate buttons */}
      <div className="flex justify-end gap-2 mb-4">
        {entries.length > 0 && (
          <Button variant="ghost" size="sm" onClick={() => setClearTarget({ type: "week" })} className="gap-2 text-muted-foreground">
            <Trash2 className="h-4 w-4" />
            {t("clearWeek")}
          </Button>
        )}
        <Button variant="outline" size="sm" onClick={() => setShowBatchModal(true)} className="gap-2">
          <ChefHat className="h-4 w-4" />
          {t("batchCooking")}
        </Button>
        <Button size="sm" onClick={() => setShowAiModal(true)} className="gap-2">
          <Sparkles className="h-4 w-4" />
          {t("generateWithAi")}
        </Button>
      </div>

      <div className="overflow-x-auto">
        <table className="w-full min-w-[640px] border-collapse table-fixed">
          <colgroup>
            <col className="w-24" />
            {DAYS.map(({ key }) => (
              <col key={key} />
            ))}
          </colgroup>
          <thead>
            <tr>
              <th className="text-left text-xs font-medium text-muted-foreground pb-3" />
              {DAYS.map(({ key, label }) => {
                const dayHasEntries = entries.some((e) => e.day === key);
                return (
                  <th key={key} className="text-center text-sm font-semibold pb-3 px-2">
                    <span className="group inline-flex items-center gap-1">
                      {label}
                      {dayHasEntries && (
                        <button
                          onClick={() => setClearTarget({ type: "day", day: key, label })}
                          title={t("clearDay")}
                          className="opacity-0 group-hover:opacity-100 text-muted-foreground hover:text-destructive transition-opacity"
                        >
                          <Trash2 className="h-3 w-3" />
                        </button>
                      )}
                    </span>
                  </th>
                );
              })}
            </tr>
          </thead>
          <tbody>
            {MEAL_TYPES.map(({ key: mealType, label }) => (
              <tr key={mealType} className="border-t">
                <td className="py-3 pr-3">
                  <span className="text-xs font-medium text-muted-foreground uppercase tracking-wide">{label}</span>
                </td>
                {DAYS.map(({ key: day }) => {
                  const entry = getEntry(day, mealType);
                  return (
                    <td key={day} className="py-2 px-1 align-top">
                      {entry?.recipe ? (
                        <div className="group relative rounded-lg bg-primary/10 border border-primary/20 p-2 text-xs min-h-[52px]">
                          <Link
                            href={`/recipes/${entry.recipe.id}`}
                            className="block pr-8 hover:underline"
                          >
                            <div className="font-medium line-clamp-2">{entry.batchDish?.name ?? entry.recipe.title}</div>
                            <div className="text-muted-foreground mt-0.5 flex items-center gap-1">
                              {t("servingsAbbrev", { count: entry.servings })}
                              {cookedIds.has(entry.id) && (
                                <Check className="h-3 w-3 text-green-600 shrink-0" />
                              )}
                            </div>
                          </Link>
                          <div className="absolute top-1 right-1 flex items-center gap-1 opacity-0 group-hover:opacity-100 transition-opacity">
                            <button
                              onClick={() => markCooked(entry)}
                              disabled={markingCookedIds.has(entry.id)}
                              title={t("markCooked")}
                              className="text-muted-foreground hover:text-primary disabled:opacity-50"
                            >
                              <ChefHat className="h-3 w-3" />
                            </button>
                            <button
                              onClick={() => removeEntry(entry)}
                              title={t("removeEntry")}
                              className="text-muted-foreground hover:text-destructive"
                            >
                              <Trash2 className="h-3 w-3" />
                            </button>
                          </div>
                        </div>
                      ) : (
                        <button
                          onClick={() => setAdding({ day, mealType })}
                          className="w-full min-h-[52px] rounded-lg border-2 border-dashed border-muted-foreground/20 hover:border-muted-foreground/40 flex items-center justify-center transition-colors"
                        >
                          <Plus className="h-3.5 w-3.5 text-muted-foreground/40" />
                        </button>
                      )}
                    </td>
                  );
                })}
              </tr>
            ))}
          </tbody>
        </table>
      </div>

      {adding && addingDay && addingMeal && (
        <AddEntryModal
          weekStart={weekStart}
          day={adding.day}
          mealType={adding.mealType}
          userRecipes={userRecipes}
          onAdded={handleAdded}
          onClose={() => setAdding(null)}
          dayLabel={addingDay.label}
          mealLabel={addingMeal.label}
        />
      )}

      {/* AI generation modal */}
      {showAiModal && (
        <Dialog open onOpenChange={(open) => { if (!aiGenerating) setShowAiModal(open); }}>
          <DialogContent className="max-w-sm">
            <DialogHeader>
              <DialogTitle className="flex items-center gap-2">
                <Sparkles className="h-4 w-4" />
                {t("generateWithAi")}
              </DialogTitle>
              <DialogDescription>{t("aiModalDescription")}</DialogDescription>
            </DialogHeader>
            <div className="space-y-4">
              <div className="space-y-1.5">
                <label className="text-sm font-medium">{t("dietaryPrefs")}</label>
                <Input
                  placeholder={t("dietaryPrefsPlaceholder")}
                  value={dietaryPrefs}
                  onChange={(e) => setDietaryPrefs(e.target.value)}
                  disabled={aiGenerating}
                />
              </div>
              <div className="grid grid-cols-2 gap-3">
                <div className="space-y-1.5">
                  <label className="text-sm font-medium">{t("servings")}</label>
                  <Input
                    type="number"
                    min={1}
                    max={20}
                    value={aiServings}
                    onChange={(e) => setAiServings(e.target.value)}
                    disabled={aiGenerating}
                  />
                </div>
                <div className="space-y-1.5">
                  <label className="text-sm font-medium">{t("difficulty")}</label>
                  <Select value={aiDifficulty} onValueChange={(v) => setAiDifficulty(v as typeof aiDifficulty)} disabled={aiGenerating}>
                    <SelectTrigger>
                      <SelectValue placeholder={t("anyDifficulty")} />
                    </SelectTrigger>
                    <SelectContent>
                      <SelectItem value="">{t("anyDifficulty")}</SelectItem>
                      <SelectItem value="easy">{tRecipe("difficulty.easy")}</SelectItem>
                      <SelectItem value="medium">{tRecipe("difficulty.medium")}</SelectItem>
                      <SelectItem value="hard">{tRecipe("difficulty.hard")}</SelectItem>
                    </SelectContent>
                  </Select>
                </div>
              </div>
              <div className="space-y-2">
                <label className="flex items-center gap-2 cursor-pointer select-none">
                  <input
                    type="checkbox"
                    className="h-4 w-4"
                    checked={usePantry}
                    onChange={(e) => {
                      setUsePantry(e.target.checked);
                      if (!e.target.checked) setPantryMode(false);
                    }}
                    disabled={aiGenerating}
                  />
                  <span className="text-sm font-medium">{t("includePantryItems")}</span>
                </label>
                {usePantry && (
                  <label className="flex items-start gap-2 cursor-pointer select-none pl-6">
                    <input
                      type="checkbox"
                      className="h-4 w-4 mt-0.5"
                      checked={pantryMode}
                      onChange={(e) => setPantryMode(e.target.checked)}
                      disabled={aiGenerating}
                    />
                    <span className="space-y-0.5">
                      <span className="text-sm font-medium block">{t("pantryMode")}</span>
                      <span className="text-sm text-muted-foreground block">{t("pantryModeDescription")}</span>
                    </span>
                  </label>
                )}
              </div>
              {hasNutritionGoals && (
                <label className="flex items-start gap-2 cursor-pointer select-none">
                  <input
                    type="checkbox"
                    className="h-4 w-4 mt-0.5"
                    checked={targetNutritionGoals}
                    onChange={(e) => setTargetNutritionGoals(e.target.checked)}
                    disabled={aiGenerating}
                  />
                  <span className="space-y-0.5">
                    <span className="text-sm font-medium block">{t("targetNutritionGoals")}</span>
                    <span className="text-sm text-muted-foreground block">{t("targetNutritionGoalsDescription")}</span>
                  </span>
                </label>
              )}
              <FakeProgressBar active={aiGenerating} durationMs={20000} label={aiPhase} />
              <div className="flex gap-2 justify-end">
                <Button variant="ghost" onClick={() => setShowAiModal(false)} disabled={aiGenerating}>
                  {t("cancel")}
                </Button>
                <Button onClick={() => { void generateWithAi(); }} disabled={aiGenerating} className="gap-2">
                  {aiGenerating ? (
                    <>
                      <span className="animate-spin inline-block h-3.5 w-3.5 border-2 border-current border-t-transparent rounded-full" />
                      {t("generating")}
                    </>
                  ) : (
                    <>
                      <Sparkles className="h-3.5 w-3.5" />
                      {t("generate")}
                    </>
                  )}
                </Button>
              </div>
            </div>
          </DialogContent>
        </Dialog>
      )}

      <BatchCookGenerateDialog open={showBatchModal} onOpenChange={setShowBatchModal} />

      <AlertDialog open={clearTarget !== null} onOpenChange={(open) => !open && setClearTarget(null)}>
        <AlertDialogContent>
          <AlertDialogHeader>
            <AlertDialogTitle>
              {clearTarget?.type === "day" ? t("clearDayConfirmTitle", { day: clearTarget.label }) : t("clearWeekConfirmTitle")}
            </AlertDialogTitle>
            <AlertDialogDescription>{t("clearConfirmDescription")}</AlertDialogDescription>
          </AlertDialogHeader>
          <AlertDialogFooter>
            <AlertDialogCancel disabled={clearing}>{tCommon("cancel")}</AlertDialogCancel>
            <AlertDialogAction
              disabled={clearing}
              onClick={() => { void confirmClear(); }}
              className="bg-destructive text-destructive-foreground hover:bg-destructive/90"
            >
              {tCommon("delete")}
            </AlertDialogAction>
          </AlertDialogFooter>
        </AlertDialogContent>
      </AlertDialog>
    </>
  );
}
