import { useEffect, useMemo, useState } from "react";
import { Alert, Modal, Pressable, Text, View } from "react-native";
import { router } from "expo-router";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { api } from "@/lib/api";
import { getLanguageTag, t } from "@/lib/i18n";
import { colors, radius, spacing } from "@/lib/theme";
import {
  Body,
  Button,
  Card,
  EmptyState,
  ErrorView,
  Heading,
  LoadingView,
  Row,
  Screen,
  Small,
  Spacer,
  Tag,
  Title,
} from "@/components/ui";

/** Veckoplanerare (spec §25): dagsvy + veckostrip, kopplad till /v1/week-plans. */

interface WeekPlanEntry {
  id: string;
  date: string;
  mealType: string;
  recipeId: string | null;
  mealBoxId: string | null;
  titleSv: string;
  portions: number;
  status: string;
  rescheduleReasonSv: string | null;
  sortOrder: number;
}
interface WeekPlan {
  id: string;
  weekStartDate: string;
  status: string;
  entries: WeekPlanEntry[];
}
interface WeekPlansResponse {
  plans: WeekPlan[];
}

const MEAL_ORDER = ["breakfast", "lunch", "dinner", "snack", "dessert"];
const mealTypeLabel = (mealType: string): string =>
  MEAL_ORDER.includes(mealType) ? t(`myday.mealType.${mealType}`) : mealType;

function toKey(d: Date): string {
  const y = d.getFullYear();
  const m = String(d.getMonth() + 1).padStart(2, "0");
  const day = String(d.getDate()).padStart(2, "0");
  return `${y}-${m}-${day}`;
}
function addDays(d: Date, n: number): Date {
  const copy = new Date(d);
  copy.setDate(copy.getDate() + n);
  return copy;
}
/** Måndagen i veckan som d ligger i – veckoplaneraren visar alltid mån–sön. */
function mondayOf(d: Date): Date {
  const copy = new Date(d);
  const dow = copy.getDay(); // 0=sön, 1=mån … 6=lör
  copy.setDate(copy.getDate() + (dow === 0 ? -6 : 1 - dow));
  copy.setHours(0, 0, 0, 0);
  return copy;
}
function cap(s: string): string {
  return s.length ? s[0]!.toUpperCase() + s.slice(1) : s;
}

