<script>
  // App.svelte — Root component with conditional view switching (no router library).
  // Date navigation: previous/next day button + current date display.
  // Scan flow per §4.1: local DB check → confirm+log OR OFF lookup → FoodEditor → log.
  // Dates are YYYY-MM-DD strings end-to-end (spec §8.3 rule 4).

  import { onMount } from 'svelte'
  import { api } from './lib/api.js'
  import {
    currentDate, appView, goPrevDay, goNextDay, setDate,
    navigateTo, addLogEntryToStore, refreshDayData, mealEdit
  } from './lib/stores.svelte.js'
  import { formatDate, formatKcal, defaultQuantity, previewCalories } from './lib/format.js'
  import Dashboard from './components/Dashboard.svelte'
  import FoodSearch from './components/FoodSearch.svelte'
  import FoodEditor from './components/FoodEditor.svelte'
  import FoodLibrary from './components/FoodLibrary.svelte'
  import BarcodeScanner from './components/BarcodeScanner.svelte'

  // Health check — every async view handles loading/error states (spec §8.2 rule 4)
  let backend = $state({ loading: true, ok: false, error: null })

  onMount(async () => {
    try {
      await api.health()
      backend = { loading: false, ok: true, error: null }
    } catch (e) {
      backend = { loading: false, ok: false, error: e.message }
    }
  })

  // ── Target form state ──────────────────────────────────────────────────────
  let targetCalories = $state('2000')
  let targetProtein = $state('')
  let targetCarbs = $state('')
  let targetFat = $state('')
  let targetStartDate = $state(currentDate.value)
  let targetSaving = $state(false)
  let targetError = $state(null)
  let targetSuccess = $state(false)

  function openTargetForm() {
    targetStartDate = currentDate.value
    targetSuccess = false
    targetError = null
    appView.current = 'targetForm'
  }

  async function saveTarget(e) {
    e.preventDefault()
    const cal = parseInt(targetCalories)
    if (isNaN(cal) || cal <= 0) { targetError = 'Calories must be a positive number'; return }

    targetSaving = true
    targetError = null
    try {
      await api.createTarget({
        start_date: targetStartDate,
        calories: cal,
        protein_g: targetProtein ? parseFloat(targetProtein) : null,
        carbs_g: targetCarbs ? parseFloat(targetCarbs) : null,
        fat_g: targetFat ? parseFloat(targetFat) : null,
      })
      targetSuccess = true
      setTimeout(() => {
        appView.current = 'dashboard'
        targetSuccess = false
      }, 800)
    } catch (e) {
      targetError = e.message
    } finally {
      targetSaving = false
    }
  }

  // ── Scan flow state (§4.1) ─────────────────────────────────────────────────
  // Phases: null (not scanning), 'localFound', 'localConfirm', 'offFound', 'notFound', 'error'
  let scanPhase = $state(null)
  let scanBarcode = $state('')
  let scanLoading = $state(false)
  let scanError = $state(null)
  // Data from API
  let localFood = $state(null)      // FoodRead if found locally
  let offFood = $state(null)         // Normalized OFF food dict
  // Logging state
  let scanLogQuantity = $state(1)
  let scanLogMealSlot = $state('')
  let scanLogging = $state(false)
  let scanLogError = $state(null)
  let scanLiveKcal = $derived(localFood ? Math.round(previewCalories(localFood, scanLogQuantity)) : 0)
  let refreshing = $state(false)

  const SLOTS = ['', 'breakfast', 'lunch', 'dinner', 'snack']

  function resetScanFlow() {
    scanPhase = null
    scanBarcode = ''
    scanLoading = false
    scanError = null
    localFood = null
    offFood = null
    scanLogQuantity = 1
    scanLogMealSlot = ''
    scanLogging = false
    scanLogError = null
    refreshing = false
  }

  async function handleBarcode(barcode) {
    console.log('[App] handleBarcode:', barcode)
    resetScanFlow()
    scanBarcode = barcode
    scanLoading = true

    // Step 1: Check local DB by barcode
    try {
      console.log('[App] searching local DB for barcode:', barcode)
      const results = await api.searchFoodsByBarcode(barcode)
      console.log('[App] local search results:', results?.length ?? 0)
      if (results && results.length > 0) {
        localFood = results[0]
        scanLogQuantity = defaultQuantity(localFood)
        scanLoading = false
        scanPhase = 'localFound'
        console.log('[App] local food found:', localFood.name)
        return
      }
      console.log('[App] not found locally, trying OpenFoodFacts…')
    } catch (e) {
      console.warn('[App] local search failed:', e)
      // Local lookup failed — try OFF anyway
    }

    // Step 2: Not found locally → try OFF
    try {
      console.log('[App] fetching OFF product:', barcode)
      offFood = await api.offProduct(barcode)
      scanLoading = false
      scanPhase = 'offFound'
      console.log('[App] OFF product found:', offFood?.product_name ?? offFood?.name)
    } catch (e) {
      console.warn('[App] OFF lookup failed:', e.message)
      // OFF miss (404) or network error
      scanLoading = false
      if (e.message?.includes('404') || e.message?.includes('not found')) {
        scanPhase = 'notFound'
        console.log('[App] OFF product not found (404)')
      } else {
        scanError = e.message
        scanPhase = 'error'
        console.error('[App] OFF lookup error:', e.message)
      }
    }
  }

  async function confirmLocalLog() {
    if (!localFood || scanLogQuantity <= 0) return
    scanLogging = true
    scanLogError = null
    try {
      const entry = await api.addLogEntry({
        food_id: localFood.id,
        quantity: parseFloat(scanLogQuantity),
        meal_slot: scanLogMealSlot || null,
        date: currentDate.value,
      })
      await addLogEntryToStore(entry)
      resetScanFlow()
      appView.current = 'dashboard'
    } catch (e) {
      scanLogError = e.message
    } finally {
      scanLogging = false
    }
  }

  async function refreshFromOff() {
    if (!localFood) return
    refreshing = true
    try {
      const updated = await api.offRefresh(localFood.id)
      localFood = updated
      scanLogQuantity = defaultQuantity(updated)
    } catch (e) {
      scanError = e.message
    } finally {
      refreshing = false
    }
  }

  function handleOffSaved(savedFood) {
    // FoodEditor called onSaved after creating food from OFF data
    // Now offer to log it
    localFood = savedFood
    offFood = null
    scanLogQuantity = defaultQuantity(savedFood)
    scanPhase = 'localFound'
  }

  function backToScan() {
    resetScanFlow()
  }

  function backToDashboard() {
    resetScanFlow()
    appView.current = 'dashboard'
  }

  // ── Date navigation ───────────────────────────────────────────────────────
  function handleDateInput(e) {
    setDate(e.target.value)
  }
