<script lang="ts">
  import { untrack } from 'svelte';
  import { Plus } from 'lucide-svelte';
  import type { Recipe, Ingredient, Step } from '$lib/types';
  import ImageUploadBox from '$lib/components/ImageUploadBox.svelte';
  import IngredientRow from '$lib/components/IngredientRow.svelte';
  import StepList from '$lib/components/StepList.svelte';
  import type { DraftIng, DraftStep } from '$lib/components/recipe-editor-types';

  type Props = {
    recipe: Recipe;
    saving?: boolean;
    onsave: (patch: {
      title: string;
      description: string | null;
      servings_default: number | null;
      prep_time_min: number | null;
      cook_time_min: number | null;
      total_time_min: number | null;
      ingredients: Ingredient[];
      steps: Step[];
    }) => void | Promise<void>;
    oncancel: () => void;
    /** Fires whenever the image was uploaded or removed — separate from save,
     *  because the image is its own endpoint and persists immediately. */
    onimagechange?: (image_path: string | null) => void;
  };

  let { recipe, saving = false, onsave, oncancel, onimagechange }: Props = $props();

  // Form-lokaler Zustand: Initialwerte aus dem Prop snapshotten (untrack),
  // damit User-Edits nicht von prop-Updates ueberschrieben werden.
  let title = $state(untrack(() => recipe.title));
  let description = $state(untrack(() => recipe.description ?? ''));
  let servings = $state<number | ''>(untrack(() => recipe.servings_default ?? ''));
  let prepMin = $state<number | ''>(untrack(() => recipe.prep_time_min ?? ''));
  let cookMin = $state<number | ''>(untrack(() => recipe.cook_time_min ?? ''));
  let totalMin = $state<number | ''>(untrack(() => recipe.total_time_min ?? ''));

  let ingredients = $state<DraftIng[]>(
    untrack(() =>
      recipe.ingredients.map((i) => ({
        qty: i.quantity !== null ? String(i.quantity).replace('.', ',') : '',
        unit: i.unit ?? '',
        name: i.name,
        note: i.note ?? '',
        section_heading: i.section_heading
      }))
    )
  );
  let steps = $state<DraftStep[]>(
    untrack(() => recipe.steps.map((s) => ({ text: s.text })))
  );

  function addIngredient() {
    ingredients = [...ingredients, { qty: '', unit: '', name: '', note: '', section_heading: null }];
  }
  function removeIngredient(idx: number) {
    ingredients = ingredients.filter((_, i) => i !== idx);
  }
  function moveIngredient(idx: number, dir: -1 | 1) {
    const target = idx + dir;
    if (target < 0 || target >= ingredients.length) return;
    const next = [...ingredients];
    [next[idx], next[target]] = [next[target], next[idx]];
    ingredients = next;
  }
  function addSection(idx: number) {
    const next = [...ingredients];
    next[idx] = { ...next[idx], section_heading: '' };
    ingredients = next;
  }
  function removeSection(idx: number) {
    const next = [...ingredients];
    next[idx] = { ...next[idx], section_heading: null };
    ingredients = next;
  }
  function addStep() {
    steps = [...steps, { text: '' }];
  }
  function removeStep(idx: number) {
    steps = steps.filter((_, i) => i !== idx);
  }

  function parseQty(raw: string): number | null {
    const cleaned = raw.trim().replace(',', '.');
    if (!cleaned) return null;
    const n = Number(cleaned);
    return Number.isFinite(n) ? n : null;
  }

  function toNumOrNull(v: number | ''): number | null {
    return v === '' ? null : v;
  }

  async function save() {
    const cleanedIngredients: Ingredient[] = ingredients
      .filter((i) => i.name.trim())
      .map((i, idx) => {
        const qty = parseQty(i.qty);
        const unit = i.unit.trim() || null;
        const name = i.name.trim();
        const note = i.note.trim() || null;
        const rawParts: string[] = [];
        if (qty !== null) rawParts.push(String(qty).replace('.', ','));
        if (unit) rawParts.push(unit);
        rawParts.push(name);
        const heading = i.section_heading === null ? null : (i.section_heading.trim() || null);
        return {
          position: idx + 1,
          quantity: qty,
          unit,
          name,
          note,
          raw_text: rawParts.join(' '),
          section_heading: heading
        };
      });
    const cleanedSteps: Step[] = steps
      .filter((s) => s.text.trim())
      .map((s, idx) => ({ position: idx + 1, text: s.text.trim() }));

    await onsave({
      title: title.trim() || recipe.title,
      description: description.trim() || null,
      servings_default: toNumOrNull(servings),
      prep_time_min: toNumOrNull(prepMin),
      cook_time_min: toNumOrNull(cookMin),
      total_time_min: toNumOrNull(totalMin),
      ingredients: cleanedIngredients,
      steps: cleanedSteps
    });
  }