export default function PlanScreen() {
  const locale = getLanguageTag();
  const queryClient = useQueryClient();
  const [selectedKey, setSelectedKey] = useState<string>(() => toKey(new Date()));
  const [actionEntry, setActionEntry] = useState<WeekPlanEntry | null>(null);
  const [addMealOpen, setAddMealOpen] = useState(false);
  const [generating, setGenerating] = useState(false);
  const [weekOffset, setWeekOffset] = useState(0); // 0 = denna vecka, 1 = nästa vecka …
  const todayKey = toKey(new Date());

  const selected = useMemo(() => new Date(`${selectedKey}T00:00:00`), [selectedKey]);
  // Planeringsfönster: 7 dagar från veckostart (idag + veckoförskjutning).
  // Aldrig bakåt i tiden – weekOffset klampas till >= 0.
  const todayMidnight = useMemo(() => {
    const d = new Date();
    d.setHours(0, 0, 0, 0);
    return d;
  }, []);
  // Veckan börjar ALLTID på måndag (mån–sön), oavsett vilken dag det är idag.
  const thisMonday = useMemo(() => mondayOf(todayMidnight), [todayMidnight]);
  const weekStart = useMemo(() => addDays(thisMonday, weekOffset * 7), [thisMonday, weekOffset]);
  const weekStartKey = toKey(weekStart);
  const weekDays = useMemo(
    () => Array.from({ length: 7 }, (_, i) => addDays(weekStart, i)),
    [weekStart],
  );
  // Byt vecka (framåt/bakåt). Sätter markerad dag till första dagen i veckan.
  const goWeek = (delta: number) =>
    setWeekOffset((o) => {
      const next = Math.max(0, o + delta);
      // Denna vecka: markera idag. Kommande veckor: markera måndagen.
      setSelectedKey(next === 0 ? todayKey : toKey(addDays(thisMonday, next * 7)));
      return next;
    });
  // Lunch + middag varje dag som default (fler fyllda måltider), går att toggla.
  const [mealSlots, setMealSlots] = useState<string[][]>(() =>
    Array.from({ length: 7 }, () => ["lunch", "dinner"]),
  );
  const toggleSlot = (dayIdx: number, meal: string) =>
    setMealSlots((prev) =>
      prev.map((meals, i) =>
        i !== dayIdx
          ? meals
          : meals.includes(meal)
            ? meals.filter((m) => m !== meal)
            : [...meals, meal],
      ),
    );

  const query = useQuery({
    queryKey: ["week-plan", weekStartKey],
    queryFn: () => api<WeekPlansResponse>(`/v1/week-plans?weekStartDate=${weekStartKey}`),
    refetchInterval: generating ? 3000 : false,
  });
  const plan = query.data?.plans?.[0] ?? null;
  const planId = plan?.id ?? null;
  const draftPlanId = plan && plan.status === "draft" ? plan.id : null;
  const hasEntries = (plan?.entries?.length ?? 0) > 0;

  const entriesByDate = useMemo(() => {
    const map: Record<string, WeekPlanEntry[]> = {};
    for (const e of plan?.entries ?? []) {
      (map[e.date] ??= []).push(e);
    }
    for (const list of Object.values(map)) {
      list.sort(
        (a, b) =>
          MEAL_ORDER.indexOf(a.mealType) - MEAL_ORDER.indexOf(b.mealType) ||
          a.sortOrder - b.sortOrder,
      );
    }
    return map;
  }, [plan]);

  const selectedEntries = entriesByDate[selectedKey] ?? [];

  useEffect(() => {
    if (generating && (plan?.entries?.length ?? 0) > 0) setGenerating(false);
  }, [generating, plan]);

  useEffect(() => {
    if (!generating) return;
    const timer = setTimeout(() => setGenerating(false), 45000);
    return () => clearTimeout(timer);
  }, [generating]);

  const invalidate = () => queryClient.invalidateQueries({ queryKey: ["week-plan", weekStartKey] });
  const onMutationError = (err: unknown) =>
    Alert.alert(t("common.oops"), err instanceof Error ? err.message : t("common.error"));

  const generate = useMutation({
    mutationFn: () =>
      api("/v1/week-plans/generate", {
        method: "POST",
        body: { weekStartDate: weekStartKey, mealTypes: ["lunch", "dinner"], mealSlots },
      }),
    onSuccess: () => setGenerating(true),
    onError: onMutationError,
  });

  const patchEntry = useMutation({
    mutationFn: (vars: { planId: string; entryId: string; status: string }) =>
      api(`/v1/week-plans/${vars.planId}/entries/${vars.entryId}`, {
        method: "PATCH",
        body: { status: vars.status },
      }),
    onSuccess: () => invalidate(),
    onError: onMutationError,
  });

  const removeEntry = useMutation({
    mutationFn: (vars: { planId: string; entryId: string }) =>
      api(`/v1/week-plans/${vars.planId}/entries/${vars.entryId}`, { method: "DELETE" }),
    onSuccess: () => invalidate(),
    onError: onMutationError,
  });

  const activate = useMutation({
    mutationFn: (id: string) => api(`/v1/week-plans/${id}/activate`, { method: "POST" }),
    onSuccess: () => invalidate(),
    onError: onMutationError,
  });

  const createList = useMutation({
    mutationFn: (weekPlanId: string) =>
      api<{ list: { id: string } }>("/v1/shopping-lists", {
        method: "POST",
        body: { weekPlanId, generateFromPlan: true },
      }),
    // Navigera med listId så rätt (nygenererade) lista visas, inte en äldre tom.
    onSuccess: (res) => router.push(`/shopping?listId=${res.list.id}`),
    onError: onMutationError,
  });

  // Öppnar en egen bottenpanel (Modal) i stället för Alert – ingen "Avbryt",
  // tryck utanför för att stänga (känns mer enterprise).
  const openActions = (entry: WeekPlanEntry) => {
    if (planId) setActionEntry(entry);
  };

  const weekRangeLabel = `${new Intl.DateTimeFormat(locale, { day: "numeric" }).format(
    weekStart,
  )}–${new Intl.DateTimeFormat(locale, { day: "numeric", month: "short" }).format(
    addDays(weekStart, 6),
  )}`;
  const dayHeader = cap(
    new Intl.DateTimeFormat(locale, { weekday: "long", day: "numeric", month: "long" }).format(
      selected,
    ),
  );
  const weekdayShort = new Intl.DateTimeFormat(locale, { weekday: "short" });

  return (
    <Screen>
      <View style={{ flexDirection: "row", alignItems: "center", justifyContent: "space-between" }}>
        <Pressable
          onPress={() => goWeek(-1)}
          hitSlop={8}
          disabled={weekOffset === 0}
          style={{ opacity: weekOffset === 0 ? 0.3 : 1 }}
        >
          <Text style={{ fontSize: 22, color: colors.textMuted, paddingHorizontal: spacing.sm }}>
            ‹
          </Text>
        </Pressable>
        <Title>{weekRangeLabel}</Title>
        <Pressable onPress={() => goWeek(1)} hitSlop={8}>
          <Text style={{ fontSize: 22, color: colors.textMuted, paddingHorizontal: spacing.sm }}>
            ›
          </Text>
        </Pressable>
      </View>

      <Pressable
        onPress={() => {
          setWeekOffset(0);
          setSelectedKey(todayKey);
        }}
        style={{ alignSelf: "flex-start", paddingVertical: spacing.xs }}
      >
        <Text style={{ color: colors.primary, fontSize: 13, fontWeight: "600" }}>
          {t("plan.today")}
        </Text>
      </Pressable>

      <View
        style={{
          flexDirection: "row",
          justifyContent: "space-between",
          marginVertical: spacing.sm,
        }}
      >
        {weekDays.map((d) => {
          const key = toKey(d);
          const isSelected = key === selectedKey;
          const isToday = key === todayKey;
          const count = entriesByDate[key]?.length ?? 0;
          return (
            <Pressable
              key={key}
              onPress={() => setSelectedKey(key)}
              accessibilityRole="button"
              accessibilityState={{ selected: isSelected }}
              style={{
                flex: 1,
                alignItems: "center",
                paddingVertical: spacing.xs,
                marginHorizontal: 2,
                borderRadius: radius.md,
                backgroundColor: isSelected
                  ? colors.primary
                  : isToday
                    ? colors.primarySoft
                    : "transparent",
              }}
            >
              <Text style={{ fontSize: 12, color: isSelected ? colors.surface : colors.textMuted }}>
                {cap(weekdayShort.format(d))}
              </Text>
              <Text
                style={{
                  fontSize: 16,
                  fontWeight: isSelected || isToday ? "700" : "500",
                  color: isSelected ? colors.surface : colors.text,
                }}
              >
                {d.getDate()}
              </Text>
              <Text
                style={{
                  fontSize: 10,
                  lineHeight: 12,
                  minHeight: 12,
                  color: isSelected ? colors.surface : colors.primary,
                }}
              >
                {count > 0 ? "•".repeat(Math.min(count, 3)) : " "}
              </Text>
            </Pressable>
          );
        })}
      </View>

      <Small>{dayHeader}</Small>
      {draftPlanId ? (
        <Button
          label={t("plan.activate")}
          variant="secondary"
          onPress={() => draftPlanId && activate.mutate(draftPlanId)}
          loading={activate.isPending}
        />
      ) : null}
      <Spacer size={spacing.xs} />

      {query.isLoading ? (
        <LoadingView />
      ) : query.isError ? (
        <ErrorView onRetry={() => void query.refetch()} />
      ) : generating ? (
        <>
          <Small>{t("plan.generating")}</Small>
          <LoadingView />
        </>
      ) : selectedEntries.length > 0 ? (
        selectedEntries.map((entry) => {
          const cooked = entry.status === "cooked";
          const skipped = entry.status === "skipped";
          return (
            <Card key={entry.id} onPress={() => openActions(entry)}>
              <Row style={{ justifyContent: "space-between" }}>
                <Body muted={cooked || skipped}>{entry.titleSv}</Body>
                <Row>
                  {cooked ? <Tag label={t("plan.cooked")} tone="success" /> : null}
                  {skipped ? <Tag label={t("plan.skipped")} tone="warning" /> : null}
                  <Tag label={mealTypeLabel(entry.mealType)} />
                </Row>
              </Row>
              <Small>{t("plan.portions", { count: entry.portions })}</Small>
              {entry.rescheduleReasonSv ? <Small>{entry.rescheduleReasonSv}</Small> : null}
            </Card>
          );
        })
      ) : (
        <>
          <EmptyState text={t("plan.emptyDay")} />
          {(plan === null || !hasEntries) && (
            <>
              <Small>{t("plan.chooseMeals")}</Small>
              {weekDays.map((d, i) => (
                <Row
                  key={toKey(d)}
                  style={{
                    justifyContent: "space-between",
                    alignItems: "center",
                    marginVertical: 2,
                  }}
                >
                  <Small>
                    {cap(
                      new Intl.DateTimeFormat(locale, { weekday: "short", day: "numeric" }).format(
                        d,
                      ),
                    )}
                  </Small>
                  <Row>
                    {(["breakfast", "lunch", "dinner"] as const).map((meal) => (
                      <Pressable
                        key={meal}
                        onPress={() => toggleSlot(i, meal)}
                        style={{ marginLeft: spacing.xs }}
                      >
                        <Tag
                          label={mealTypeLabel(meal)}
                          tone={mealSlots[i]?.includes(meal) ? "accent" : "neutral"}
                        />
                      </Pressable>
                    ))}
                  </Row>
                </Row>
              ))}
              <Spacer size={spacing.xs} />
              <Button
                label={t("plan.generate")}
                onPress={() => generate.mutate()}
                loading={generate.isPending}
              />
            </>
          )}
        </>
      )}

      {/* Lägg till en måltid på vald dag (även tom dag), så länge en plan finns. */}
      {planId && !generating ? (
        <>
          <Spacer size={spacing.xs} />
          <Button
            label={t("plan.addMeal")}
            variant="secondary"
            onPress={() => setAddMealOpen(true)}
          />
        </>
      ) : null}

      {hasEntries ? (
        <>
          <Spacer size={spacing.sm} />
          <Button
            label={t("plan.createShopping")}
            variant="secondary"
            onPress={() => planId && createList.mutate(planId)}
            loading={createList.isPending}
          />
          <Spacer size={spacing.xs} />
          <Button
            label={t("plan.regenerate")}
            variant="ghost"
            onPress={() => generate.mutate()}
            loading={generate.isPending}
          />
        </>
      ) : null}

      {/* Välj måltidstyp att lägga till – navigerar till receptväljaren i "lägg till"-läge. */}
      <Modal
        visible={addMealOpen}
        transparent
        animationType="fade"
        onRequestClose={() => setAddMealOpen(false)}
      >
        <Pressable
          onPress={() => setAddMealOpen(false)}
          style={{ flex: 1, justifyContent: "flex-end", backgroundColor: "rgba(0,0,0,0.4)" }}
        >
          <Pressable
            onPress={() => {}}
            style={{
              backgroundColor: colors.surface,
              borderTopLeftRadius: radius.lg,
              borderTopRightRadius: radius.lg,
              padding: spacing.lg,
              paddingBottom: spacing.xl,
            }}
          >
            <Heading>{t("plan.addMeal")}</Heading>
            <Small>{dayHeader}</Small>
            <Spacer size={spacing.sm} />
            {(["breakfast", "lunch", "dinner", "snack", "dessert"] as const).map((meal) => (
              <View key={meal}>
                <Button
                  label={mealTypeLabel(meal)}
                  variant="secondary"
                  onPress={() => {
                    setAddMealOpen(false);
                    router.push(
                      `/swap-meal/new?planId=${planId}&mealType=${meal}&date=${selectedKey}`,
                    );
                  }}
                />
                <Spacer size={spacing.xs} />
              </View>
            ))}
          </Pressable>
        </Pressable>
      </Modal>

      {/* Åtgärdspanel för en måltid – tryck utanför för att stänga, ingen Avbryt. */}
      <Modal
        visible={actionEntry !== null}
        transparent
        animationType="fade"
        onRequestClose={() => setActionEntry(null)}
      >
        <Pressable
          onPress={() => setActionEntry(null)}
          style={{ flex: 1, justifyContent: "flex-end", backgroundColor: "rgba(0,0,0,0.4)" }}
        >
          <Pressable
            onPress={() => {}}
            style={{
              backgroundColor: colors.surface,
              borderTopLeftRadius: radius.lg,
              borderTopRightRadius: radius.lg,
              padding: spacing.lg,
              paddingBottom: spacing.xl,
            }}
          >
            {actionEntry ? (
              <>
                <Heading>{actionEntry.titleSv}</Heading>
                {actionEntry.date === todayKey ? (
                  <>
                    <Button
                      label={t("recipe.iCookedThis")}
                      onPress={() => {
                        patchEntry.mutate({
                          planId: planId!,
                          entryId: actionEntry.id,
                          status: "cooked",
                        });
                        setActionEntry(null);
                      }}
                    />
                    <Spacer size={spacing.xs} />
                  </>
                ) : null}
                <Button
                  label={t("plan.swapDish")}
                  variant="secondary"
                  onPress={() => {
                    const e = actionEntry;
                    setActionEntry(null);
                    router.push(`/swap-meal/${e.id}?planId=${planId}&mealType=${e.mealType}`);
                  }}
                />
                <Spacer size={spacing.xs} />
                <Button
                  label={t("common.remove")}
                  variant="danger"
                  onPress={() => {
                    removeEntry.mutate({ planId: planId!, entryId: actionEntry.id });
                    setActionEntry(null);
                  }}
                />
              </>
            ) : null}
          </Pressable>
        </Pressable>
      </Modal>
    </Screen>
  );
}
