import { useState } from "react";
import { Alert, Pressable, View } from "react-native";
import { router, useLocalSearchParams } from "expo-router";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { api, ApiError } from "@/lib/api";
import { t } from "@/lib/i18n";
import { formatMinor } from "@/lib/money";
import {
  Body,
  Button,
  Card,
  ErrorView,
  Heading,
  LoadingView,
  Row,
  Screen,
  Small,
  Spacer,
  Tag,
  Title,
} from "@/components/ui";
import { colors, spacing } from "@/lib/theme";
import { formatQuantity } from "@/lib/units";

/** Receptdetalj: säkerhet, näring, ingredienser vs lager, varianter, betyg. */

interface RecipeDetail {
  id: string;
  titleSv: string;
  title?: string;
  descriptionSv: string;
  description?: string;
  portions: number;
  totalTimeMinutes: number;
  spiceLevel: number;
  nutritionPerPortion: { kcal: number; proteinG: number; carbsG: number; fatG: number };
  estimatedCostMinorPerPortion: number | null;
  costCurrency?: string;
  allergens: string[];
  ingredients: Array<{
    id: string;
    displayNameSv: string;
    displayName?: string;
    quantity: number;
    unit: string;
    optional: boolean;
    groupName: string | null;
    canonicalIngredientId: string;
  }>;
  steps: Array<{
    id: string;
    stepNumber: number;
    instructionSv: string;
    instruction?: string;
    temperatureC: number | null;
  }>;
  safety: { safe: boolean; violations: Array<{ severity: string; messageSv: string }> };
  variants: Array<{ id: string; titleSv: string; variantType: string }>;
  coverage: {
    percent: number;
    missing: Array<{
      canonicalIngredientId: string;
      displayNameSv: string;
      displayName?: string;
      quantity: number;
      unit: string;
    }>;
  } | null;
  myRating: { stars: number } | null;
  isFavorite: boolean;
  ratingAverage: number | null;
  ratingCount: number;
  creatorDisplayName: string | null;
  verificationStatus: string;
}

