<!-- eslint-disable vue/no-v-html -->
<template>
  <div :class="dense ? 'wrapper' : 'wrapper pa-3'">
    <section>
      <v-container class="ma-0 pa-0">
        <v-row>
          <v-col
            v-if="preferences.imagePosition && preferences.imagePosition != ImagePosition.hidden"
            :order="preferences.imagePosition == ImagePosition.left ? -1 : 1"
            cols="4"
            align-self="center"
          >
            <img
              :key="imageKey"
              :src="recipeImageUrl"
              style="min-height: 50; max-width: 100%;"
            >
          </v-col>
          <v-col order="0">
            <v-card-title class="headline pl-0">
              <v-icon
                start
                color="primary"
              >
                {{ $globals.icons.primary }}
              </v-icon>
              {{ recipe.name }}
            </v-card-title>
            <div
              v-if="recipeYield"
              class="d-flex justify-space-between align-center pb-6"
            >
              <div>
                <v-icon start>
                  {{ $globals.icons.potSteam }}
                </v-icon>
                <!-- eslint-disable-next-line vue/no-v-html -->
                <span v-html="recipeYield" />
              </div>
            </div>
            <v-row class="d-flex justify-start">
              <RecipeTimeCard
                :prep-time="recipe.prepTime"
                :total-time="recipe.totalTime"
                :perform-time="recipe.performTime"
                small
                color="white"
                class="ml-4"
              />
            </v-row>

            <v-card-text
              v-if="preferences.showDescription"
              class="px-0"
            >
              <SafeMarkdown :source="recipe.description" />
            </v-card-text>
          </v-col>
        </v-row>
      </v-container>
    </section>

    <!-- Ingredients -->
    <section>
      <v-card-title class="headline pl-0">
        {{ $t("recipe.ingredients") }}
      </v-card-title>
      <div
        v-for="(ingredientSection, sectionIndex) in ingredientSections"
        :key="`ingredient-section-${sectionIndex}`"
        class="print-section"
      >
        <h4
          v-if="ingredientSection.ingredients[0].title"
          class="ingredient-title mt-2"
        >
          {{ ingredientSection.ingredients[0].title }}
        </h4>
        <div
          class="ingredient-grid"
          :style="{ gridTemplateRows: `repeat(${Math.ceil(ingredientSection.ingredients.length / 2)}, min-content)` }"
        >
          <template
            v-for="(ingredient, ingredientIndex) in ingredientSection.ingredients"
            :key="`ingredient-${ingredientIndex}`"
          >
            <!-- eslint-disable-next-line vue/no-v-html -->
            <p
              class="ingredient-body"
              v-html="parseText(ingredient)"
            />
          </template>
        </div>
      </div>
    </section>

    <!-- Instructions -->
    <section>
      <div
        v-for="(instructionSection, sectionIndex) in instructionSections"
        :key="`instruction-section-${sectionIndex}`"
        :class="{ 'print-section': instructionSection.sectionName }"
      >
        <v-card-title
          v-if="!sectionIndex"
          class="headline pl-0"
        >
          {{ $t("recipe.instructions") }}
        </v-card-title>
        <div
          v-for="(step, stepIndex) in instructionSection.instructions"
          :key="`instruction-${stepIndex}`"
        >
          <div class="print-section">
            <h4
              v-if="step.title"
              :key="`instruction-title-${stepIndex}`"
              class="instruction-title mb-2"
            >
              {{ step.title }}
            </h4>
            <h5>
              {{ step.summary ? step.summary : $t("recipe.step-index", {
                step: stepIndex
                  + instructionSection.stepOffset
                  + 1,
              }) }}
            </h5>
            <SafeMarkdown
              :source="step.text"
              class="recipe-step-body"
            />
          </div>
        </div>
      </div>
    </section>

    <!-- Notes -->
    <div v-if="preferences.showNotes">
      <v-divider
        v-if="hasNotes"
        class="grey my-4"
      />

      <section>
        <div
          v-for="(note, index) in recipe.notes"
          :key="index + 'note'"
        >
          <div class="print-section">
            <h4>{{ note.title }}</h4>
            <SafeMarkdown
              :source="note.text"
              class="note-body"
            />
          </div>
        </div>
      </section>
    </div>

    <!-- Nutrition -->
    <div v-if="preferences.showNutrition">
      <v-card-title class="headline pl-0">
        {{ $t("recipe.nutrition") }}
      </v-card-title>

      <section>
        <div class="print-section">
          <table class="nutrition-table">
            <tbody>
              <tr
                v-for="(value, key) in recipe.nutrition"
                :key="key"
              >
                <template v-if="value">
                  <td>{{ labels[key].label }}</td>
                  <td>{{ value ? (labels[key].suffix ? `${value} ${labels[key].suffix}` : value) : '-' }}</td>
                </template>
              </tr>
            </tbody>
          </table>
        </div>
      </section>
    </div>
  </div>
