"use client";

import { useState } from "react";
import { useTranslations } from "next-intl";
import { Minus, Plus, Sparkles, X } from "lucide-react";
import { Button } from "@/components/ui/button";
import { formatIngredientQuantity, type UnitPref } from "@/lib/unit-conversion";
import { SubstituteIngredientPopover } from "@/components/recipe/substitute-ingredient-popover";

type Ingredient = {
  id: string;
  rawName: string;
  quantity: string | null;
  unit: string | null;
  note: string | null;
  order: number;
};

export type ScaledIngredient = {
  rawName: string;
  quantity: string;
  unit: string | null;
  note?: string;
};

export function ServingScaler({
  baseServings,
  ingredients,
  recipeTitle,
  recipeId,
  onAiScale,
  unitPref = "metric",
}: {
  baseServings: number;
  ingredients: Ingredient[];
  recipeTitle?: string;
  recipeId?: string;
  onAiScale?: (ingredients: ScaledIngredient[] | null) => void;
  unitPref?: UnitPref;
}) {
  const t = useTranslations("servingScaler");
  const [servings, setServings] = useState(baseServings);
  const [aiScaledIngredients, setAiScaledIngredients] = useState<ScaledIngredient[] | null>(null);
  const [aiScaling, setAiScaling] = useState(false);
  const min = 1;
  const max = 100;

  async function handleAiScale() {
    if (!recipeId) return;
    setAiScaling(true);
    try {
      const res = await fetch("/api/v1/ai/scale", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ recipeId, targetServings: servings }),
      });
      if (!res.ok) return;
      const data = await res.json() as { ingredients: ScaledIngredient[] };
      setAiScaledIngredients(data.ingredients);
      onAiScale?.(data.ingredients);
    } finally {
      setAiScaling(false);
    }
  }

  function dismissAiScale() {
    setAiScaledIngredients(null);
    onAiScale?.(null);
  }

  return (
    <div className="space-y-4">
      <div className="flex items-center gap-3 flex-wrap">
        <span className="text-sm font-medium text-muted-foreground">{t("servings")}</span>
        <div className="flex items-center gap-2">
          <Button
            variant="outline"
            size="sm"
            className="h-7 w-7 p-0"
            onClick={() => setServings((s) => Math.max(min, s - 1))}
            disabled={servings <= min}
          >
            <Minus className="h-3 w-3" />
          </Button>
          <span className="w-8 text-center font-semibold tabular-nums">{servings}</span>
          <Button
            variant="outline"
            size="sm"
            className="h-7 w-7 p-0"
            onClick={() => setServings((s) => Math.min(max, s + 1))}
            disabled={servings >= max}
          >
            <Plus className="h-3 w-3" />
          </Button>
        </div>
        {servings !== baseServings && (
          <button
            className="text-xs text-muted-foreground hover:text-foreground underline"
            onClick={() => setServings(baseServings)}
          >
            {t("reset")}
          </button>
        )}
        {recipeId && servings !== baseServings && (
          <Button
            variant="outline"
            size="sm"
            className="h-7 gap-1 text-xs"
            onClick={handleAiScale}
            disabled={aiScaling}
          >
            <Sparkles className="h-3 w-3" />
            {aiScaling ? t("scaling") : t("aiScale")}
          </Button>
        )}
      </div>

      {aiScaledIngredients && (
        <div className="flex items-center gap-2 text-xs text-muted-foreground">
          <Sparkles className="h-3 w-3 shrink-0" />
          <span>{t("aiScaledNote")}</span>
          <button
            className="ml-auto hover:text-foreground"
            onClick={dismissAiScale}
            aria-label={t("dismissAiScaling")}
          >
            <X className="h-3 w-3" />
          </button>
        </div>
      )}

      {/* grid + `contents` on each <li>, not flex — a flex child's quantity
          column only has a *minimum* width, so it drifts row-to-row once any
          value's text (e.g. an appended "(~2 tbsp)" conversion) exceeds that
          minimum. A shared grid track sizes to the widest cell across every
          row, so the name column lines up regardless of quantity length. */}
      <ul className="grid grid-cols-[auto_1fr] gap-x-2 gap-y-2 text-sm">
        {ingredients
          .sort((a, b) => a.order - b.order)
          .map((ing) => {
            const aiIng = aiScaledIngredients?.find((s) => s.rawName === ing.rawName);
            return (
              <li key={ing.id} className="contents group">
                <span className="font-medium tabular-nums text-right whitespace-nowrap">
                  {aiIng
                    ? formatIngredientQuantity(aiIng.quantity, aiIng.unit, unitPref)
                    : formatIngredientQuantity(ing.quantity, ing.unit, unitPref, {
                        base: baseServings,
                        desired: servings,
                      })}
                </span>
                <span className="flex items-center gap-1">
                  {ing.rawName}
                  {(aiIng?.note ?? ing.note) && (
                    <span className="text-muted-foreground">, {aiIng?.note ?? ing.note}</span>
                  )}
                  {recipeTitle && <SubstituteIngredientPopover ingredient={ing.rawName} recipeTitle={recipeTitle} />}
                </span>
              </li>
            );
          })}
      </ul>
    </div>
  );
}
