"use client";

import Link from "next/link";
import type { MouseEvent as ReactMouseEvent, PointerEvent as ReactPointerEvent, WheelEvent as ReactWheelEvent } from "react";
import { useEffect, useMemo, useRef, useState } from "react";
import { formatScenarioDurationLabel } from "@/lib/scenario-utils";

type Tag = {
  id: string;
  label: string;
};

type EmployeeProfile = {
  name: string;
  role: string;
};

type ScenarioItem = {
  id: string;
  templateId: string;
  title: string;
  targetSkill: string;
  difficulty: string;
  maxTurns: number;
  shortBrief: string;
  managerGoal: string;
  employeeProfile: EmployeeProfile;
  tags: Tag[];
};

type ScenarioCarouselProps = {
  scenarios: ScenarioItem[];
};

type LayoutState = {
  viewportWidth: number;
  contentWidth: number;
  trackWidth: number;
};

const DIFFICULTY_FILTER_ORDER = ["Fondamentaux", "Intermédiaire", "Expert"] as const;

function getDifficultyLabel(value: string) {
  switch (value) {
    case "Exigeant":
      return "Expert";
    case "Intermédiaire":
    case "Intermediaire":
      return "Intermédiaire";
    default:
      return value;
  }
}

function getDifficultyColor(value: string) {
  switch (value) {
    case "Fondamentaux":
      return "#1775BA";
    case "Intermédiaire":
    case "Intermédiaire":
    case "Intermediaire":
      return "#D88E04";
    case "Exigeant":
      return "#C1161B";
    default:
      return "#5B6B79";
  }
}

function clamp(value: number, min: number, max: number) {
  return Math.min(Math.max(value, min), max);
}