</script>

<div class="editor">
  <section class="block">
    <h2>Bild</h2>
    <ImageUploadBox
      recipeId={recipe.id!}
      imagePath={recipe.image_path}
      onchange={(p) => onimagechange?.(p)}
    />
  </section>

  <div class="meta">
    <label class="field">
      <span class="lbl">Titel</span>
      <input type="text" bind:value={title} placeholder="Rezeptname" />
    </label>
    <label class="field">
      <span class="lbl">Beschreibung</span>
      <textarea bind:value={description} rows="2" placeholder="Kurze Beschreibung (optional)"></textarea>
    </label>
    <div class="row">
      <label class="field small">
        <span class="lbl">Portionen</span>
        <input
          type="number"
          min="1"
          bind:value={servings}
          placeholder="—"
        />
      </label>
      <label class="field small">
        <span class="lbl">Vorb. (min)</span>
        <input type="number" min="0" bind:value={prepMin} placeholder="—" />
      </label>
      <label class="field small">
        <span class="lbl">Kochen (min)</span>
        <input type="number" min="0" bind:value={cookMin} placeholder="—" />
      </label>
      <label class="field small">
        <span class="lbl">Gesamt (min)</span>
        <input type="number" min="0" bind:value={totalMin} placeholder="—" />
      </label>
    </div>
  </div>

  <section class="block">
    <h2>Zutaten</h2>
    <ul class="ing-list">
      {#each ingredients as ing, idx (idx)}
        <IngredientRow
          {ing}
          {idx}
          total={ingredients.length}
          onmove={(dir) => moveIngredient(idx, dir)}
          onremove={() => removeIngredient(idx)}
          onaddSection={() => addSection(idx)}
          onremoveSection={() => removeSection(idx)}
        />
      {/each}
    </ul>
    <button class="add" type="button" onclick={addIngredient}>
      <Plus size={16} strokeWidth={2} />
      <span>Zutat hinzufügen</span>
    </button>
  </section>

  <section class="block">
    <h2>Zubereitung</h2>
    <StepList {steps} onadd={addStep} onremove={removeStep} />
  </section>

  <div class="foot">
    <button class="btn ghost" type="button" onclick={oncancel} disabled={saving}>
      Abbrechen
    </button>
    <button class="btn primary" type="button" onclick={save} disabled={saving}>
      {saving ? 'Speichere …' : 'Speichern'}
    </button>
  </div>
</div>

<style>
  .editor {
    display: flex;
    flex-direction: column;
    gap: 1rem;
  }
  .meta {
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
    background: white;
    border: 1px solid #e4eae7;
    border-radius: 12px;
    padding: 1rem;
  }
  .field {
    display: flex;
    flex-direction: column;
    gap: 0.3rem;
  }
  .lbl {
    font-size: 0.8rem;
    color: #666;
    font-weight: 600;
  }
  .field input,
  .field textarea {
    padding: 0.55rem 0.7rem;
    font-size: 0.95rem;
    border: 1px solid #cfd9d1;
    border-radius: 8px;
    font-family: inherit;
    background: white;
    min-height: 40px;
  }
  .field textarea {
    resize: vertical;
  }
  .row {
    display: flex;
    gap: 0.5rem;
    flex-wrap: wrap;
  }
  .small {
    flex: 1;
    min-width: 100px;
  }
  .block {
    background: white;
    border: 1px solid #e4eae7;
    border-radius: 12px;
    padding: 1rem;
  }
  .block h2 {
    font-size: 1.05rem;
    margin: 0 0 0.75rem;
    color: #2b6a3d;
  }
  .ing-list {
    list-style: none;
    padding: 0;
    margin: 0 0 0.6rem;
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
  }
  .add {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    padding: 0.55rem 0.9rem;
    border: 1px dashed #cfd9d1;
    background: white;
    color: #2b6a3d;
    border-radius: 8px;
    cursor: pointer;
    font-size: 0.9rem;
    font-family: inherit;
  }
  .add:hover {
    background: #f4f8f5;
  }
  .foot {
    display: flex;
    justify-content: space-between;
    gap: 0.5rem;
    padding-top: 0.5rem;
  }
  .btn {
    padding: 0.7rem 1.25rem;
    border-radius: 10px;
    border: 1px solid #cfd9d1;
    background: white;
    cursor: pointer;
    font-family: inherit;
    font-size: 0.95rem;
    min-height: 44px;
  }
  .btn.ghost {
    color: #666;
  }
  .btn.primary {
    background: #2b6a3d;
    color: white;
    border-color: #2b6a3d;
    font-weight: 600;
  }
  .btn:disabled {
    opacity: 0.6;
    cursor: progress;
  }
</style>
