import type { Accessor } from "solid-js";
import { createEffect, createMemo, createSignal, onCleanup } from "solid-js";
import type { BentoSelection, StepKind } from "@ben-to/builder/domain";
import { computeRecipeSteps } from "@ben-to/builder/domain";
import { scaleQuantities } from "@ben-to/recipes/domain";
import type { LocaleCode } from "@ben-to/i18n/dictionary";
import type { DictionaryView } from "./dictionary-view";
import { loadRecipeChecklist, saveRecipeChecklist } from "../../infra/recipe-checklist-persistence";
import { trackEvent } from "../../infra/analytics";
import { shareRecipeWithFallback } from "./recipe-share";

type MergedRecipeView = ReturnType<typeof computeRecipeSteps>;

export function useRecipeSheet(props: {
  readonly selection: Accessor<BentoSelection>;
  readonly currentStep: Accessor<StepKind>;
  readonly mergedRecipe: Accessor<MergedRecipeView>;
  readonly recipeDisplayTitle: Accessor<string>;
  readonly locale: Accessor<LocaleCode>;
  readonly t: Accessor<DictionaryView>;
}) {
  const [servings, setServings] = createSignal(1);
  const [servingsDraft, setServingsDraft] = createSignal<string | null>(null);
  const [recipeProgressCompact, setRecipeProgressCompact] = createSignal(false);
  const [shareFeedback, setShareFeedback] = createSignal<string | null>(null);
  const [checkedIngredientIds, setCheckedIngredientIds] = createSignal(new Set<string>());
  const [doneStepIds, setDoneStepIds] = createSignal(new Set<string>());

  const baseServings = createMemo(() => Math.max(1, props.mergedRecipe().servings));

  const displayedIngredients = createMemo(() => {
    const quantityFactor = servings() / baseServings();
    return props.mergedRecipe().ingredients.map((ingredient) => ({
      ...ingredient,
      quantity: scaleQuantities(ingredient.quantity, quantityFactor)
    }));
  });

  let recipeScrollHost: HTMLDivElement | undefined;
  let shareFeedbackTimer: ReturnType<typeof setTimeout> | undefined;

  const clearShareFeedbackTimer = () => {
    if (shareFeedbackTimer !== undefined) clearTimeout(shareFeedbackTimer);
  };

  onCleanup(() => {
    clearShareFeedbackTimer();
  });

  let lastRecipeKey = "";

  createEffect(() => {
    const selection = props.selection();
    const recipeKey = `${selection.baseId ?? ""}:${selection.variantId ?? ""}:${baseServings()}`;
    if (recipeKey !== lastRecipeKey) {
      lastRecipeKey = recipeKey;
      setServings(baseServings());
      setServingsDraft(null);
    }
  });

  createEffect(() => {
    const variantId = props.selection().variantId;
    const recipe = props.mergedRecipe();
    const validIngredientIds = new Set(recipe.ingredients.map((item) => item.id));
    const validStepIds = new Set(recipe.steps.map((item) => item.id));

    if (!variantId) {
      setCheckedIngredientIds(new Set<string>());
      setDoneStepIds(new Set<string>());
      return;
    }

    const stored = loadRecipeChecklist(variantId);
    const ingredients = new Set(stored.ingredientIds.filter((id) => validIngredientIds.has(id)));
    const steps = new Set(stored.stepIds.filter((id) => validStepIds.has(id)));
    setCheckedIngredientIds(ingredients);
    setDoneStepIds(steps);
  });

  const toggleIngredientChecklist = (id: string) => {
    const variantId = props.selection().variantId;
    if (!variantId) return;
    setCheckedIngredientIds((prev) => {
      const next = new Set(prev);
      if (next.has(id)) next.delete(id);
      else next.add(id);
      saveRecipeChecklist(variantId, {
        ingredientIds: [...next],
        stepIds: [...doneStepIds()]
      });
      return next;
    });
  };

  const toggleStepChecklist = (id: string) => {
    const variantId = props.selection().variantId;
    if (!variantId) return;
    setDoneStepIds((prev) => {
      const next = new Set(prev);
      if (next.has(id)) next.delete(id);
      else next.add(id);
      saveRecipeChecklist(variantId, {
        ingredientIds: [...checkedIngredientIds()],
        stepIds: [...next]
      });
      return next;
    });
  };

  createEffect(() => {
    if (props.currentStep() !== "recipe") {
      setRecipeProgressCompact(false);
      return;
    }
    queueMicrotask(() => {
      recipeScrollHost?.scrollTo(0, 0);
      setRecipeProgressCompact(false);
    });
  });

  const onRecipeScroll: EventListener = (event) => {
    const el = event.currentTarget as HTMLDivElement;
    setRecipeProgressCompact(el.scrollTop > 14);
  };

  const servingsFieldValue = createMemo(() => servingsDraft() ?? String(servings()));

  const bumpServings = (delta: number) => {
    setServingsDraft(null);
    setServings((n) => Math.min(99, Math.max(1, n + delta)));
  };

  const onServingsFocus = () => {
    setServingsDraft(String(servings()));
  };

  const onServingsInput = (event: InputEvent & { currentTarget: HTMLInputElement }) => {
    const digits = event.currentTarget.value.replace(/\D/g, "").slice(0, 2);
    setServingsDraft(digits);
  };

  const onServingsBlur = () => {
    const raw = servingsDraft();
    setServingsDraft(null);
    if (raw === null || raw === "") {
      setServings(baseServings());
      return;
    }
    const parsed = Number.parseInt(raw, 10);
    setServings(Number.isFinite(parsed) ? Math.min(99, Math.max(1, parsed)) : baseServings());
  };

  const getRecipeShareUrl = () => {
    if (typeof window === "undefined") return "";
    const { baseId, variantId } = props.selection();
    if (!baseId || !variantId) return "";
    const path = `/r/${encodeURIComponent(baseId)}/${encodeURIComponent(variantId)}`;
    return new URL(path, window.location.origin).href;
  };

  const buildRecipeShareText = () => {
    const loc = props.locale();
    const dict = props.t();
    const title = props.recipeDisplayTitle() || dict.recipe;
    const lines: string[] = [title, "", `${dict.servings}: ${servings()}`, "", dict.ingredients];
    for (const ing of displayedIngredients()) {
      lines.push(`• ${ing.name[loc]} — ${ing.quantity} ${ing.unit}`);
    }
    lines.push("", dict.steps);
    props.mergedRecipe().steps.forEach((step, index) => {
      lines.push(`${index + 1}. ${step.text[loc]}`);
    });
    const url = getRecipeShareUrl();
    if (url) {
      lines.push("", dict.recipeShareUrlIntro, url);
    }
    return lines.join("\n");
  };

  const flashShareFeedback = (message: string) => {
    clearShareFeedbackTimer();
    setShareFeedback(message);
    shareFeedbackTimer = setTimeout(() => {
      setShareFeedback(null);
      shareFeedbackTimer = undefined;
    }, 4500);
  };

  const shareRecipe = async () => {
    const dict = props.t();
    await shareRecipeWithFallback({
      title: props.recipeDisplayTitle() || dict.recipe,
      body: buildRecipeShareText(),
      url: getRecipeShareUrl(),
      variantIdForTrack: props.selection().variantId ?? "none",
      strings: { shareCopied: dict.shareCopied, shareCopyFailed: dict.shareCopyFailed },
      setShareFeedback,
      clearShareFeedbackTimer,
      flashShareFeedback
    });
  };

  const printRecipe = () => {
    window.print();
    trackEvent("recipe", "print", props.selection().variantId ?? "none");
  };

  const resetServingsForGoHome = () => {
    setServings(1);
    setServingsDraft(null);
  };

  return {
    servings,
    servingsDraft,
    servingsFieldValue,
    bumpServings,
    onServingsFocus,
    onServingsInput,
    onServingsBlur,
    checkedIngredientIds,
    doneStepIds,
    toggleIngredientChecklist,
    toggleStepChecklist,
    recipeProgressCompact,
    shareFeedback,
    onRecipeScroll,
    shareRecipe,
    printRecipe,
    resetServingsForGoHome,
    /** Callback ref Solid : assigner au conteneur scroll de la feuille recette. */
    bindRecipeScrollHost: (el: HTMLDivElement) => {
      recipeScrollHost = el;
    },
    displayedIngredients
  };
}

export type RecipeSheetHandle = ReturnType<typeof useRecipeSheet>;
