import { useEffect, useMemo, useState } from "react";
import { Alert, Pressable, Text, View } from "react-native";
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,
  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;
}
function startOfWeekMonday(d: Date): Date {
  const copy = new Date(d);
  const dow = (copy.getDay() + 6) % 7;
  copy.setDate(copy.getDate() - 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 [generating, setGenerating] = useState(false);
  const todayKey = toKey(new Date());

  const selected = useMemo(() => new Date(`${selectedKey}T00:00:00`), [selectedKey]);
  const monday = useMemo(() => startOfWeekMonday(selected), [selected]);
  const mondayKey = toKey(monday);
  const weekDays = useMemo(() => Array.from({ length: 7 }, (_, i) => addDays(monday, i)), [monday]);

  const query = useQuery({
    queryKey: ["week-plan", mondayKey],
    queryFn: () => api<WeekPlansResponse>(`/v1/week-plans?weekStartDate=${mondayKey}`),
    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 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", mondayKey] });
  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: mondayKey, mealTypes: ["lunch", "dinner"] },
      }),
    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 activate = useMutation({
    mutationFn: (id: string) => api(`/v1/week-plans/${id}/activate`, { method: "POST" }),
    onSuccess: () => invalidate(),
    onError: onMutationError,
  });

  const openActions = (entry: WeekPlanEntry) => {
    if (!planId) return;
    Alert.alert(entry.titleSv, undefined, [
      {
        text: t("recipe.iCookedThis"),
        onPress: () => patchEntry.mutate({ planId, entryId: entry.id, status: "cooked" }),
      },
      {
        text: t("common.skip"),
        onPress: () => patchEntry.mutate({ planId, entryId: entry.id, status: "skipped" }),
      },
      { text: t("common.cancel"), style: "cancel" },
    ]);
  };

  const monthLabel = cap(
    new Intl.DateTimeFormat(locale, { month: "long", year: "numeric" }).format(selected),
  );
  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={() => setSelectedKey(toKey(addDays(selected, -7)))} hitSlop={8}>
          <Text style={{ fontSize: 22, color: colors.textMuted, paddingHorizontal: spacing.sm }}>
            ‹
          </Text>
        </Pressable>
        <Title>{monthLabel}</Title>
        <Pressable onPress={() => setSelectedKey(toKey(addDays(selected, 7)))} hitSlop={8}>
          <Text style={{ fontSize: 22, color: colors.textMuted, paddingHorizontal: spacing.sm }}>
            ›
          </Text>
        </Pressable>
      </View>

      <Pressable
        onPress={() => 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 && (
            <Button
              label={t("plan.generate")}
              onPress={() => generate.mutate()}
              loading={generate.isPending}
            />
          )}
        </>
      )}
    </Screen>
  );
}
