import React, { useCallback, useEffect, useState } from 'react';
import { Box, Text, useInput } from 'ink';
import type { RecipeDTO, RecipeType, RecipeSummaryDTO, ProductionStepDTO, IngredientDTO, ArticleDTO } from '@effigenix/api-client';
import { RECIPE_TYPE_LABELS } from '@effigenix/api-client';
import { useNavigation } from '../../state/navigation-context.js';
import { LoadingSpinner } from '../shared/LoadingSpinner.js';
import { ErrorDisplay } from '../shared/ErrorDisplay.js';
import { SuccessDisplay } from '../shared/SuccessDisplay.js';
import { ConfirmDialog } from '../shared/ConfirmDialog.js';
import { client } from '../../utils/api-client.js';

type MenuAction = 'add-ingredient' | 'remove-ingredient' | 'reorder-ingredients' | 'add-step' | 'remove-step' | 'activate' | 'archive' | 'back';
type Mode = 'menu' | 'select-step-to-remove' | 'confirm-remove' | 'select-ingredient-to-remove' | 'confirm-remove-ingredient' | 'confirm-activate' | 'confirm-archive' | 'reorder-ingredient';

function errorMessage(err: unknown): string {
  return err instanceof Error ? err.message : 'Unbekannter Fehler';
}