</script>

<main>
  <h1>CalCount</h1>

  {#if backend.loading}
    <p class="status">Connecting to backend…</p>
  {:else if backend.error}
    <p class="status err" role="alert">Backend unreachable: {backend.error}</p>
  {:else}
    {#if appView.current === 'dashboard' || appView.current === 'addFood' || appView.current === 'createFood' || appView.current === 'targetForm'}
      <!-- Date navigation (always visible except on target form or when not relevant) -->
      <nav class="date-nav">
        <button type="button" class="nav-btn" onclick={goPrevDay} title="Previous day">←</button>
        <input
          type="date"
          value={currentDate.value}
          onchange={handleDateInput}
          class="date-input"
        />
        <button type="button" class="nav-btn" onclick={goNextDay} title="Next day">→</button>
        <span class="date-display">{formatDate(currentDate.value)}</span>
      </nav>
    {/if}

    {#if appView.current === 'dashboard'}
      <Dashboard date={currentDate.value} />

      <div class="fab-container">
        <button type="button" class="fab" onclick={() => appView.current = 'addFood'}>
          + Add Food
        </button>
        <button type="button" class="fab scan-fab" onclick={() => { resetScanFlow(); appView.current = 'scan' }}>
          📷 Scan
        </button>
        <button type="button" class="target-btn" onclick={() => appView.current = 'foods'}>
          🍔 Foods
        </button>
        <button type="button" class="target-btn" onclick={openTargetForm}>
          🎯 Target
        </button>
      </div>

    {:else if appView.current === 'scan'}
      <!-- Scan view — BarcodeScanner → scan flow -->
      {#if !scanPhase}
        <button type="button" class="back-btn" onclick={backToDashboard}>← Dashboard</button>
        <BarcodeScanner onBarcode={handleBarcode} />

      {:else if scanLoading}
        <div class="scan-status-card">
          <button type="button" class="back-btn" onclick={backToScan}>← Scan again</button>
          <p class="status">Looking up barcode {scanBarcode}…</p>
        </div>

      {:else if scanPhase === 'localFound'}
        <!-- Local food found → confirm and log -->
        <div class="scan-status-card">
          <button type="button" class="back-btn" onclick={backToScan}>← Scan again</button>
          <h3>Found: {localFood.name}</h3>
          {#if localFood.brand}<p class="scan-brand">{localFood.brand}</p>{/if}
          <p class="scan-kcal">{formatKcal(localFood.calories_per_unit)}/{localFood.unit_type === 'count' ? 'item' : '100g'}</p>

          <div class="log-form">
            <label>
              Quantity
              <input
                type="number"
                step="any"
                min="0.1"
                bind:value={scanLogQuantity}
                class="qty-input"
              />
              {localFood.unit_type === 'count' ? 'items' : 'g'}
            </label>
            <p class="preview-kcal">= {formatKcal(scanLiveKcal)}</p>

            <label>
              Meal slot
              <select bind:value={scanLogMealSlot}>
                {#each SLOTS as s}
                  <option value={s}>{s || '(none)'}</option>
                {/each}
              </select>
            </label>

            {#if scanLogError}<p class="err" role="alert">{scanLogError}</p>{/if}
            {#if scanError}<p class="err" role="alert">{scanError}</p>{/if}

            <div class="log-actions">
              <button type="button" onclick={confirmLocalLog} disabled={scanLogging || scanLogQuantity <= 0}>
                {scanLogging ? 'Logging…' : 'Log it'}
              </button>
            </div>

            {#if localFood.source === 'openfoodfacts' || localFood.barcode}
              <div class="refresh-section">
                <p class="refresh-hint">Data from {localFood.source === 'openfoodfacts' ? 'OpenFoodFacts' : 'local'}. Refresh for latest?</p>
                <button type="button" class="secondary" onclick={refreshFromOff} disabled={refreshing}>
                  {refreshing ? 'Refreshing…' : 'Refresh from OpenFoodFacts'}
                </button>
              </div>
            {/if}
          </div>
        </div>

      {:else if scanPhase === 'offFound'}
        <!-- OFF product found → pre-fill FoodEditor -->
        <div class="scan-status-card">
          <button type="button" class="back-btn" onclick={backToScan}>← Scan again</button>
          <h3>Found on OpenFoodFacts</h3>
          <FoodEditor food={offFood} onSaved={handleOffSaved} onCancel={backToScan} />
        </div>

      {:else if scanPhase === 'notFound'}
        <div class="scan-status-card">
          <button type="button" class="back-btn" onclick={backToScan}>← Scan again</button>
          <h3>Not found</h3>
          <p class="status">Barcode "{scanBarcode}" was not found locally or on OpenFoodFacts.</p>
          <div class="not-found-actions">
            <button type="button" onclick={() => { resetScanFlow(); appView.current = 'createFood' }}>
              Create food manually
            </button>
            <button type="button" onclick={() => { resetScanFlow(); appView.current = 'addFood' }}>
              Search foods
            </button>
          </div>
        </div>

      {:else if scanPhase === 'error'}
        <div class="scan-status-card">
          <button type="button" class="back-btn" onclick={backToScan}>← Scan again</button>
          <p class="err" role="alert">Lookup error: {scanError}</p>
        </div>
      {/if}

    {:else if appView.current === 'addFood'}
      <FoodSearch />

    {:else if appView.current === 'createFood'}
      <FoodEditor />

    {:else if appView.current === 'foods'}
      <FoodLibrary />

    {:else if appView.current === 'editMeal'}
      <FoodEditor mealId={mealEdit.foodId} />

    {:else if appView.current === 'targetForm'}
      <div class="target-form-view">
        <button type="button" class="back-btn" onclick={() => appView.current = 'dashboard'}>← Back</button>
        <h3>Set daily target</h3>

        {#if targetSuccess}
          <p class="success">Target saved!</p>
        {:else}
          <form onsubmit={saveTarget}>
            <label>
              Calorie goal <span class="required">*</span>
              <input type="number" min="1" bind:value={targetCalories} required />
            </label>

            <label>
              Start date
              <input type="date" bind:value={targetStartDate} />
            </label>

            <fieldset>
              <legend>Macros (optional, grams)</legend>
              <div class="macro-grid">
                <label>
                  Protein
                  <input type="number" step="any" min="0" bind:value={targetProtein} placeholder="g" />
                </label>
                <label>
                  Carbs
                  <input type="number" step="any" min="0" bind:value={targetCarbs} placeholder="g" />
                </label>
                <label>
                  Fat
                  <input type="number" step="any" min="0" bind:value={targetFat} placeholder="g" />
                </label>
              </div>
            </fieldset>

            {#if targetError}<p class="err" role="alert">{targetError}</p>{/if}

            <div class="form-actions">
              <button type="submit" disabled={targetSaving}>
                {targetSaving ? 'Saving…' : 'Save target'}
              </button>
              <button type="button" class="secondary" onclick={() => appView.current = 'dashboard'}>
                Cancel
              </button>
            </div>
          </form>
        {/if}
      </div>
    {/if}
  {/if}
</main>

<style>
  main {
    max-width: 32rem;
    margin: 0 auto;
    padding: 1rem;
    font-family: system-ui, sans-serif;
    /* mobile-first single column */
  }

  h1 {
    font-size: 1.25rem;
    margin: 0 0 0.75rem;
  }

  .status { font-size: 0.9rem; color: var(--text-muted, #6b7280); }
  .status.err { color: #dc2626; }

  .back-btn {
    background: none;
    border: none;
    color: var(--link, #2563eb);
    cursor: pointer;
    font: inherit;
    font-size: 0.9rem;
    padding: 0;
    margin-bottom: 0.75rem;
  }

  /* ── Date navigation ─────────────────────────────────────────────── */
  .date-nav {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    margin-bottom: 0.75rem;
  }
  .nav-btn {
    background: var(--bg-muted, #f3f4f6);
    border: 1px solid var(--border, #d1d5db);
    border-radius: 0.35rem;
    padding: 0.35rem 0.6rem;
    cursor: pointer;
    font-size: 1rem;
    line-height: 1;
  }
  .date-input {
    padding: 0.35rem 0.5rem;
    font: inherit;
    border: 1px solid var(--border, #d1d5db);
    border-radius: 0.35rem;
  }
  .date-display {
    font-size: 0.9rem;
    color: var(--text-muted, #6b7280);
    margin-left: 0.3rem;
  }

  /* ── FAB / action buttons ────────────────────────────────────────── */
  .fab-container {
    display: flex;
    gap: 0.5rem;
    margin-top: 1.5rem;
    justify-content: center;
  }
  .fab, .target-btn {
    padding: 0.6rem 1.2rem;
    border: 1px solid var(--border, #d1d5db);
    border-radius: 0.35rem;
    font: inherit;
    font-size: 0.95rem;
    cursor: pointer;
    background: var(--bg, #fff);
  }
  .fab {
    background: var(--link, #2563eb);
    color: #fff;
    border-color: var(--link, #2563eb);
    font-weight: 600;
  }
  .scan-fab {
    background: #7c3aed;
    border-color: #7c3aed;
  }

  /* ── Scan flow cards ─────────────────────────────────────────────── */
  .scan-status-card {
    /* common wrapper for scan phases */
  }
  .scan-brand { color: var(--text-muted, #6b7280); font-size: 0.9rem; }
  .scan-kcal { font-weight: 600; font-size: 1rem; margin: 0.5rem 0; }

  .log-form {
    display: flex;
    flex-direction: column;
    gap: 0.6rem;
    margin-top: 0.75rem;
  }
  .log-form label {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    font-size: 0.9rem;
  }
  .qty-input {
    width: 5rem;
    padding: 0.3rem 0.4rem;
    font: inherit;
    border: 1px solid var(--border, #d1d5db);
    border-radius: 0.35rem;
  }
  .preview-kcal {
    font-weight: 600;
    font-size: 1rem;
    margin: 0;
  }
  .log-actions { display: flex; gap: 0.4rem; margin-top: 0.5rem; }

  .refresh-section {
    margin-top: 0.75rem;
    padding-top: 0.75rem;
    border-top: 1px solid var(--border, #e5e7eb);
  }
  .refresh-hint {
    font-size: 0.8rem;
    color: var(--text-muted, #6b7280);
    margin: 0 0 0.4rem;
  }

  .not-found-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    margin-top: 1rem;
  }

  h3 { margin: 0 0 0.5rem; font-size: 1.1rem; }

  /* ── Target form ─────────────────────────────────────────────────── */
  .target-form-view {
    /* mobile-first single column */
  }
  form {
    display: flex;
    flex-direction: column;
    gap: 0.8rem;
  }
  label {
    display: flex;
    flex-direction: column;
    gap: 0.2rem;
    font-size: 0.9rem;
  }
  .required { color: #dc2626; }
  input[type="number"],
  input[type="date"] {
    padding: 0.4rem 0.6rem;
    font: inherit;
    border: 1px solid var(--border, #d1d5db);
    border-radius: 0.35rem;
  }
  fieldset {
    border: 1px solid var(--border, #e5e7eb);
    border-radius: 0.35rem;
    padding: 0.6rem 0.8rem;
  }
  legend {
    font-size: 0.85rem;
    font-weight: 600;
    color: var(--text-muted, #6b7280);
    padding: 0 0.3rem;
  }
  .macro-grid {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
  }
  .form-actions {
    display: flex;
    gap: 0.4rem;
    margin-top: 0.5rem;
  }
  button {
    padding: 0.5rem 1rem;
    border: 1px solid var(--border, #d1d5db);
    border-radius: 0.35rem;
    background: var(--bg, #fff);
    cursor: pointer;
    font: inherit;
    font-size: 0.9rem;
  }
  button:disabled { opacity: 0.5; cursor: default; }
  button.secondary { background: var(--bg-muted, #f3f4f6); }
  .err { color: #dc2626; font-size: 0.85rem; }
  .success { color: #16a34a; font-size: 1rem; font-weight: 600; }
  select {
    padding: 0.3rem 0.4rem;
    font: inherit;
    border: 1px solid var(--border, #d1d5db);
    border-radius: 0.35rem;
  }
</style>