</template>

<script setup lang="ts">
import DOMPurify from "dompurify";
import RecipeTimeCard from "~/components/Domain/Recipe/RecipeTimeCard.vue";
import { useStaticRoutes } from "~/composables/api";
import type { Recipe, RecipeIngredient, RecipeStep } from "~/lib/api/types/recipe";
import type { NoUndefinedField } from "~/lib/api/types/non-generated";
import { ImagePosition, useUserPrintPreferences } from "~/composables/use-users/preferences";
import { useIngredientTextParser, useNutritionLabels } from "~/composables/recipes";
import { usePageState } from "~/composables/recipe-page/shared-state";
import { useScaledAmount } from "~/composables/recipes/use-scaled-amount";

type IngredientSection = {
  sectionName: string;
  ingredients: RecipeIngredient[];
};

type InstructionSection = {
  sectionName: string;
  stepOffset: number;
  instructions: RecipeStep[];
};

interface Props {
  recipe: NoUndefinedField<Recipe>;
  scale?: number;
  dense?: boolean;
}
const props = withDefaults(defineProps<Props>(), {
  scale: 1,
  dense: false,
});

const i18n = useI18n();
const preferences = useUserPrintPreferences();
const { recipeImage } = useStaticRoutes();
const { imageKey } = usePageState(props.recipe.slug);
const { labels } = useNutritionLabels();

function sanitizeHTML(rawHtml: string) {
  return DOMPurify.sanitize(rawHtml, {
    USE_PROFILES: { html: true },
    ALLOWED_TAGS: ["strong", "sup"],
  });
}
const servingsDisplay = computed(() => {
  const { scaledAmountDisplay } = useScaledAmount(props.recipe.recipeYieldQuantity, props.scale);
  return scaledAmountDisplay || props.recipe.recipeYield
    ? i18n.t("recipe.yields-amount-with-text", {
      amount: scaledAmountDisplay,
      text: props.recipe.recipeYield,
    }) as string
    : "";
});

const yieldDisplay = computed(() => {
  const { scaledAmountDisplay } = useScaledAmount(props.recipe.recipeServings, props.scale);
  return scaledAmountDisplay ? i18n.t("recipe.serves-amount", { amount: scaledAmountDisplay }) as string : "";
});

const recipeYield = computed(() => {
  if (servingsDisplay.value && yieldDisplay.value) {
    return sanitizeHTML(`${yieldDisplay.value}; ${servingsDisplay.value}`);
  }
  else {
    return sanitizeHTML(yieldDisplay.value || servingsDisplay.value);
  }
});

const recipeImageUrl = computed(() => {
  return recipeImage(props.recipe.id, props.recipe.image, imageKey.value);
});

