<script lang="ts">
  import { goto, invalidateAll } from '$app/navigation';
  import { api } from '$lib/api';
  import { clientSession } from '$lib/session';
  import { toast } from '$lib/toast';
  import type { Mix, MixIngredient, RawMaterial } from '$lib/types';

  type DraftIngredient = {
    id: number | null;
    raw_material_id: number | null;
    quantity_kg: number;
    notes: string;
  };

  let {
    rawMaterials,
    initialMix = null
  }: {
    rawMaterials: RawMaterial[];
    initialMix?: Mix | null;
  } = $props();
  const getInitialMix = () => initialMix;

  let savedMix = $state<Mix | null>(getInitialMix());
  let mixName = $state(getInitialMix()?.name ?? '');
  let clientName = $state(getInitialMix()?.client_name ?? '');
  let mixStatus = $state(getInitialMix()?.status ?? 'draft');
  let mixVersion = $state(getInitialMix()?.version ?? 1);
  let mixNotes = $state(getInitialMix()?.notes ?? '');
  let draftIngredients = $state<DraftIngredient[]>([]);
  let isSaving = $state(false);

  function currency(value: number | null | undefined, digits = 2) {
    if (value === null || value === undefined) {
      return 'N/A';
    }

    return `$${value.toFixed(digits)}`;
  }

  function findRawMaterial(rawMaterialId: number | null) {
    return rawMaterials.find((material) => material.id === rawMaterialId) ?? null;
  }

  function rowFromIngredient(ingredient: MixIngredient): DraftIngredient {
    return {
      id: ingredient.id,
      raw_material_id: ingredient.raw_material_id,
      quantity_kg: ingredient.quantity_kg,
      notes: ingredient.notes ?? ''
    };
  }

  function createEmptyIngredient(): DraftIngredient {
    return {
      id: null,
      raw_material_id: rawMaterials[0]?.id ?? null,
      quantity_kg: 0,
      notes: ''
    };
  }

  function loadDraftFromMix(mix: Mix | null) {
    if (!mix) {
      savedMix = null;
      mixName = '';
      clientName = '';
      mixStatus = 'draft';
      mixVersion = 1;
      mixNotes = '';
      draftIngredients = [createEmptyIngredient()];
      return;
    }

    savedMix = mix;
    mixName = mix.name;
    clientName = mix.client_name;
    mixStatus = mix.status;
    mixVersion = mix.version ?? 1;
    mixNotes = mix.notes ?? '';
    draftIngredients = mix.ingredients.length ? mix.ingredients.map(rowFromIngredient) : [createEmptyIngredient()];
  }

  loadDraftFromMix(getInitialMix());

  function resetDraft() {
    loadDraftFromMix(savedMix);
  }

  function updateIngredientField(index: number, field: keyof DraftIngredient, value: string | number | null) {
    draftIngredients = draftIngredients.map((row, rowIndex) =>
      rowIndex === index
        ? {
            ...row,
            [field]: value
          }
        : row
    );
  }

  function addIngredientRow() {
    draftIngredients = [...draftIngredients, createEmptyIngredient()];
  }

  function removeIngredientRow(index: number) {
    draftIngredients = draftIngredients.filter((_, rowIndex) => rowIndex !== index);

    if (!draftIngredients.length) {
      draftIngredients = [createEmptyIngredient()];
    }
  }

  function getCostPerKg(rawMaterialId: number | null) {
    return findRawMaterial(rawMaterialId)?.current_price?.cost_per_kg ?? null;
  }

  function getDraftWarnings() {
    const warnings: string[] = [];
    const chosen = draftIngredients
      .map((row) => row.raw_material_id)
      .filter((rawMaterialId): rawMaterialId is number => rawMaterialId !== null);

    if (!mixName.trim()) {
      warnings.push('Mix name is required.');
    }

    if (!clientName.trim()) {
      warnings.push('Client name is required.');
    }

    if (!draftIngredients.length || draftIngredients.every((row) => !row.raw_material_id || row.quantity_kg <= 0)) {
      warnings.push('Add at least one ingredient row with a positive quantity.');
    }

    if (new Set(chosen).size !== chosen.length) {
      warnings.push('Each raw material can only appear once in a mix.');
    }

    draftIngredients.forEach((row, index) => {
      if (row.raw_material_id === null) {
        warnings.push(`Row ${index + 1} is missing a raw material.`);
      }
      if (row.quantity_kg <= 0) {
        warnings.push(`Row ${index + 1} must have a quantity greater than zero.`);
      }
      if (row.raw_material_id !== null && getCostPerKg(row.raw_material_id) === null) {
        warnings.push(`Row ${index + 1} has no active raw material price.`);
      }
    });

    return warnings;
  }

  function getCleanIngredients() {
    return draftIngredients
      .filter((row) => row.raw_material_id !== null && row.quantity_kg > 0)
      .map((row) => ({
        id: row.id,
        raw_material_id: row.raw_material_id as number,
        quantity_kg: Number(row.quantity_kg),
        notes: row.notes.trim() || null
      }));
  }

  async function saveMix() {
    const validationWarnings = getDraftWarnings();
    if (validationWarnings.length) {
      toast.error(validationWarnings[0]);
      return;
    }

    isSaving = true;
    const tid = toast.loading(savedMix ? 'Saving mix…' : 'Creating mix…');

    try {
      const cleanIngredients = getCleanIngredients();

      if (!savedMix) {
        const created = await api.createMix({
          client_name: clientName.trim(),
          name: mixName.trim(),
          status: mixStatus,
          version: mixVersion,
          notes: mixNotes.trim() || null,
          ingredients: cleanIngredients.map((row) => ({
            raw_material_id: row.raw_material_id,
            quantity_kg: row.quantity_kg,
            notes: row.notes
          }))
        });

        toast.dismiss(tid);
        toast.success('Mix created');
        await invalidateAll();
        await goto(`/mixes/${created.id}`);
        return;
      }

      await api.updateMix(savedMix.id, {
        client_name: clientName.trim(),
        name: mixName.trim(),
        status: mixStatus,
        version: mixVersion,
        notes: mixNotes.trim() || null
      });

      const originalById = new Map(savedMix.ingredients.map((ingredient) => [ingredient.id, ingredient]));
      const draftIds = new Set(cleanIngredients.filter((row) => row.id !== null).map((row) => row.id as number));

      const rowsToDelete = savedMix.ingredients.filter((ingredient) => {
        if (!draftIds.has(ingredient.id)) {
          return true;
        }

        const draftRow = cleanIngredients.find((row) => row.id === ingredient.id);
        return draftRow ? draftRow.raw_material_id !== ingredient.raw_material_id : false;
      });

      for (const ingredient of rowsToDelete) {
        await api.deleteMixIngredient(savedMix.id, ingredient.id);
      }

      const rowsToAdd = cleanIngredients.filter((row) => {
        if (row.id === null) {
          return true;
        }

        const originalRow = originalById.get(row.id);
        return originalRow ? originalRow.raw_material_id !== row.raw_material_id : true;
      });

      for (const row of rowsToAdd) {
        await api.addMixIngredient(savedMix.id, {
          raw_material_id: row.raw_material_id,
          quantity_kg: row.quantity_kg,
          notes: row.notes
        });
      }

      const rowsToPatch = cleanIngredients.filter((row) => {
        if (row.id === null) {
          return false;
        }

        const originalRow = originalById.get(row.id);
        if (!originalRow || originalRow.raw_material_id !== row.raw_material_id) {
          return false;
        }

        return originalRow.quantity_kg !== row.quantity_kg || (originalRow.notes ?? null) !== row.notes;
      });

      for (const row of rowsToPatch) {
        await api.updateMixIngredient(savedMix.id, row.id as number, {
          quantity_kg: row.quantity_kg,
          notes: row.notes
        });
      }

      const refreshed = await api.mix(savedMix.id);
      await invalidateAll();
      loadDraftFromMix(refreshed);
      toast.dismiss(tid);
      toast.success('Mix saved');
    } catch (error) {
      toast.dismiss(tid);
      toast.error(error instanceof Error ? error.message : 'Unable to save mix');
    } finally {
      isSaving = false;
    }
  }

  const draftRows = $derived(
    draftIngredients.map((row) => {
      const material = findRawMaterial(row.raw_material_id);
      const costPerKg = material?.current_price?.cost_per_kg ?? null;
      const lineCost = costPerKg === null ? null : Number((row.quantity_kg * costPerKg).toFixed(4));

      return {
        ...row,
        marketValue: material?.current_price?.market_value ?? null,
        wastePercentage: material?.current_price?.waste_percentage ?? null,
        costPerKg,
        lineCost
      };
    })
  );
  const totalMixKg = $derived(draftRows.reduce((sum, row) => sum + Number(row.quantity_kg || 0), 0));
  const totalMixCost = $derived(Number(draftRows.reduce((sum, row) => sum + Number(row.lineCost || 0), 0).toFixed(4)));
  const mixCostPerKg = $derived(totalMixKg > 0 ? Number((totalMixCost / totalMixKg).toFixed(4)) : null);
  const draftWarnings = $derived(getDraftWarnings());