export default function RecipeScreen() {
  const { id } = useLocalSearchParams<{ id: string }>();
  const queryClient = useQueryClient();
  const [portions, setPortions] = useState<number | null>(null);

  const query = useQuery({
    queryKey: ["recipe", id],
    queryFn: () => api<RecipeDetail>(`/v1/recipes/${id}`),
  });

  const scaled = useQuery({
    queryKey: ["recipe-scaled", id, portions],
    queryFn: () =>
      api<{ ingredients: RecipeDetail["ingredients"] }>(
        `/v1/recipes/${id}/scaled?portions=${portions}`,
      ),
    enabled: portions != null,
  });

  const favorite = useMutation({
    mutationFn: (isFavorite: boolean) =>
      api(`/v1/recipes/${id}/favorite`, { method: isFavorite ? "DELETE" : "POST" }),
    onMutate: async (isFavorite: boolean) => {
      await queryClient.cancelQueries({ queryKey: ["recipe", id] });
      const prev = queryClient.getQueryData<RecipeDetail>(["recipe", id]);
      queryClient.setQueryData<RecipeDetail>(["recipe", id], (old) =>
        old ? { ...old, isFavorite: !isFavorite } : old,
      );
      return { prev };
    },
    onError: (err, _vars, ctx) => {
      if (ctx?.prev) queryClient.setQueryData(["recipe", id], ctx.prev);
      Alert.alert(t("common.oops"), err instanceof Error ? err.message : t("common.error"));
    },
    onSettled: () => void queryClient.invalidateQueries({ queryKey: ["recipe", id] }),
  });

  const rate = useMutation({
    mutationFn: (stars: number) =>
      api(`/v1/recipes/${id}/rate`, { method: "POST", body: { stars, feedbackTags: [] } }),
    onMutate: async (stars: number) => {
      await queryClient.cancelQueries({ queryKey: ["recipe", id] });
      const previous = queryClient.getQueryData<RecipeDetail>(["recipe", id]);
      queryClient.setQueryData<RecipeDetail>(["recipe", id], (old) =>
        old ? { ...old, myRating: { stars } } : old,
      );
      return { previous };
    },
    onError: (err, _stars, context) => {
      if (context?.previous) queryClient.setQueryData(["recipe", id], context.previous);
      Alert.alert(t("common.oops"), err instanceof Error ? err.message : t("common.error"));
    },
    onSettled: () => void queryClient.invalidateQueries({ queryKey: ["recipe", id] }),
  });

  // "Har du lagat denna?" – snabbregistrering utan matlagningsläget: loggar
  // måltiden och räknar av råvarorna från lagret. Saknade råvaror ignoreras
  // (servern hoppar över dem, ingen krasch).
  const logCooked = useMutation({
    mutationFn: () => {
      const hour = new Date().getHours();
      const mealType = hour < 10 ? "breakfast" : hour < 15 ? "lunch" : "dinner";
      return api(`/v1/recipes/${id}/cook`, {
        method: "POST",
        body: { portionsCooked: shownPortions, deductInventory: true, mealType },
      });
    },
    onSuccess: () => {
      void queryClient.invalidateQueries({ queryKey: ["inventory"] });
      void queryClient.invalidateQueries({ queryKey: ["what-to-eat"] });
      void queryClient.invalidateQueries({ queryKey: ["day"] });
      void queryClient.invalidateQueries({ queryKey: ["recipe", id] });
      Alert.alert(t("cookedLog.doneTitle"), t("cookedLog.doneBody"));
    },
    onError: (e) =>
      Alert.alert(t("common.oops"), e instanceof ApiError ? e.message : t("common.error")),
  });

  // Lägg de saknade ingredienserna på inköpslistan (skapar en lista om ingen finns).
  const addMissing = useMutation({
    mutationFn: async (missing: NonNullable<RecipeDetail["coverage"]>["missing"]) => {
      const result = await api<{ lists: Array<{ id: string }> }>("/v1/shopping-lists");
      let listId = result.lists[0]?.id;
      if (!listId) {
        const created = await api<{ list: { id: string } }>("/v1/shopping-lists", {
          method: "POST",
          body: { name: t("shopping.title") },
        });
        listId = created.list.id;
      }
      for (const m of missing) {
        await api(`/v1/shopping-lists/${listId}/items`, {
          method: "POST",
          // Skicka riktig mängd + enhet + katalog-id (annars blir det "1 st").
          // Katalog-id gör att servern slår ihop med ev. befintlig rad.
          body: {
            displayName: m.displayNameSv,
            canonicalIngredientId: m.canonicalIngredientId,
            quantity: m.quantity,
            unit: m.unit,
          },
        });
      }
      return missing.length;
    },
    onSuccess: (count) => {
      void queryClient.invalidateQueries({ queryKey: ["shopping-lists"] });
      Alert.alert(t("recipe.coverage.added"), t("recipe.coverage.addedBody", { count }));
    },
    onError: (err) => {
      // Visa tydlig diagnostik: HTTP-status vs nätverksfel (hjälper felsökning).
      const detail =
        err instanceof ApiError
          ? `[${err.status}] ${err.message}`
          : err instanceof Error
            ? err.message
            : t("common.error");
      Alert.alert(t("common.oops"), detail);
    },
  });

  if (query.isLoading) return <LoadingView />;
  if (query.isError || !query.data) return <ErrorView onRetry={() => void query.refetch()} />;
  const recipe = query.data;
  const shownPortions = portions ?? recipe.portions;
  const ingredients =
    portions != null && scaled.data ? scaled.data.ingredients : recipe.ingredients;
  const blockers = recipe.safety.violations.filter((v) => v.severity === "blocker");
  const warnings = recipe.safety.violations.filter((v) => v.severity === "warning");

  return (
    <Screen>
      <Title>{recipe.title ?? recipe.titleSv}</Title>
      <Row>
        <Tag label={t("recipe.time", { min: recipe.totalTimeMinutes })} />
        <Tag label={`${Math.round(recipe.nutritionPerPortion.kcal)} kcal`} />
        <Tag
          label={`${Math.round(recipe.nutritionPerPortion.proteinG)} g protein`}
          tone="success"
        />
        {recipe.estimatedCostMinorPerPortion != null && (
          <Tag
            label={t("recipe.cost", {
              amount: formatMinor(
                recipe.estimatedCostMinorPerPortion,
                recipe.costCurrency ?? "SEK",
              ),
            })}
          />
        )}
      </Row>
      <Body muted>{recipe.description ?? recipe.descriptionSv}</Body>
      {recipe.creatorDisplayName && (
        <Small>
          {recipe.creatorDisplayName.includes("Redaktion")
            ? `Skapat av ${recipe.creatorDisplayName}`
            : t("recipe.source", { name: recipe.creatorDisplayName })}
        </Small>
      )}

      {!recipe.safety.safe && (
        <Card style={{ borderColor: colors.danger, backgroundColor: colors.dangerSoft }}>
          <Body>⛔ {t("recipe.notSafe")}</Body>
          {blockers.map((v, i) => (
            <Small key={i}>{v.messageSv}</Small>
          ))}
        </Card>
      )}
      {warnings.length > 0 && (
        <Card style={{ backgroundColor: colors.warningSoft, borderColor: colors.warning }}>
          {warnings.map((v, i) => (
            <Small key={i}>⚠️ {v.messageSv}</Small>
          ))}
        </Card>
      )}

      {recipe.variants.length > 0 && (
        <Row>
          {recipe.variants.map((variant) => (
            <Tag key={variant.id} label={`↔ ${variant.titleSv}`} tone="accent" />
          ))}
        </Row>
      )}

      {recipe.coverage && (
        <Card>
          <Row style={{ justifyContent: "space-between", alignItems: "center" }}>
            <Heading>{t("recipe.coverage.have", { percent: recipe.coverage.percent })}</Heading>
            {recipe.coverage.missing.length > 0 && (
              <Tag
                label={t("recipe.coverage.missingCount", { count: recipe.coverage.missing.length })}
                tone="warning"
              />
            )}
          </Row>
          {recipe.coverage.missing.length === 0 ? (
            <Small>{t("recipe.coverage.haveAll")}</Small>
          ) : (
            <>
              <Small>
                {t("recipe.coverage.youAreMissing", {
                  names: recipe.coverage.missing
                    .map((m) => m.displayName ?? m.displayNameSv)
                    .join(", "),
                })}
              </Small>
              <Spacer size={spacing.xs} />
              <Button
                label={t("recipe.coverage.addToList", { count: recipe.coverage.missing.length })}
                variant="primary"
                loading={addMissing.isPending}
                onPress={() => addMissing.mutate(recipe.coverage!.missing)}
              />
            </>
          )}
        </Card>
      )}

      <Card>
        <Row style={{ justifyContent: "space-between" }}>
          <Heading>{t("recipe.ingredients")}</Heading>
          <Row>
            <Button
              label="−"
              variant="ghost"
              onPress={() => setPortions(Math.max(1, shownPortions - 1))}
            />
            <Body>{t("recipe.portions", { count: shownPortions })}</Body>
            <Button
              label="+"
              variant="ghost"
              onPress={() => setPortions(Math.min(24, shownPortions + 1))}
            />
          </Row>
        </Row>
        {ingredients.map((ing) => (
          <Row
            key={ing.id ?? ing.displayName ?? ing.displayNameSv}
            style={{ justifyContent: "space-between" }}
          >
            <Body>
              {ing.displayName ?? ing.displayNameSv}
              {ing.optional ? " (valfritt)" : ""}
            </Body>
            <Small>{formatQuantity(ing.quantity, ing.unit)}</Small>
          </Row>
        ))}
      </Card>

      <Card>
        <Heading>{t("recipe.steps")}</Heading>
        {recipe.steps.map((step) => (
          <View key={step.id} style={{ marginBottom: spacing.sm }}>
            <Body>
              {step.stepNumber}. {step.instruction ?? step.instructionSv}
              {step.temperatureC ? ` (${step.temperatureC} °C)` : ""}
            </Body>
          </View>
        ))}
      </Card>

      <Button
        label={`👨‍🍳 ${t("recipe.cook")}`}
        onPress={() => router.push(`/cooking/${recipe.id}?portions=${shownPortions}`)}
      />
      <Row>
        <View style={{ flex: 1 }}>
          <Button
            label={recipe.isFavorite ? `★ ${t("recipe.saved")}` : `☆ ${t("recipe.save")}`}
            variant="secondary"
            onPress={() => favorite.mutate(recipe.isFavorite)}
          />
        </View>
      </Row>

      <Card>
        <Heading>{t("cooked.rate")}</Heading>
        <Row>
          {[1, 2, 3, 4, 5].map((star) => {
            const filled = (recipe.myRating?.stars ?? 0) >= star;
            return (
              <Pressable
                key={star}
                onPress={() => rate.mutate(star)}
                hitSlop={8}
                style={({ pressed }) => ({
                  opacity: pressed ? 0.6 : 1,
                  paddingHorizontal: spacing.xs,
                })}
              >
                <Small style={{ fontSize: 34, color: filled ? colors.accent : colors.border }}>
                  {filled ? "★" : "☆"}
                </Small>
              </Pressable>
            );
          })}
        </Row>
        {recipe.ratingAverage != null && (
          <Small>
            {t("recipe.avgRating", {
              avg: recipe.ratingAverage.toFixed(1),
              count: recipe.ratingCount,
            })}
          </Small>
        )}
      </Card>

      {/* "Har du lagat denna?" – logga + räkna av lager, även utan kalender. */}
      <Card>
        <Heading>{t("cookedLog.title")}</Heading>
        <Small>{t("cookedLog.subtitle")}</Small>
        <Spacer size={spacing.sm} />
        <Button
          label={t("cookedLog.button")}
          loading={logCooked.isPending}
          onPress={() =>
            Alert.alert(t("cookedLog.title"), t("cookedLog.confirm", { count: shownPortions }), [
              { text: t("common.cancel"), style: "cancel" },
              { text: t("cookedLog.button"), onPress: () => logCooked.mutate() },
            ])
          }
        />
      </Card>
      <Spacer />
    </Screen>
  );
}