export function RecipeDetailScreen() {
  const { params, navigate, back } = useNavigation();
  const recipeId = params['recipeId'] ?? '';

  const [recipe, setRecipe] = useState<RecipeDTO | null>(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);
  const [mode, setMode] = useState<Mode>('menu');
  const [selectedAction, setSelectedAction] = useState(0);
  const [actionLoading, setActionLoading] = useState(false);
  const [successMessage, setSuccessMessage] = useState<string | null>(null);
  const [selectedStepIndex, setSelectedStepIndex] = useState(0);
  const [stepToRemove, setStepToRemove] = useState<ProductionStepDTO | null>(null);
  const [selectedIngredientIndex, setSelectedIngredientIndex] = useState(0);
  const [ingredientToRemove, setIngredientToRemove] = useState<IngredientDTO | null>(null);
  const [articleMap, setArticleMap] = useState<Record<string, string>>({});
  const [recipeMap, setRecipeMap] = useState<Record<string, string>>({});

  // Reorder state
  const [reorderList, setReorderList] = useState<IngredientDTO[]>([]);
  const [reorderCursor, setReorderCursor] = useState(0);
  const [reorderHeld, setReorderHeld] = useState<number | null>(null);

  const isDraft = recipe?.status === 'DRAFT';
  const isActive = recipe?.status === 'ACTIVE';

  const menuItems: { id: MenuAction; label: string }[] = [
    ...(isDraft ? [
      { id: 'add-ingredient' as const, label: '[Zutat hinzufügen]' },
      { id: 'remove-ingredient' as const, label: '[Zutat entfernen]' },
      ...(sortedIngredientsOf(recipe).length >= 2
        ? [{ id: 'reorder-ingredients' as const, label: '[Zutaten neu anordnen]' }]
        : []),
      { id: 'add-step' as const, label: '[Schritt hinzufügen]' },
      { id: 'remove-step' as const, label: '[Schritt entfernen]' },
      { id: 'activate' as const, label: '[Rezept aktivieren]' },
    ] : []),
    ...(isActive ? [
      { id: 'archive' as const, label: '[Rezept archivieren]' },
    ] : []),
    { id: 'back' as const, label: '[Zurück]' },
  ];

  const clampedAction = Math.min(selectedAction, menuItems.length - 1);

  const sortedSteps = recipe?.productionSteps
    ? [...recipe.productionSteps].sort((a, b) => a.stepNumber - b.stepNumber)
    : [];

  const sortedIngredients = sortedIngredientsOf(recipe);

  const loadRecipe = useCallback(() => {
    setLoading(true);
    setError(null);
    Promise.all([
      client.recipes.getById(recipeId),
      client.articles.list().catch(() => [] as ArticleDTO[]),
      client.recipes.list().catch(() => [] as RecipeSummaryDTO[]),
    ]).then(([r, articles, recipes]) => {
      setRecipe(r);
      const aMap: Record<string, string> = {};
      for (const a of articles) aMap[a.id] = `${a.name} (${a.articleNumber})`;
      setArticleMap(aMap);
      const rMap: Record<string, string> = {};
      for (const rec of recipes) rMap[rec.id] = `${rec.name} v${rec.version}`;
      setRecipeMap(rMap);
      setLoading(false);
    }).catch((err: unknown) => { setError(errorMessage(err)); setLoading(false); });
  }, [recipeId]);

  useEffect(() => { if (recipeId) loadRecipe(); }, [loadRecipe, recipeId]);

  useInput((_input, key) => {
    if (loading || actionLoading) return;

    if (mode === 'menu') {
      if (key.upArrow) setSelectedAction((i) => Math.max(0, i - 1));
      if (key.downArrow) setSelectedAction((i) => Math.min(menuItems.length - 1, i + 1));
      if (key.return) void handleAction();
      if (key.backspace || key.escape) back();
    }

    if (mode === 'select-step-to-remove') {
      if (key.upArrow) setSelectedStepIndex((i) => Math.max(0, i - 1));
      if (key.downArrow) setSelectedStepIndex((i) => Math.min(sortedSteps.length - 1, i + 1));
      if (key.return && sortedSteps.length > 0) {
        setStepToRemove(sortedSteps[selectedStepIndex] ?? null);
        setMode('confirm-remove');
      }
      if (key.escape) { setMode('menu'); setSelectedStepIndex(0); }
    }

    if (mode === 'select-ingredient-to-remove') {
      if (key.upArrow) setSelectedIngredientIndex((i) => Math.max(0, i - 1));
      if (key.downArrow) setSelectedIngredientIndex((i) => Math.min(sortedIngredients.length - 1, i + 1));
      if (key.return && sortedIngredients.length > 0) {
        setIngredientToRemove(sortedIngredients[selectedIngredientIndex] ?? null);
        setMode('confirm-remove-ingredient');
      }
      if (key.escape) { setMode('menu'); setSelectedIngredientIndex(0); }
    }

    if (mode === 'reorder-ingredient') {
      if (key.escape) {
        setMode('menu');
        setReorderHeld(null);
        return;
      }
      if (key.return) {
        void handleReorderSave();
        return;
      }
      if (_input === ' ') {
        if (reorderHeld === null) {
          setReorderHeld(reorderCursor);
        } else {
          setReorderHeld(null);
        }
        return;
      }
      if (key.upArrow) {
        if (reorderHeld !== null) {
          if (reorderCursor > 0) {
            setReorderList((list) => {
              const newList = [...list];
              const temp = newList[reorderCursor]!;
              newList[reorderCursor] = newList[reorderCursor - 1]!;
              newList[reorderCursor - 1] = temp;
              return newList;
            });
            setReorderHeld(reorderCursor - 1);
            setReorderCursor((c) => c - 1);
          }
        } else {
          setReorderCursor((c) => Math.max(0, c - 1));
        }
        return;
      }
      if (key.downArrow) {
        if (reorderHeld !== null) {
          if (reorderCursor < reorderList.length - 1) {
            setReorderList((list) => {
              const newList = [...list];
              const temp = newList[reorderCursor]!;
              newList[reorderCursor] = newList[reorderCursor + 1]!;
              newList[reorderCursor + 1] = temp;
              return newList;
            });
            setReorderHeld(reorderCursor + 1);
            setReorderCursor((c) => c + 1);
          }
        } else {
          setReorderCursor((c) => Math.min(reorderList.length - 1, c + 1));
        }
        return;
      }
    }
  });

  const handleAction = async () => {
    if (!recipe) return;
    const item = menuItems[clampedAction];
    if (!item) return;

    switch (item.id) {
      case 'add-ingredient':
        navigate('recipe-add-ingredient', { recipeId });
        break;
      case 'remove-ingredient':
        if (sortedIngredients.length === 0) {
          setError('Keine Zutaten vorhanden.');
          return;
        }
        setSelectedIngredientIndex(0);
        setMode('select-ingredient-to-remove');
        break;
      case 'reorder-ingredients':
        setReorderList([...sortedIngredients]);
        setReorderCursor(0);
        setReorderHeld(null);
        setMode('reorder-ingredient');
        break;
      case 'add-step':
        navigate('recipe-add-production-step', { recipeId });
        break;
      case 'remove-step':
        if (sortedSteps.length === 0) {
          setError('Keine Produktionsschritte vorhanden.');
          return;
        }
        setSelectedStepIndex(0);
        setMode('select-step-to-remove');
        break;
      case 'activate':
        setMode('confirm-activate');
        break;
      case 'archive':
        setMode('confirm-archive');
        break;
      case 'back':
        back();
        break;
    }
  };

  const handleReorderSave = useCallback(async () => {
    if (!recipe) return;

    const hasChanged = reorderList.some((ing, idx) => ing.id !== sortedIngredients[idx]?.id);
    if (!hasChanged) {
      setMode('menu');
      setReorderHeld(null);
      return;
    }

    setActionLoading(true);
    setMode('menu');
    setReorderHeld(null);

    try {
      // Remove all ingredients
      for (const ing of sortedIngredients) {
        await client.recipes.removeIngredient(recipe.id, ing.id);
      }
      // Re-add in new order
      for (let i = 0; i < reorderList.length; i++) {
        const ing = reorderList[i]!;
        await client.recipes.addIngredient(recipe.id, {
          articleId: ing.articleId,
          quantity: ing.quantity,
          uom: ing.uom,
          position: i + 1,
          ...(ing.subRecipeId ? { subRecipeId: ing.subRecipeId } : {}),
          substitutable: ing.substitutable,
        });
      }
      const updated = await client.recipes.getById(recipe.id);
      setRecipe(updated);
      setSuccessMessage('Zutaten-Reihenfolge aktualisiert.');
    } catch (err: unknown) {
      setError(errorMessage(err));
      // Reload to get consistent state
      try {
        const updated = await client.recipes.getById(recipe.id);
        setRecipe(updated);
      } catch { /* ignore reload error */ }
    }
    setActionLoading(false);
  }, [recipe, reorderList, sortedIngredients]);

  const handleRemoveStep = useCallback(async () => {
    if (!recipe || !stepToRemove) return;
    setMode('menu');
    setActionLoading(true);
    try {
      await client.recipes.removeProductionStep(recipe.id, stepToRemove.stepNumber);
      const updated = await client.recipes.getById(recipe.id);
      setRecipe(updated);
      setSuccessMessage(`Schritt ${stepToRemove.stepNumber} entfernt.`);
    } catch (err: unknown) {
      setError(errorMessage(err));
    }
    setActionLoading(false);
    setStepToRemove(null);
  }, [recipe, stepToRemove]);

  const handleRemoveIngredient = useCallback(async () => {
    if (!recipe || !ingredientToRemove) return;
    setMode('menu');
    setActionLoading(true);
    try {
      await client.recipes.removeIngredient(recipe.id, ingredientToRemove.id);
      const updated = await client.recipes.getById(recipe.id);
      setRecipe(updated);
      setSuccessMessage(`Zutat (Position ${ingredientToRemove.position}) entfernt.`);
    } catch (err: unknown) {
      setError(errorMessage(err));
    }
    setActionLoading(false);
    setIngredientToRemove(null);
  }, [recipe, ingredientToRemove]);

  const handleActivate = useCallback(async () => {
    if (!recipe) return;
    setMode('menu');
    setActionLoading(true);
    try {
      const updated = await client.recipes.activateRecipe(recipe.id);
      setRecipe(updated);
      setSuccessMessage('Rezept wurde aktiviert.');
    } catch (err: unknown) {
      setError(errorMessage(err));
    }
    setActionLoading(false);
  }, [recipe]);

  const handleArchive = useCallback(async () => {
    if (!recipe) return;
    setMode('menu');
    setActionLoading(true);
    try {
      const updated = await client.recipes.archiveRecipe(recipe.id);
      setRecipe(updated);
      setSuccessMessage('Rezept wurde archiviert.');
    } catch (err: unknown) {
      setError(errorMessage(err));
    }
    setActionLoading(false);
  }, [recipe]);

  if (loading) return <LoadingSpinner label="Lade Rezept..." />;
  if (error && !recipe) return <ErrorDisplay message={error} onDismiss={back} />;
  if (!recipe) return <Text color="red">Rezept nicht gefunden.</Text>;

  const typeName = RECIPE_TYPE_LABELS[recipe.type as RecipeType] ?? recipe.type;

  return (
    <Box flexDirection="column" gap={1}>
      <Text color="cyan" bold>Rezept: {recipe.name}</Text>

      {error && <ErrorDisplay message={error} onDismiss={() => setError(null)} />}
      {successMessage && <SuccessDisplay message={successMessage} onDismiss={() => setSuccessMessage(null)} />}

      <Box flexDirection="column" borderStyle="round" borderColor="gray" paddingX={2} paddingY={1}>
        <Box gap={2}>
          <Text color="gray">Status:</Text>
          <Text bold>{recipe.status}</Text>
        </Box>
        <Box gap={2}>
          <Text color="gray">Typ:</Text>
          <Text>{typeName}</Text>
        </Box>
        <Box gap={2}>
          <Text color="gray">Version:</Text>
          <Text>{recipe.version}</Text>
        </Box>
        {recipe.description && (
          <Box gap={2}>
            <Text color="gray">Beschreibung:</Text>
            <Text>{recipe.description}</Text>
          </Box>
        )}
        <Box gap={2}>
          <Text color="gray">Ausbeute:</Text>
          <Text>{recipe.yieldPercentage}%</Text>
        </Box>
        {recipe.shelfLifeDays !== null && (
          <Box gap={2}>
            <Text color="gray">Haltbarkeit:</Text>
            <Text>{recipe.shelfLifeDays} Tage</Text>
          </Box>
        )}
        <Box gap={2}>
          <Text color="gray">Ausgabemenge:</Text>
          <Text>{recipe.outputQuantity} {recipe.outputUom}</Text>
        </Box>
        <Box gap={2}>
          <Text color="gray">Artikel:</Text>
          <Text>{articleMap[recipe.articleId] ?? recipe.articleId}</Text>
        </Box>

        {recipe.ingredients.length > 0 && (
          <Box flexDirection="column" marginTop={1}>
            <Text color="gray">Zutaten:</Text>
            {sortedIngredients.map((ing) => (
              <Box key={ing.id} paddingLeft={2} gap={1}>
                <Text color="yellow">{ing.position}.</Text>
                <Text>{ing.quantity} {ing.uom}</Text>
                <Text color="gray">– {articleMap[ing.articleId] ?? ing.articleId}</Text>
                {ing.subRecipeId && <Text color="blue">[Rezept: {recipeMap[ing.subRecipeId] ?? ing.subRecipeId}]</Text>}
                {ing.substitutable && <Text color="green">[austauschbar]</Text>}
              </Box>
            ))}
          </Box>
        )}

        {sortedSteps.length > 0 && (
          <Box flexDirection="column" marginTop={1}>
            <Text color="gray">Produktionsschritte:</Text>
            {sortedSteps.map((step) => (
              <Box key={step.id} paddingLeft={2} gap={1}>
                <Text color="yellow">{step.stepNumber}.</Text>
                <Text>{step.description}</Text>
                {step.durationMinutes != null && <Text color="gray">({step.durationMinutes} min)</Text>}
                {step.temperatureCelsius != null && <Text color="gray">[{step.temperatureCelsius}°C]</Text>}
              </Box>
            ))}
          </Box>
        )}
      </Box>

      {mode === 'reorder-ingredient' && (
        <Box flexDirection="column">
          <Text color="yellow" bold>Zutaten neu anordnen:</Text>
          {reorderList.map((ing, index) => {
            const isCursor = index === reorderCursor;
            const isHeld = index === reorderHeld;
            const prefix = isHeld ? '[*] ' : isCursor ? ' ▶  ' : '    ';
            return (
              <Box key={`${ing.id}-${index}`}>
                <Text color={isCursor ? 'cyan' : isHeld ? 'yellow' : 'white'}>
                  {prefix}{index + 1}. {ing.quantity} {ing.uom} – {articleMap[ing.articleId] ?? ing.articleId}
                </Text>
              </Box>
            );
          })}
          <Text color="gray" dimColor>↑↓ bewegen · Space greifen/loslassen · Enter speichern · Escape abbrechen</Text>
        </Box>
      )}

      {mode === 'select-step-to-remove' && (
        <Box flexDirection="column">
          <Text color="yellow" bold>Schritt zum Entfernen auswählen:</Text>
          {sortedSteps.map((step, index) => (
            <Box key={step.id}>
              <Text color={index === selectedStepIndex ? 'cyan' : 'white'}>
                {index === selectedStepIndex ? '▶ ' : '  '}Schritt {step.stepNumber}: {step.description}
              </Text>
            </Box>
          ))}
          <Text color="gray" dimColor>↑↓ auswählen · Enter bestätigen · Escape abbrechen</Text>
        </Box>
      )}

      {mode === 'select-ingredient-to-remove' && (
        <Box flexDirection="column">
          <Text color="yellow" bold>Zutat zum Entfernen auswählen:</Text>
          {sortedIngredients.map((ing, index) => (
            <Box key={ing.id}>
              <Text color={index === selectedIngredientIndex ? 'cyan' : 'white'}>
                {index === selectedIngredientIndex ? '▶ ' : '  '}Position {ing.position}: {ing.quantity} {ing.uom} – {articleMap[ing.articleId] ?? ing.articleId}
              </Text>
            </Box>
          ))}
          <Text color="gray" dimColor>↑↓ auswählen · Enter bestätigen · Escape abbrechen</Text>
        </Box>
      )}

      {mode === 'confirm-remove-ingredient' && ingredientToRemove && (
        <ConfirmDialog
          message={`Zutat an Position ${ingredientToRemove.position} (${articleMap[ingredientToRemove.articleId] ?? ingredientToRemove.articleId}) entfernen?`}
          onConfirm={() => void handleRemoveIngredient()}
          onCancel={() => { setMode('menu'); setIngredientToRemove(null); }}
        />
      )}

      {mode === 'confirm-remove' && stepToRemove && (
        <ConfirmDialog
          message={`Schritt ${stepToRemove.stepNumber} "${stepToRemove.description}" entfernen?`}
          onConfirm={() => void handleRemoveStep()}
          onCancel={() => { setMode('menu'); setStepToRemove(null); }}
        />
      )}

      {mode === 'confirm-activate' && (
        <ConfirmDialog
          message="Rezept wirklich aktivieren? Der Status wechselt zu ACTIVE."
          onConfirm={() => void handleActivate()}
          onCancel={() => setMode('menu')}
        />
      )}

      {mode === 'confirm-archive' && (
        <ConfirmDialog
          message="Rezept wirklich archivieren? Der Status wechselt zu ARCHIVED."
          onConfirm={() => void handleArchive()}
          onCancel={() => setMode('menu')}
        />
      )}

      {mode === 'menu' && (
        <Box flexDirection="column">
          <Text color="gray" bold>Aktionen:</Text>
          {actionLoading && <LoadingSpinner label="Aktion wird ausgeführt..." />}
          {!actionLoading && menuItems.map((item, index) => (
            <Box key={item.id}>
              <Text color={index === clampedAction ? 'cyan' : 'white'}>
                {index === clampedAction ? '▶ ' : '  '}{item.label}
              </Text>
            </Box>
          ))}
        </Box>
      )}

      <Box marginTop={1}>
        <Text color="gray" dimColor>↑↓ navigieren · Enter ausführen · Backspace Zurück</Text>
      </Box>
    </Box>
  );
}

function sortedIngredientsOf(recipe: RecipeDTO | null): IngredientDTO[] {
  if (!recipe?.ingredients) return [];
  return [...recipe.ingredients].sort((a, b) => a.position - b.position);
}