</script>

{#if !$clientSession}
  <section class="locked-card">
    <p class="eyebrow">Client Access Required</p>
    <h2>Sign in on the Hunter Premium Produce home page before editing mixes.</h2>
    <p>Mix worksheets use live raw material pricing and save directly into Mix Master.</p>
    <a href="/">Return to sign-in</a>
  </section>
{:else}
  <section class="page-intro page-actions">
    <div class="intro-actions">
      <a class="secondary-button" href="/mixes">Back to table</a>
      <button class="primary-button" type="button" onclick={saveMix} disabled={isSaving}>
        {isSaving ? 'Saving...' : savedMix ? 'Save Mix' : 'Create Mix'}
      </button>
    </div>
  </section>

  <section class="metric-row">
    <article class="metric-card">
      <span>Live Draft Kg</span>
      <strong>{totalMixKg.toFixed(2)}</strong>
      <p>Total quantity in the current worksheet</p>
    </article>

    <article class="metric-card">
      <span>Live Draft Cost</span>
      <strong>{currency(totalMixCost)}</strong>
      <p>Calculated from current row factors</p>
    </article>

    <article class="metric-card">
      <span>Cost / Kg</span>
      <strong>{currency(mixCostPerKg, 4)}</strong>
      <p>Current worksheet output</p>
    </article>
  </section>

  <section class="editor-grid">
    <article class="editor-card">
      <div class="section-heading">
        <div>
          <p class="eyebrow">Worksheet Meta</p>
          <h3>Mix details</h3>
        </div>

        <div class="editor-actions">
          <button class="secondary-button" type="button" onclick={resetDraft}>Reset</button>
          <button class="primary-button" type="button" onclick={saveMix} disabled={isSaving}>
            {isSaving ? 'Saving...' : savedMix ? 'Save Mix' : 'Create Mix'}
          </button>
        </div>
      </div>

      <div class="meta-grid">
        <label>
          Mix Name
          <input bind:value={mixName} placeholder="Hunter Orchard Blend" />
        </label>

        <label>
          Client
          <input bind:value={clientName} placeholder="Hunter Premium Produce" />
        </label>

        <label>
          Status
          <select bind:value={mixStatus}>
            <option value="draft">Draft</option>
            <option value="active">Active</option>
            <option value="inactive">Inactive</option>
          </select>
        </label>

        <label>
          Version
          <input bind:value={mixVersion} type="number" min="1" step="1" />
        </label>
      </div>

      <label class="notes-field">
        Notes
        <textarea bind:value={mixNotes} rows="3" placeholder="Internal mixing notes, process assumptions, or version comments"></textarea>
      </label>

      <div class="section-heading spreadsheet-head">
        <div>
          <p class="eyebrow">Spreadsheet Rows</p>
          <h4>Ingredient builder</h4>
        </div>
        <button class="secondary-button" type="button" onclick={addIngredientRow}>Add Row</button>
      </div>

      <div class="sheet-wrap">
        <table class="sheet-table">
          <thead>
            <tr>
              <th>Raw Material</th>
              <th>Market Value</th>
              <th>Waste %</th>
              <th>Cost / Kg</th>
              <th>Qty Kg</th>
              <th>Line Cost</th>
              <th>Notes</th>
              <th></th>
            </tr>
          </thead>
          <tbody>
            {#each draftRows as row, index}
              <tr>
                <td data-label="Raw Material">
                  <select
                    value={row.raw_material_id ?? ''}
                    onchange={(event) =>
                      updateIngredientField(
                        index,
                        'raw_material_id',
                        Number((event.currentTarget as HTMLSelectElement).value) || null
                      )}
                  >
                    <option value="">Select material</option>
                    {#each rawMaterials as material}
                      <option value={material.id}>{material.name}</option>
                    {/each}
                  </select>
                </td>
                <td data-label="Market Value">{currency(row.marketValue)}</td>
                <td data-label="Waste %">{row.wastePercentage !== null ? `${(row.wastePercentage * 100).toFixed(1)}%` : 'N/A'}</td>
                <td data-label="Cost / Kg">{currency(row.costPerKg, 4)}</td>
                <td data-label="Qty Kg">
                  <input
                    type="number"
                    min="0"
                    step="0.01"
                    value={row.quantity_kg}
                    oninput={(event) =>
                      updateIngredientField(index, 'quantity_kg', Number((event.currentTarget as HTMLInputElement).value))
                    }
                  />
                </td>
                <td data-label="Line Cost">{currency(row.lineCost)}</td>
                <td data-label="Notes">
                  <input
                    type="text"
                    value={row.notes}
                    oninput={(event) => updateIngredientField(index, 'notes', (event.currentTarget as HTMLInputElement).value)}
                    placeholder="Optional row note"
                  />
                </td>
                <td data-label="Row Action">
                  <button class="icon-delete" type="button" onclick={() => removeIngredientRow(index)}>Remove</button>
                </td>
              </tr>
            {/each}
          </tbody>
        </table>
      </div>
    </article>

    <aside class="sidebar-stack">
      <article class="summary-card">
        <div class="section-heading">
          <div>
            <p class="eyebrow">Live Totals</p>
            <h3>Worksheet summary</h3>
          </div>
        </div>

        <div class="summary-grid">
          <article>
            <span>Total Kg</span>
            <strong>{totalMixKg.toFixed(2)}</strong>
          </article>
          <article>
            <span>Total Cost</span>
            <strong>{currency(totalMixCost)}</strong>
          </article>
          <article>
            <span>Cost / Kg</span>
            <strong>{currency(mixCostPerKg, 4)}</strong>
          </article>
          <article>
            <span>Rows</span>
            <strong>{draftRows.length}</strong>
          </article>
        </div>
      </article>

      <article class="summary-card">
        <div class="section-heading">
          <div>
            <p class="eyebrow">Calculation Factors</p>
            <h3>What drives cost</h3>
          </div>
        </div>

        <div class="factor-list">
          <article>
            <strong>Market value</strong>
            <span>Each raw material row uses the active market value from the raw materials module.</span>
          </article>
          <article>
            <strong>Waste percentage</strong>
            <span>Material loss is included in the computed cost per kg used by the worksheet.</span>
          </article>
          <article>
            <strong>Kg per unit</strong>
            <span>Unit conversion already affects each raw material cost per kg before line costs are calculated.</span>
          </article>
          <article>
            <strong>Quantity used</strong>
            <span>Line cost is recalculated instantly from quantity times cost per kg.</span>
          </article>
        </div>
      </article>

      <article class="summary-card">
        <div class="section-heading">
          <div>
            <p class="eyebrow">Draft Checks</p>
            <h3>Validation</h3>
          </div>
        </div>

        {#if draftWarnings.length}
          <div class="warning-list">
            {#each draftWarnings as warning}
              <article>{warning}</article>
            {/each}
          </div>
        {:else}
          <div class="healthy-card">
            <strong>Ready to save</strong>
            <p>This draft has the required metadata and valid ingredient rows.</p>
          </div>
        {/if}
      </article>
    </aside>
  </section>
{/if}

<style>
  h2,
  h3,
  h4,
  p {
    margin: 0;
  }

  .eyebrow {
    color: #7f8e85;
    font-size: 0.74rem;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
  }

  .locked-card,
  .page-intro,
  .metric-card,
  .editor-card,
  .summary-card {
    background: var(--panel);
    border: 1px solid var(--line);
    border-radius: 1.16rem;
    box-shadow: var(--shadow);
  }

  .locked-card,
  .page-intro,
  .metric-row,
  .editor-grid {
    margin-bottom: 1.12rem;
  }

  .locked-card,
  .page-intro,
  .editor-card,
  .summary-card {
    padding: 1.08rem;
  }

  .locked-card {
    display: grid;
    gap: 0.62rem;
    max-width: 40rem;
  }

  .locked-card h2 {
    margin: 0.3rem 0 0.4rem;
    font-size: clamp(1.56rem, 3vw, 2.02rem);
    font-weight: 700;
  }

  .locked-card p:last-of-type,
  .metric-card p,
  .summary-card span,
  .factor-list span,
  .healthy-card p {
    color: var(--muted);
  }

  .locked-card a {
    color: var(--green-deep);
    font-weight: 600;
  }

  .page-intro,
  .section-heading,
  .intro-actions,
  .editor-actions {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.68rem;
  }

  .page-intro {
    align-items: end;
  }

  .page-actions {
    justify-content: flex-end;
  }

  .primary-button,
  .secondary-button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 0.82rem;
    padding: 0.74rem 0.9rem;
    font-weight: 600;
    cursor: pointer;
  }

  .primary-button {
    border: none;
    color: #fff;
    background: var(--color-brand);
    box-shadow: none;
  }

  .secondary-button {
    border: 1px solid var(--line-strong);
    color: #304038;
    background: #fff;
  }

  .primary-button:disabled,
  .secondary-button:disabled {
    opacity: 0.7;
    cursor: wait;
  }

  .metric-row,
  .editor-grid,
  .meta-grid,
  .summary-grid {
    display: grid;
    gap: 0.9rem;
  }

  .metric-row {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }

  .metric-card {
    padding: 1.04rem 1.08rem;
  }

  .metric-card span {
    display: block;
    color: var(--muted);
    font-size: 0.84rem;
  }

  .metric-card strong {
    display: block;
    margin: 0.48rem 0 0.26rem;
    font-size: 1.72rem;
    font-weight: 700;
  }

  .section-heading {
    align-items: flex-start;
    margin-bottom: 0.9rem;
  }

  .section-heading h3,
  .section-heading h4 {
    font-size: 1.02rem;
    font-weight: 700;
  }

  .editor-grid {
    grid-template-columns: minmax(0, 1.45fr) minmax(280px, 0.75fr);
  }

  .editor-card,
  .summary-card {
    display: grid;
    gap: 0.9rem;
  }

  .meta-grid {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }

  label {
    display: grid;
    gap: 0.32rem;
    color: #53645b;
    font-size: 0.86rem;
    font-weight: 600;
  }

  input,
  textarea,
  select {
    width: 100%;
    padding: 0.82rem 0.88rem;
    border: 1px solid var(--line-strong);
    border-radius: 0.88rem;
    background: var(--panel-soft);
    color: var(--text);
  }

  .sheet-wrap {
    overflow-x: auto;
  }

  .sheet-table {
    width: 100%;
    min-width: 58rem;
    border-collapse: separate;
    border-spacing: 0 0.54rem;
  }

  .sheet-table th,
  .sheet-table td {
    padding: 0.88rem 0.92rem;
    text-align: left;
    white-space: nowrap;
  }

  .sheet-table th {
    color: var(--muted);
    font-size: 0.74rem;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
  }

  .sheet-table tbody td {
    background: var(--panel-soft);
    border-top: 1px solid var(--line);
    border-bottom: 1px solid var(--line);
  }

  .sheet-table tbody td:first-child {
    border-left: 1px solid var(--line);
    border-radius: 0.92rem 0 0 0.92rem;
  }

  .sheet-table tbody td:last-child {
    border-right: 1px solid var(--line);
    border-radius: 0 0.92rem 0.92rem 0;
  }

  .sheet-table input,
  .sheet-table select {
    min-width: 8rem;
    padding: 0.7rem 0.78rem;
    background: #fff;
  }

  .icon-delete {
    border: 1px solid #eed8d8;
    border-radius: 0.74rem;
    padding: 0.64rem 0.78rem;
    color: #a34a4a;
    background: #fff7f7;
    font-weight: 600;
    cursor: pointer;
  }

  .sidebar-stack,
  .factor-list,
  .warning-list {
    display: grid;
    gap: 0.9rem;
  }

  .summary-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .summary-grid article,
  .factor-list article {
    padding: 0.88rem 0.94rem;
    border: 1px solid var(--line);
    border-radius: 0.92rem;
    background: var(--panel-soft);
  }

  .summary-grid strong {
    display: block;
    margin-top: 0.28rem;
    font-size: 1.08rem;
    font-weight: 700;
  }

  .factor-list strong,
  .healthy-card strong {
    display: block;
    margin-bottom: 0.28rem;
    font-size: 0.96rem;
    font-weight: 700;
  }

  .warning-list article {
    padding: 0.84rem 0.9rem;
    border: 1px solid #f0d8d8;
    border-radius: 0.92rem;
    background: #fff7f7;
    color: #9a4747;
    font-size: 0.86rem;
    font-weight: 600;
  }

  .healthy-card {
    padding: 0.95rem 1rem;
    border: 1px solid #d9ecdf;
    border-radius: 0.96rem;
    background: #f6fcf8;
  }

  @media (max-width: 980px) {
    .metric-row,
    .editor-grid {
      grid-template-columns: 1fr;
    }
  }

  @media (max-width: 720px) {
    .page-intro,
    .section-heading,
    .intro-actions,
    .editor-actions {
      flex-direction: column;
      align-items: stretch;
    }

    .meta-grid,
    .summary-grid {
      grid-template-columns: 1fr;
    }

    .sheet-table {
      min-width: 0;
      border-spacing: 0;
    }

    .sheet-table,
    .sheet-table thead,
    .sheet-table tbody,
    .sheet-table tr,
    .sheet-table td {
      display: block;
      width: 100%;
    }

    .sheet-table thead {
      display: none;
    }

    .sheet-table tbody {
      display: grid;
      gap: 0.75rem;
    }

    .sheet-table tbody tr {
      border: 1px solid var(--line);
      border-radius: 1rem;
      background: var(--panel-soft);
      overflow: hidden;
    }

    .sheet-table tbody td {
      border: none;
      border-bottom: 1px solid var(--line);
      border-left: none;
      border-right: none;
      border-radius: 0;
      white-space: normal;
    }

    .sheet-table tbody td:last-child {
      border-bottom: none;
    }

    .sheet-table tbody td::before {
      content: attr(data-label);
      display: block;
      margin-bottom: 0.24rem;
      color: var(--muted);
      font-size: 0.72rem;
      font-weight: 700;
      letter-spacing: 0.06em;
      text-transform: uppercase;
    }
  }
</style>