export function ScenarioCarousel({ scenarios }: ScenarioCarouselProps) {
  const viewportRef = useRef<HTMLDivElement | null>(null);
  const contentRef = useRef<HTMLDivElement | null>(null);
  const scrollbarTrackRef = useRef<HTMLDivElement | null>(null);
  const thumbDragOffsetRef = useRef(0);
  const dragStateRef = useRef({
    active: false,
    startX: 0,
    startScrollLeft: 0,
    moved: false,
  });
  const suppressClickRef = useRef(false);
  const [layout, setLayout] = useState<LayoutState>({
    viewportWidth: 0,
    contentWidth: 0,
    trackWidth: 0,
  });
  const [scrollLeft, setScrollLeft] = useState(0);
  const [draggingThumb, setDraggingThumb] = useState(false);
  const [draggingRail, setDraggingRail] = useState(false);
  const [selectedDifficulty, setSelectedDifficulty] = useState("Tous niveaux");
  const [selectedTag, setSelectedTag] = useState("Tous les tags");
  const [mobileFiltersOpen, setMobileFiltersOpen] = useState(false);

  const difficultyOptions = useMemo(() => {
    const availableDifficulties = new Set(
      scenarios.map((scenario) => getDifficultyLabel(scenario.difficulty)),
    );

    return [
      "Tous niveaux",
      ...DIFFICULTY_FILTER_ORDER.filter((difficulty) => availableDifficulties.has(difficulty)),
    ];
  }, [scenarios]);
  const tagOptions = useMemo(
    () => ["Tous les tags", ...new Set(scenarios.flatMap((scenario) => scenario.tags.map((tag) => tag.label)))],
    [scenarios],
  );
  const filteredScenarios = useMemo(
    () =>
      scenarios.filter((scenario) => {
        const matchesDifficulty =
          selectedDifficulty === "Tous niveaux" ||
          getDifficultyLabel(scenario.difficulty) === selectedDifficulty;
        const matchesTag =
          selectedTag === "Tous les tags" || scenario.tags.some((tag) => tag.label === selectedTag);

        return matchesDifficulty && matchesTag;
      }),
    [scenarios, selectedDifficulty, selectedTag],
  );
  const maxScroll = Math.max(layout.contentWidth - layout.viewportWidth, 0);
  const thumbWidth = layout.contentWidth <= layout.viewportWidth || layout.trackWidth <= 0
    ? layout.trackWidth
    : Math.max((layout.viewportWidth / layout.contentWidth) * layout.trackWidth, 88);
  const maxThumbLeft = Math.max(layout.trackWidth - thumbWidth, 0);
  const thumbLeft = maxScroll === 0 ? 0 : (scrollLeft / maxScroll) * maxThumbLeft;

  function setScrollPosition(nextScrollLeft: number) {
    setScrollLeft(clamp(nextScrollLeft, 0, maxScroll));
  }

  useEffect(() => {
    function updateLayout() {
      const viewportWidth = viewportRef.current?.clientWidth ?? 0;
      const contentWidth = contentRef.current?.scrollWidth ?? 0;
      const trackWidth = scrollbarTrackRef.current?.clientWidth ?? 0;

      setLayout({ viewportWidth, contentWidth, trackWidth });
      setScrollLeft((current) => clamp(current, 0, Math.max(contentWidth - viewportWidth, 0)));
    }

    updateLayout();

    const resizeObserver = new ResizeObserver(updateLayout);

    if (viewportRef.current) resizeObserver.observe(viewportRef.current);
    if (contentRef.current) resizeObserver.observe(contentRef.current);
    if (scrollbarTrackRef.current) resizeObserver.observe(scrollbarTrackRef.current);

    window.addEventListener("resize", updateLayout);

    return () => {
      resizeObserver.disconnect();
      window.removeEventListener("resize", updateLayout);
    };
  }, [filteredScenarios]);

  useEffect(() => {
    if (!draggingThumb && !draggingRail) return;

    function handlePointerMove(event: PointerEvent) {
      if (draggingThumb) {
        const track = scrollbarTrackRef.current;
        if (!track) return;

        const trackRect = track.getBoundingClientRect();
        const nextThumbLeft = clamp(
          event.clientX - trackRect.left - thumbDragOffsetRef.current,
          0,
          maxThumbLeft,
        );

        setScrollLeft(
          clamp(
            maxThumbLeft === 0 ? 0 : (nextThumbLeft / maxThumbLeft) * maxScroll,
            0,
            maxScroll,
          ),
        );
        return;
      }

      const dragState = dragStateRef.current;
      if (!dragState.active) return;

      const deltaX = event.clientX - dragState.startX;
      if (Math.abs(deltaX) > 4) {
        dragState.moved = true;
      }

      setScrollLeft(clamp(dragState.startScrollLeft - deltaX, 0, maxScroll));
    }

    function handlePointerUp() {
      if (dragStateRef.current.moved) {
        suppressClickRef.current = true;
        window.setTimeout(() => {
          suppressClickRef.current = false;
        }, 0);
      }

      dragStateRef.current = {
        active: false,
        startX: 0,
        startScrollLeft: 0,
        moved: false,
      };
      setDraggingThumb(false);
      setDraggingRail(false);
      document.body.style.userSelect = "";
    }

    window.addEventListener("pointermove", handlePointerMove);
    window.addEventListener("pointerup", handlePointerUp);

    return () => {
      window.removeEventListener("pointermove", handlePointerMove);
      window.removeEventListener("pointerup", handlePointerUp);
      document.body.style.userSelect = "";
    };
  }, [draggingRail, draggingThumb, maxScroll, maxThumbLeft]);

  function handleViewportPointerDown(event: ReactPointerEvent<HTMLDivElement>) {
    if (event.pointerType === "mouse" && event.button !== 0) {
      return;
    }
    if (maxScroll === 0) {
      return;
    }

    event.preventDefault();
    dragStateRef.current = {
      active: true,
      startX: event.clientX,
      startScrollLeft: scrollLeft,
      moved: false,
    };
    setDraggingRail(true);
    document.body.style.userSelect = "none";
  }

  function handleViewportWheel(event: ReactWheelEvent<HTMLDivElement>) {
    const delta = Math.abs(event.deltaX) > 0 ? event.deltaX : event.shiftKey ? event.deltaY : 0;

    if (delta === 0 || maxScroll === 0) {
      return;
    }

    event.preventDefault();
    setScrollPosition(scrollLeft + delta);
  }

  function handleTrackPointerDown(event: ReactPointerEvent<HTMLDivElement>) {
    const trackRect = event.currentTarget.getBoundingClientRect();
    const clickX = event.clientX - trackRect.left;
    const targetThumbLeft = clamp(clickX - thumbWidth / 2, 0, maxThumbLeft);
    setScrollPosition(maxThumbLeft === 0 ? 0 : (targetThumbLeft / maxThumbLeft) * maxScroll);
  }

  function handleThumbPointerDown(event: ReactPointerEvent<HTMLButtonElement>) {
    event.stopPropagation();
    const thumbRect = event.currentTarget.getBoundingClientRect();
    thumbDragOffsetRef.current = event.clientX - thumbRect.left;
    setDraggingThumb(true);
    document.body.style.userSelect = "none";
  }

  function handleCardClick(event: ReactMouseEvent<HTMLAnchorElement>) {
    if (!suppressClickRef.current) {
      return;
    }

    event.preventDefault();
    event.stopPropagation();
  }

  return (
    <section className="fade-in-up mt-5">
      <div className="px-1">
        <div
          data-tutorial-target="scenario-filters"
          className="glass-card rounded-[22px] border border-[var(--line)] px-3 py-2.5 sm:rounded-[26px] sm:px-5 sm:py-4"
        >
          <div className="flex items-center justify-between gap-3 lg:hidden">
            <div className="min-w-0">
              <p className="text-[10px] font-semibold uppercase tracking-[0.18em] text-[var(--accent-gold)]">
                Filtres
              </p>
              <p className="mt-0.5 text-xs text-[var(--foreground)]">
                {filteredScenarios.length} cas pratique{filteredScenarios.length > 1 ? "s" : ""}
              </p>
            </div>
            <button
              type="button"
              onClick={() => setMobileFiltersOpen((open) => !open)}
              className="rounded-full border border-[var(--line)] bg-white px-3 py-1.5 text-xs font-semibold text-[var(--foreground)] transition-colors hover:border-[var(--primary)] hover:text-[var(--primary)]"
            >
              {mobileFiltersOpen ? "Masquer" : "Filtres"}
            </button>
          </div>

          <div className={`${mobileFiltersOpen ? "mt-3 flex" : "hidden"} flex-col gap-3 lg:mt-0 lg:flex lg:flex-row lg:items-start lg:justify-between lg:gap-4`}>
            <div className="min-w-0">
              <p className="hidden text-xs font-semibold uppercase tracking-[0.22em] text-[var(--accent-gold)] lg:block">
                Filtres
              </p>
              <div className="flex flex-wrap gap-1.5 lg:mt-3 lg:gap-2">
                {difficultyOptions.map((option) => (
                  <button
                    key={option}
                    type="button"
                    onClick={() => setSelectedDifficulty(option)}
                    className={selectedDifficulty === option
                      ? "rounded-full bg-[rgba(23,117,186,0.12)] px-3 py-1.5 text-xs font-semibold text-[var(--primary)] lg:px-4 lg:py-2 lg:text-sm"
                      : "rounded-full border border-[var(--line)] bg-white px-3 py-1.5 text-xs font-semibold text-[var(--foreground)] transition-colors hover:border-[var(--primary)] hover:text-[var(--primary)] lg:px-4 lg:py-2 lg:text-sm"}
                  >
                    {option}
                  </button>
                ))}
              </div>
            </div>

            <div className="min-w-0 lg:max-w-[48%]">
              <p className="hidden text-xs font-semibold uppercase tracking-[0.22em] text-[var(--primary)] lg:block">
                Tags
              </p>
              <div className="flex flex-wrap gap-1.5 lg:mt-3 lg:gap-2">
                {tagOptions.slice(0, 6).map((option) => (
                  <button
                    key={option}
                    type="button"
                    onClick={() => setSelectedTag(option)}
                    className={selectedTag === option
                      ? "rounded-full bg-[rgba(216,142,4,0.14)] px-3 py-1.5 text-xs font-semibold text-[var(--accent-gold)] lg:px-4 lg:py-2 lg:text-sm"
                      : "rounded-full border border-[var(--line)] bg-white px-3 py-1.5 text-xs font-semibold text-[var(--foreground)] transition-colors hover:border-[var(--accent-gold)] hover:text-[var(--accent-gold)] lg:px-4 lg:py-2 lg:text-sm"}
                  >
                    {option}
                  </button>
                ))}
              </div>
            </div>
          </div>
        </div>
      </div>

      <div
        data-tutorial-target="scenario-cards"
        className="px-1 pt-1 pb-4 sm:pt-2"
      >
        <div
          ref={viewportRef}
          className={`overflow-hidden px-1 py-2 ${draggingRail ? "cursor-grabbing" : "cursor-grab"}`}
          onPointerDownCapture={handleViewportPointerDown}
          onWheel={handleViewportWheel}
          style={{ touchAction: "pan-y" }}
        >
          <div
            ref={contentRef}
            className="flex gap-5"
            style={{ transform: `translateX(-${scrollLeft}px)` }}
          >
            {filteredScenarios.length > 0 ? (
              filteredScenarios.map((scenario, index) => (
                <Link
                  key={scenario.templateId}
                  href={`/scenario/${scenario.id}`}
                  draggable={false}
                  onClickCapture={handleCardClick}
                  onDragStart={(event) => event.preventDefault()}
                  className="group relative flex min-h-[340px] w-[286px] shrink-0 select-none flex-col overflow-hidden rounded-[24px] border border-[rgba(216,222,227,0.9)] bg-white p-4 shadow-none transition-transform duration-300 hover:-translate-y-1 sm:min-h-[380px] sm:w-[360px] sm:rounded-[30px] sm:p-6 xl:w-[390px]"
                  style={{ animationDelay: `${index * 80}ms` }}
                >
                  <div
                    className="absolute inset-x-0 top-0 h-1.5"
                    style={{ backgroundColor: getDifficultyColor(scenario.difficulty) }}
                  />
                  <div className="flex items-start justify-between gap-3 sm:gap-4">
                    <div>
                      <span className="inline-flex rounded-full bg-[var(--surface-muted)] px-2.5 py-1 text-[10px] font-semibold uppercase tracking-[0.18em] text-[var(--foreground)] sm:px-3 sm:text-xs sm:tracking-[0.22em]">
                        {getDifficultyLabel(scenario.difficulty)}
                      </span>
                      <p className="mt-2 text-xs font-semibold uppercase tracking-[0.16em] text-[var(--primary)] sm:mt-3 sm:text-sm sm:tracking-[0.18em]">
                        {scenario.targetSkill}
                      </p>
                    </div>
                    <span className="rounded-full border border-[var(--line)] px-2.5 py-1 text-[10px] font-semibold text-[var(--foreground)] sm:px-3 sm:text-xs">
                      {formatScenarioDurationLabel(scenario.maxTurns)}
                    </span>
                  </div>

                  <div className="mt-4 flex-1 sm:mt-5">
                    <h2 className="text-xl font-extrabold tracking-[-0.03em] text-[var(--ink)] sm:text-2xl">
                      {scenario.title}
                    </h2>
                    <p className="mt-2 text-xs leading-5 text-[var(--foreground)] sm:mt-3 sm:text-sm sm:leading-7">
                      {scenario.shortBrief}
                    </p>

                    <div className="mt-4 flex flex-wrap gap-1.5 sm:mt-5 sm:gap-2">
                      {scenario.tags.map((tag) => (
                        <span
                          key={tag.id}
                          className="rounded-full bg-[rgba(23,117,186,0.08)] px-2.5 py-1 text-[10px] font-semibold text-[var(--primary)] sm:px-3 sm:text-xs"
                        >
                          {tag.label}
                        </span>
                      ))}
                    </div>

                    <dl className="mt-4 space-y-2 text-xs sm:mt-6 sm:space-y-3 sm:text-sm">
                      <div>
                        <dt className="font-semibold text-[var(--accent-red)]">
                          Collaborateur
                        </dt>
                        <dd className="text-[var(--foreground)]">
                          {scenario.employeeProfile.name}, {scenario.employeeProfile.role}
                        </dd>
                      </div>
                      <div>
                        <dt className="font-semibold text-[var(--accent-red)]">
                          Enjeu
                        </dt>
                        <dd className="text-[var(--foreground)]">
                          {scenario.managerGoal}
                        </dd>
                      </div>
                    </dl>
                  </div>

                  <div className="mt-4 flex items-center justify-between border-t border-[var(--line)] pt-4 sm:mt-6 sm:pt-5">
                    <span className="text-xs font-semibold text-[var(--foreground)] sm:text-sm">
                      Démarrer l&apos;entraînement
                    </span>
                    <span className="rounded-full bg-[var(--primary)] px-3 py-1.5 text-xs font-semibold text-white transition-colors group-hover:bg-[var(--primary-strong)] sm:px-4 sm:py-2 sm:text-sm">
                      Ouvrir
                    </span>
                  </div>
                </Link>
              ))
            ) : (
              <div className="glass-card flex min-h-[260px] w-full items-center justify-center rounded-[30px] border border-[var(--line)] px-6 py-10 text-center">
                <div>
                  <p className="text-sm font-semibold uppercase tracking-[0.22em] text-[var(--accent-red)]">
                    Aucun résultat
                  </p>
                  <p className="mt-3 text-base leading-7 text-[var(--foreground)]">
                    Aucun cas pratique ne correspond aux filtres sélectionnés.
                  </p>
                </div>
              </div>
            )}
          </div>
        </div>
      </div>

      <div
        ref={scrollbarTrackRef}
        className="mt-2 h-3 rounded-full bg-[rgba(216,222,227,0.9)] shadow-[inset_0_1px_2px_rgba(35,52,61,0.08)]"
        onPointerDown={handleTrackPointerDown}
      >
        <button
          type="button"
          aria-label="Faire défiler les cas pratiques"
          className={`block h-3 rounded-full border border-white/80 bg-[linear-gradient(90deg,#1775BA_0%,#D88E04_100%)] shadow-[0_6px_18px_rgba(23,117,186,0.22)] transition-transform ${draggingThumb ? "scale-y-110" : ""}`}
          style={{ width: `${thumbWidth}px`, transform: `translateX(${thumbLeft}px)` }}
          onPointerDown={handleThumbPointerDown}
        />
      </div>
    </section>
  );
}
