import { useMemo, useState } from 'react';
import { Alert, Modal, Pressable, ScrollView, StyleSheet, Text, View } from 'react-native';
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
import { router } from 'expo-router';
import { useTranslation } from 'react-i18next';
import { deleteMealPlanEntry, fetchMealPlanEntries, upsertMealPlanEntry } from '@/src/api/meal-plan.api';
import { fetchGoals } from '@/src/api/diet.api';
import { fetchRecipes } from '@/src/api/recipes.api';
import { Button } from '@/src/components/Button';
import { ErrorView } from '@/src/components/ErrorView';
import { Input } from '@/src/components/Input';
import { Screen } from '@/src/components/Screen';
import { useAppearance } from '@/src/context/AppearanceContext';
import { CONSUMPTION_CATEGORIES } from '@/src/types/diet';
import type { MealPlanEntry } from '@/src/types/meal-plan';
import { MealCategory } from '@/src/types/recipe';
import { addDays, formatDisplayDate, weekDays, weekRange } from '@/src/utils/date';
import { categoryLabel } from '@/src/utils/recipe';
import {
  computeDayMealPlanning,
  estimateEntryCalories,
  rankRecipeSuggestions,
} from '@/src/utils/mealPlannerSuggestions';

const PLANNER_CATEGORIES = CONSUMPTION_CATEGORIES.filter((c) => c.value <= MealCategory.Dinner);

