import { useCallback, useEffect, useState } from 'react';
import { Box, Text, useInput } from 'ink';
import { useNavigation } from '../../state/navigation-context.js';
import { FormInput } from '../shared/FormInput.js';
import { ArticlePicker } from '../shared/ArticlePicker.js';
import { LoadingSpinner } from '../shared/LoadingSpinner.js';
import { ErrorDisplay } from '../shared/ErrorDisplay.js';
import { useArticles } from '../../hooks/useArticles.js';
import { UOM_VALUES, UOM_LABELS } from '@effigenix/api-client';
import type { UoM, RecipeDTO, ArticleDTO } from '@effigenix/api-client';
import { client } from '../../utils/api-client.js';

type Field = 'articleId' | 'quantity' | 'uom' | 'subRecipeId' | 'substitutable';
const FIELDS: Field[] = ['articleId', 'quantity', 'uom', 'subRecipeId', 'substitutable'];

const FIELD_LABELS: Record<Field, string> = {
  articleId: 'Artikel *',
  quantity: 'Menge *',
  uom: 'Einheit * (←→ wechseln)',
  subRecipeId: 'Sub-Rezept-ID (optional)',
  substitutable: 'Austauschbar (ja/nein, optional)',
};

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

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

  const { articles, fetchArticles } = useArticles();

  const [recipe, setRecipe] = useState<RecipeDTO | null>(null);
  const [recipeLoading, setRecipeLoading] = useState(true);
  const [values, setValues] = useState({
    quantity: '',
    subRecipeId: '',
    substitutable: '',
  });
  const [uomIdx, setUomIdx] = useState(0);
  const [articleQuery, setArticleQuery] = useState('');
  const [selectedArticle, setSelectedArticle] = useState<{ id: string; name: string; articleNumber: string } | null>(null);
  const [activeField, setActiveField] = useState<Field>('articleId');
  const [fieldErrors, setFieldErrors] = useState<Partial<Record<Field, string>>>({});
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);

  useEffect(() => {
    if (!recipeId) return;
    void fetchArticles();
    client.recipes.getById(recipeId)
      .then((r) => { setRecipe(r); setRecipeLoading(false); })
      .catch((err: unknown) => { setError(errorMessage(err)); setRecipeLoading(false); });
  }, [recipeId, fetchArticles]);

  const setField = (field: 'quantity' | 'subRecipeId' | 'substitutable') => (value: string) => {
    setValues((v) => ({ ...v, [field]: value }));
  };

  const handleArticleSelect = useCallback((article: ArticleDTO) => {
    setSelectedArticle({ id: article.id, name: article.name, articleNumber: article.articleNumber });
    setArticleQuery('');
    setActiveField('quantity');

    void client.recipes.list().then((recipes) => {
      const linked = recipes.find((r) => r.articleId === article.id && r.status === 'ACTIVE')
        ?? recipes.find((r) => r.articleId === article.id);
      if (linked) {
        setValues((v) => ({ ...v, subRecipeId: linked.id }));
      }
    }).catch(() => { /* Rezept-Lookup fehlgeschlagen – subRecipeId bleibt leer */ });
  }, []);

  const handleSubmit = async () => {
    const errors: Partial<Record<Field, string>> = {};
    if (!selectedArticle) errors.articleId = 'Artikel ist erforderlich.';
    if (!values.quantity.trim()) errors.quantity = 'Menge ist erforderlich.';
    if (values.quantity.trim() && isNaN(Number(values.quantity))) errors.quantity = 'Muss eine Zahl sein.';
    if (values.substitutable.trim() && !['ja', 'nein'].includes(values.substitutable.trim().toLowerCase())) {
      errors.substitutable = 'Muss "ja" oder "nein" sein.';
    }
    setFieldErrors(errors);
    if (Object.keys(errors).length > 0) return;

    const maxPosition = recipe?.ingredients?.length
      ? Math.max(...recipe.ingredients.map((i) => i.position))
      : 0;

    const selectedUom = UOM_VALUES[uomIdx] as UoM;

    setLoading(true);
    setError(null);
    try {
      await client.recipes.addIngredient(recipeId, {
        articleId: selectedArticle!.id,
        quantity: values.quantity.trim(),
        uom: selectedUom,
        position: maxPosition + 1,
        ...(values.subRecipeId.trim() ? { subRecipeId: values.subRecipeId.trim() } : {}),
        ...(values.substitutable.trim() ? { substitutable: values.substitutable.trim().toLowerCase() === 'ja' } : {}),
      });
      replace('recipe-detail', { recipeId });
    } catch (err: unknown) {
      setError(errorMessage(err));
      setLoading(false);
    }
  };

  const handleFieldSubmit = (field: Field) => (_value: string) => {
    const idx = FIELDS.indexOf(field);
    if (idx < FIELDS.length - 1) {
      setActiveField(FIELDS[idx + 1] ?? field);
    } else {
      void handleSubmit();
    }
  };

  useInput((_input, key) => {
    if (loading || recipeLoading) return;
    if (activeField === 'articleId') return;

    if (activeField === 'uom') {
      if (key.leftArrow || key.rightArrow) {
        const dir = key.rightArrow ? 1 : -1;
        setUomIdx((i) => (i + dir + UOM_VALUES.length) % UOM_VALUES.length);
        return;
      }
      if (key.return) {
        handleFieldSubmit('uom')('');
        return;
      }
    }

    if (key.tab || key.downArrow) {
      setActiveField((f) => {
        const idx = FIELDS.indexOf(f);
        return FIELDS[(idx + 1) % FIELDS.length] ?? f;
      });
    }
    if (key.upArrow) {
      setActiveField((f) => {
        const idx = FIELDS.indexOf(f);
        return FIELDS[(idx - 1 + FIELDS.length) % FIELDS.length] ?? f;
      });
    }
    if (key.escape) back();
  });

  if (!recipeId) return <ErrorDisplay message="Keine Rezept-ID vorhanden." onDismiss={back} />;
  if (recipeLoading) return <Box paddingY={2}><LoadingSpinner label="Lade Rezept..." /></Box>;
  if (loading) return <Box paddingY={2}><LoadingSpinner label="Zutat wird hinzugefügt..." /></Box>;

  const uomLabel = UOM_LABELS[UOM_VALUES[uomIdx] as UoM] ?? UOM_VALUES[uomIdx];
  const selectedName = selectedArticle ? `${selectedArticle.name} (${selectedArticle.articleNumber})` : undefined;

  return (
    <Box flexDirection="column" gap={1}>
      <Text color="cyan" bold>Zutat hinzufügen</Text>
      {error && <ErrorDisplay message={error} onDismiss={() => setError(null)} />}

      <Box flexDirection="column" gap={1} width={60}>
        {FIELDS.map((field) => {
          if (field === 'articleId') {
            return (
              <Box key={field} flexDirection="column">
                <ArticlePicker
                  articles={articles}
                  query={articleQuery}
                  onQueryChange={setArticleQuery}
                  onSelect={handleArticleSelect}
                  focus={activeField === 'articleId'}
                  {...(selectedName ? { selectedName } : {})}
                />
                {fieldErrors.articleId && <Text color="red">⚠ {fieldErrors.articleId}</Text>}
              </Box>
            );
          }
          if (field === 'uom') {
            return (
              <Box key={field} flexDirection="column">
                <Text color={activeField === field ? 'cyan' : 'gray'}>
                  {FIELD_LABELS[field]}: <Text bold color="white">{activeField === field ? `< ${uomLabel} >` : uomLabel}</Text>
                </Text>
              </Box>
            );
          }
          const textField = field as 'quantity' | 'subRecipeId' | 'substitutable';
          return (
            <FormInput
              key={field}
              label={FIELD_LABELS[field]}
              value={values[textField]}
              onChange={setField(textField)}
              onSubmit={handleFieldSubmit(field)}
              focus={activeField === field}
              {...(fieldErrors[field] ? { error: fieldErrors[field] } : {})}
            />
          );
        })}
      </Box>

      <Box marginTop={1}>
        <Text color="gray" dimColor>
          Tab/↑↓ Feld wechseln · ←→ Einheit · Artikelsuche tippen · Enter auf letztem Feld speichern · Escape Abbrechen
        </Text>
      </Box>
    </Box>
  );
}