// Group ingredients by section so we can style them independently
const ingredientSections = computed<IngredientSection[]>(() => {
  if (!props.recipe.recipeIngredient) {
    return [];
  }
  const addIngredientsToSections = (ingredients: RecipeIngredient[], sections: IngredientSection[], title: string | null) => {
  // If title is set, ensure the section exists before adding ingredients
    let section: IngredientSection | undefined;
    if (title) {
      section = sections.find(sec => sec.sectionName === title);
      if (!section) {
        section = { sectionName: title, ingredients: [] };
        sections.push(section);
      }
    }

    ingredients.forEach((ingredient) => {
      if (preferences.value.expandChildRecipes && ingredient.referencedRecipe?.recipeIngredient?.length) {
        // Recursively add to the section for this referenced recipe
        addIngredientsToSections(
          ingredient.referencedRecipe.recipeIngredient,
          sections,
          "",
        );
      }
      else {
        const sectionName = title || ingredient.title || "";
        if (sectionName) {
          let sec = sections.find(sec => sec.sectionName === sectionName);
          if (!sec) {
            sec = { sectionName, ingredients: [] };
            sections.push(sec);
          }
          ingredient.title = sectionName;
          sec.ingredients.push(ingredient);
        }
        else {
          if (sections.length === 0) {
            sections.push({
              sectionName: "",
              ingredients: [ingredient],
            });
          }
          else {
            sections[sections.length - 1].ingredients.push(ingredient);
          }
        }
      }
    });
  };

  const sections: IngredientSection[] = [];
  addIngredientsToSections(props.recipe.recipeIngredient, sections, null);
  return sections;
});

// Group instructions by section so we can style them independently
const instructionSections = computed<InstructionSection[]>(() => {
  if (!props.recipe.recipeInstructions) {
    return [];
  }

  return props.recipe.recipeInstructions.reduce((sections, step) => {
    const offset = (() => {
      if (sections.length === 0) {
        return 0;
      }

      const lastOffset = sections[sections.length - 1].stepOffset;
      const lastNumSteps = sections[sections.length - 1].instructions.length;
      return lastOffset + lastNumSteps;
    })();

    // if title append new section to the end of the array
    if (step.title) {
      sections.push({
        sectionName: step.title,
        stepOffset: offset,
        instructions: [step],
      });

      return sections;
    }

    // append if first element
    if (sections.length === 0) {
      sections.push({
        sectionName: "",
        stepOffset: offset,
        instructions: [step],
      });

      return sections;
    }

    // otherwise add step to last section in the array
    sections[sections.length - 1].instructions.push(step);
    return sections;
  }, [] as InstructionSection[]);
});

const hasNotes = computed(() => {
  return props.recipe.notes && props.recipe.notes.length > 0;
});

const { parseIngredientText } = useIngredientTextParser();

function parseText(ingredient: RecipeIngredient) {
  return parseIngredientText(ingredient, props.scale);
}
</script>

<style scoped>
/* Makes all text solid black */
.wrapper {
  background-color: white;
}

.wrapper,
.wrapper :deep(*) {
  opacity: 1 !important;
  color: black !important;
}

/* Prevents sections from being broken up between pages */
.print-section {
  page-break-inside: avoid;
}

p {
  padding-bottom: 0 !important;
  margin-bottom: 0 !important;
}

.v-card__text {
  padding-bottom: 0;
  margin-bottom: 0;
}

.ingredient-grid {
  display: grid;
  grid-auto-flow: column;
  grid-template-columns: 1fr 1fr;
  grid-gap: 0.5rem;
}

.ingredient-title,
.instruction-title {
  grid-column: 1 / span 2;
  text-decoration: underline;
  text-underline-offset: 4px;
}

.ingredient-body,
.recipe-step-body,
.note-body {
  font-size: 14px;
}

ul {
  padding-left: 1rem;
}

li {
  list-style-type: none;
  margin-bottom: 0.25rem;
}

.nutrition-table {
  max-width: 80%;
  border-collapse: collapse;
}

.nutrition-table th,
.nutrition-table td {
  padding: 6px 10px;
  text-align: left;
  vertical-align: top;
  font-size: 14px;
}

.nutrition-table th {
  font-weight: bold;
  padding-bottom: 10px;
}

.nutrition-table td:first-child {
  width: 70%;
  font-weight: bold;
}

.nutrition-table td:last-child {
  width: 30%;
  text-align: right;
}

.nutrition-table td {
  padding: 2px;
  text-align: left;
  font-size: 14px;
}
</style>