export default function PlannerScreen() {
  const { t, i18n } = useTranslation();
  const { colors } = useAppearance();
  const queryClient = useQueryClient();
  const [weekAnchor, setWeekAnchor] = useState(() => weekRange().from);
  const { from, to } = useMemo(() => weekRange(weekAnchor), [weekAnchor]);
  const days = useMemo(() => weekDays(from), [from]);

  const [picker, setPicker] = useState<{ date: string; mealCategory: number; entry?: MealPlanEntry } | null>(null);
  const [recipeSearch, setRecipeSearch] = useState('');
  const [portions, setPortions] = useState('1');
  const [dailyTargets, setDailyTargets] = useState<Record<string, number>>({});
  const [selectedRecipeId, setSelectedRecipeId] = useState<number | null>(null);

  const entriesQuery = useQuery({
    queryKey: ['meal-plan', from, to],
    queryFn: () => fetchMealPlanEntries(from, to),
  });

  const goalsQuery = useQuery({
    queryKey: ['diet-goals'],
    queryFn: fetchGoals,
  });

  const recipesQuery = useQuery({
    queryKey: ['recipes', 'planner-search', recipeSearch],
    queryFn: () => fetchRecipes({ search: recipeSearch }),
    enabled: !!picker && recipeSearch.trim().length >= 2,
  });

  const suggestionsQuery = useQuery({
    queryKey: ['recipes', 'planner-suggestions', picker?.mealCategory],
    queryFn: () => fetchRecipes({ category: picker!.mealCategory as MealCategory }),
    enabled: !!picker,
  });

  const entries = entriesQuery.data ?? [];

  const dailyTarget = picker
    ? (dailyTargets[picker.date] ?? goalsQuery.data?.calorieGoal ?? 0)
    : 0;

  const selectedRecipe = useMemo(() => {
    if (!selectedRecipeId) return null;
    return (
      recipesQuery.data?.find((r) => r.id === selectedRecipeId) ??
      suggestionsQuery.data?.find((r) => r.id === selectedRecipeId) ??
      null
    );
  }, [selectedRecipeId, recipesQuery.data, suggestionsQuery.data]);

  const estimatedMealCalories = estimateEntryCalories(selectedRecipe, Number(portions) || 1);

  const dayPlanning = useMemo(() => {
    if (!picker) return null;
    const pending =
      estimatedMealCalories != null && estimatedMealCalories > 0
        ? { category: picker.mealCategory, calories: estimatedMealCalories }
        : null;
    return computeDayMealPlanning(picker.date, picker.mealCategory, entries, dailyTarget, pending);
  }, [picker, entries, dailyTarget, estimatedMealCalories]);

  const suggestions = useMemo(() => {
    if (!picker || !dayPlanning || !suggestionsQuery.data) return [];
    return rankRecipeSuggestions(suggestionsQuery.data, picker.mealCategory, dayPlanning.slotTarget);
  }, [picker, dayPlanning, suggestionsQuery.data]);

  const upsertMutation = useMutation({
    mutationFn: upsertMealPlanEntry,
    onSuccess: () => {
      setPicker(null);
      setRecipeSearch('');
      setPortions('1');
      setSelectedRecipeId(null);
      void queryClient.invalidateQueries({ queryKey: ['meal-plan'] });
    },
  });

  const deleteMutation = useMutation({
    mutationFn: deleteMealPlanEntry,
    onSuccess: () => void queryClient.invalidateQueries({ queryKey: ['meal-plan'] }),
  });

  function selectFromSearch(recipeId: number) {
    setSelectedRecipeId(recipeId);
    setRecipeSearch('');
  }

  function selectFromSuggestion(recipeId: number) {
    setSelectedRecipeId(recipeId);
  }

  function clearSelection() {
    setSelectedRecipeId(null);
  }

  function entryFor(date: string, mealCategory: number): MealPlanEntry | undefined {
    return entriesQuery.data?.find((e) => e.planDate === date && e.mealCategory === mealCategory);
  }

  return (
    <Screen title={t('planner.title')} subtitle={t('planner.subtitle')}>
      <View style={styles.header}>
        <Pressable
          onPress={() => setWeekAnchor(addDays(from, -7))}
          style={[styles.navBtn, { borderColor: colors.border, backgroundColor: colors.surface }]}
        >
          <Text style={{ color: colors.text }}>‹</Text>
        </Pressable>
        <Text style={{ color: colors.text, fontWeight: '700', flex: 1, textAlign: 'center' }}>
          {formatDisplayDate(from, i18n.language)} – {formatDisplayDate(to, i18n.language)}
        </Text>
        <Pressable
          onPress={() => setWeekAnchor(addDays(from, 7))}
          style={[styles.navBtn, { borderColor: colors.border, backgroundColor: colors.surface }]}
        >
          <Text style={{ color: colors.text }}>›</Text>
        </Pressable>
      </View>

      <Button title={t('planner.openShopping')} variant="secondary" onPress={() => router.push('/(main)/(tabs)/shopping')} />

      {entriesQuery.isLoading ? (
        <Text style={{ color: colors.textMuted }}>{t('common.loading')}</Text>
      ) : entriesQuery.isError ? (
        <ErrorView message={t('errors.loadPlannerFailed')} onRetry={() => entriesQuery.refetch()} />
      ) : (
        <ScrollView horizontal showsHorizontalScrollIndicator={false}>
          <View>
            <View style={styles.row}>
              <View style={styles.corner} />
              {days.map((day) => (
                <View key={day} style={[styles.dayHead, { borderColor: colors.border }]}>
                  <Text style={{ color: colors.textMuted, fontSize: 11, fontWeight: '600' }}>
                    {formatDisplayDate(day, i18n.language)}
                  </Text>
                </View>
              ))}
            </View>
            {PLANNER_CATEGORIES.map((cat) => (
              <View key={cat.value} style={styles.row}>
                <View style={[styles.catLabel, { borderColor: colors.border, backgroundColor: colors.surface }]}>
                  <Text style={{ color: colors.text, fontSize: 11, fontWeight: '600' }}>{t(cat.labelKey)}</Text>
                </View>
                {days.map((day) => {
                  const entry = entryFor(day, cat.value);
                  return (
                    <Pressable
                      key={`${day}-${cat.value}`}
                      onPress={() => {
                        setPicker({ date: day, mealCategory: cat.value, entry });
                        setRecipeSearch('');
                        setPortions('1');
                        setSelectedRecipeId(null);
                      }}
                      onLongPress={() => {
                        if (!entry) return;
                        Alert.alert(t('planner.removeEntry'), entry.recipeName, [
                          { text: t('common.cancel'), style: 'cancel' },
                          { text: t('common.delete'), style: 'destructive', onPress: () => deleteMutation.mutate(entry.id) },
                        ]);
                      }}
                      style={[styles.cell, { borderColor: colors.border, backgroundColor: colors.surface }]}
                    >
                      <Text style={{ color: entry ? colors.text : colors.textMuted, fontSize: 11 }} numberOfLines={2}>
                        {entry?.recipeName ?? '+'}
                      </Text>
                    </Pressable>
                  );
                })}
              </View>
            ))}
          </View>
        </ScrollView>
      )}

      <Modal visible={!!picker} transparent animationType="slide" onRequestClose={() => setPicker(null)}>
        <View style={styles.modalBackdrop}>
          <View style={[styles.modal, { backgroundColor: colors.background }]}>
            <Text style={[styles.modalTitle, { color: colors.text }]}>{t('planner.assignRecipe')}</Text>
            {picker ? (
              <Text style={{ color: colors.textMuted, marginBottom: 8 }}>
                {formatDisplayDate(picker.date, i18n.language)} · {categoryLabel(picker.mealCategory as MealCategory, t)}
              </Text>
            ) : null}
            <Input
              label={t('planner.dailyTarget')}
              keyboardType="number-pad"
              value={String(dailyTarget || '')}
              onChangeText={(text) => {
                if (!picker) return;
                const value = Number(text);
                setDailyTargets((prev) => ({
                  ...prev,
                  [picker.date]: Number.isFinite(value) ? value : 0,
                }));
              }}
            />
            {dayPlanning && dailyTarget > 0 ? (
              <View style={[styles.summaryBox, { backgroundColor: colors.surface, borderColor: colors.border }]}>
                <Text style={{ color: colors.text, fontSize: 13 }}>
                  {t('planner.daySummary', { logged: dayPlanning.logged, target: dayPlanning.dailyTarget })}
                </Text>
                <Text style={{ color: colors.textMuted, fontSize: 11, marginTop: 4 }}>
                  {t('planner.remaining', { count: Math.max(0, dayPlanning.remaining) })}
                  {dayPlanning.slotTarget > 0
                    ? ` · ${t('planner.slotHint', { count: dayPlanning.slotTarget })}`
                    : ''}
                  {dayPlanning.pendingCalories > 0
                    ? ` · ${t('planner.includingSelection', { count: dayPlanning.pendingCalories })}`
                    : ''}
                </Text>
              </View>
            ) : (
              <Text style={{ color: colors.textMuted, fontSize: 12 }}>{t('planner.noSuggestions')}</Text>
            )}
            {suggestions.length > 0 ? (
              <View>
                <Text style={{ color: colors.text, fontWeight: '600', marginBottom: 6 }}>
                  {t('planner.suggestionsTitle')}
                </Text>
                <ScrollView style={{ maxHeight: 160 }}>
                  {suggestions.map(({ recipe, diff }) => (
                    <Pressable
                      key={recipe.id}
                      onPress={() => selectFromSuggestion(recipe.id)}
                      style={[
                        styles.recipePick,
                        {
                          borderColor: selectedRecipeId === recipe.id ? colors.brand : colors.border,
                          borderWidth: selectedRecipeId === recipe.id ? 2 : 1,
                          backgroundColor: colors.surface,
                        },
                      ]}
                    >
                      <Text style={{ color: colors.text }}>{recipe.name}</Text>
                      <Text style={{ color: colors.textMuted, fontSize: 11 }}>
                        {recipe.calories} kcal{diff > 0 ? ` · ±${diff}` : ''}
                      </Text>
                    </Pressable>
                  ))}
                </ScrollView>
              </View>
            ) : null}
            <Input placeholder={t('recipes.searchRecipes')} value={recipeSearch} onChangeText={setRecipeSearch} />
            {recipeSearch.trim().length >= 2 && !selectedRecipeId ? (
              <ScrollView style={{ maxHeight: 200 }}>
                {recipesQuery.data?.map((r) => (
                  <Pressable
                    key={r.id}
                    onPress={() => selectFromSearch(r.id)}
                    style={[styles.recipePick, { borderColor: colors.border, backgroundColor: colors.surface }]}
                  >
                    <Text style={{ color: colors.text }}>{r.name}</Text>
                    {r.calories != null ? (
                      <Text style={{ color: colors.textMuted, fontSize: 11 }}>{r.calories} kcal</Text>
                    ) : null}
                  </Pressable>
                ))}
                {recipesQuery.isFetched && !recipesQuery.isLoading && recipesQuery.data?.length === 0 ? (
                  <Text style={{ color: colors.textMuted, fontSize: 12 }}>{t('recipes.noMatchingTitle')}</Text>
                ) : null}
              </ScrollView>
            ) : null}
            {selectedRecipe ? (
              <View style={[styles.summaryBox, { backgroundColor: colors.surface, borderColor: colors.brand }]}>
                <View style={{ flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', gap: 8 }}>
                  <Text style={{ color: colors.text, fontSize: 13, flex: 1 }}>
                    {t('planner.selectedRecipe', { name: selectedRecipe.name })}
                    {estimatedMealCalories != null
                      ? ` · ${estimatedMealCalories} kcal`
                      : selectedRecipe.calories != null
                        ? ` · ${selectedRecipe.calories} kcal`
                        : ''}
                  </Text>
                  <Pressable onPress={clearSelection} hitSlop={8}>
                    <Text style={{ color: colors.textMuted }}>✕</Text>
                  </Pressable>
                </View>
              </View>
            ) : null}
            <Input label={t('diet.portions')} keyboardType="decimal-pad" value={portions} onChangeText={setPortions} />
            {estimatedMealCalories != null ? (
              <Text style={{ color: colors.textMuted, fontSize: 12 }}>
                {t('planner.estimatedMeal', { count: estimatedMealCalories })}
              </Text>
            ) : null}
            <Button
              title={t('common.save')}
              disabled={!selectedRecipeId || upsertMutation.isPending}
              onPress={() => {
                if (!picker || !selectedRecipeId) return;
                upsertMutation.mutate({
                  planDate: picker.date,
                  mealCategory: picker.mealCategory,
                  recipeId: selectedRecipeId,
                  portions: Number(portions) || 1,
                });
              }}
            />
            <Button title={t('common.cancel')} variant="ghost" onPress={() => setPicker(null)} />
          </View>
        </View>
      </Modal>
    </Screen>
  );
}

const styles = StyleSheet.create({
  header: { flexDirection: 'row', alignItems: 'center', gap: 8, marginBottom: 8 },
  navBtn: { borderWidth: 1, borderRadius: 8, width: 36, height: 36, alignItems: 'center', justifyContent: 'center' },
  row: { flexDirection: 'row' },
  corner: { width: 72 },
  dayHead: { width: 88, padding: 6, borderWidth: 1, alignItems: 'center' },
  catLabel: { width: 72, padding: 6, borderWidth: 1, justifyContent: 'center' },
  cell: { width: 88, height: 56, padding: 6, borderWidth: 1, justifyContent: 'center' },
  modalBackdrop: { flex: 1, backgroundColor: 'rgba(0,0,0,0.45)', justifyContent: 'flex-end' },
  modal: { borderTopLeftRadius: 16, borderTopRightRadius: 16, padding: 16, gap: 10, maxHeight: '80%' },
  modalTitle: { fontSize: 18, fontWeight: '700' },
  summaryBox: { borderWidth: 1, borderRadius: 10, padding: 10 },
  recipePick: { borderWidth: 1, borderRadius: 8, padding: 10, marginBottom: 6 },
});
