<template>
  <section id="testimonials" ref="testimonialsSectionRef" class="pt-28 pb-10">
    <div class="container mx-auto max-w-5xl px-4">
      <h2
        class="text-2xl sm:text-5xl font-bold tracking-tight text-dark mb-16 text-center"
      >
        {{ section.title }}
      </h2>

      <div
        class="-mx-4 flex snap-x snap-mandatory gap-4 overflow-x-auto px-4 pb-4 md:hidden"
      >
        <article
          v-for="review in section.reviews ?? []"
          :key="`mobile-${review.url}`"
          ref="mobileCardRefs"
          class="shrink-0 snap-center w-[78vw] max-w-[320px] rounded-2xl border border-black/10 bg-white p-5 pb-8! rounded-[100px_0px_623px_77px/0px_50px_128px_58px]"
        >
          <div class="mb-3 flex text-[#f39c12]">
            <span v-for="star in 5" :key="star">
              {{ star <= review.rating ? "★" : "☆" }}
            </span>
          </div>

          <div
            class="mb-5 text-sm leading-relaxed text-black/70 [&_p]:mb-3 [&_p:last-child]:mb-0 [&_strong]:font-bold [&_em]:italic"
            v-html="renderMarkdown(`“${review.comment}”`)"
          />

          <div class="flex flex-col gap-2">
            <p class="font-semibold text-black">{{ review.name }}</p>
            <a
              :href="review.url"
              target="_blank"
              rel="noopener noreferrer"
              class="inline-flex gap-x-2 text-xs font-bold text-highlight hover:underline"
            >
              {{ t("View") }}
              <component :is="icons.arrowRight" class="w-4 h-4" />
            </a>
          </div>
        </article>
      </div>

      <div
        class="hidden gap-y-12 gap-x-6 md:grid md:grid-cols-2 lg:grid-cols-3"
      >
        <article
          v-for="review in section.reviews ?? []"
          :key="`desktop-${review.url}`"
          ref="desktopCardRefs"
          class="rounded-2xl border rounded-[100px_0px_623px_77px/0px_50px_128px_58px] border-black/10 bg-white p-5 pb-8! transition hover:-translate-y-1 hover:shadow-md"
        >
          <div class="mb-3 flex text-[#f39c12]">
            <span v-for="star in 5" :key="star">
              {{ star <= review.rating ? "★" : "☆" }}
            </span>
          </div>

          <div class="flex flex-col">
            <div
              class="mb-5 text-sm leading-relaxed text-black/70 [&_p]:mb-3 [&_p:last-child]:mb-0 [&_strong]:font-bold [&_em]:italic"
              v-html="renderMarkdown(`“${review.comment}”`)"
            />

            <div class="flex flex-col gap-2">
              <p class="font-semibold text-black">{{ review.name }}</p>
              <a
                :href="review.url"
                target="_blank"
                rel="noopener noreferrer"
                class="inline-flex gap-x-2 text-xs font-bold text-highlight hover:underline"
              >
                {{ t("View") }}
                <component :is="icons.arrowRight" class="w-4 h-4" />
              </a>
            </div>
          </div>
        </article>
      </div>

      <div class="mt-16 lg:mt-24 text-center">
        <Button
          :label="section.ctaText"
          :href="section.googleReviewsUrl ?? '#'"
          external
          variant="outlined-highlight"
        />
      </div>
    </div>
  </section>
</template>

<script setup lang="ts">
import { nextTick, onBeforeUnmount, onMounted, ref } from "vue";
import { useI18n } from "vue-i18n";
import { useIcons } from "@/composables/useIcons";
import MarkdownIt from "markdown-it";
import gsap from "gsap";
import { ScrollTrigger } from "gsap/ScrollTrigger";

gsap.registerPlugin(ScrollTrigger);

const icons = useIcons();
const { t } = useI18n();

type Review = {
  name: string;
  rating: number;
  label: string;
  comment: string;
  url: string;
};

type TestimonialsSection = {
  __component: "sections.testimonials";
  enabled: boolean;
  title?: string;
  ctaText?: string;
  googleReviewsUrl?: string;
  reviews?: Review[];
};

const { section } = defineProps<{
  section: TestimonialsSection;
}>();

const md = new MarkdownIt({
  html: false,
  breaks: false,
  linkify: true,
});

const renderMarkdown = (value?: string) => {
  if (!value) return "";
  return md.render(value);
};

const testimonialsSectionRef = ref<HTMLElement | null>(null);
const mobileCardRefs = ref<HTMLElement[]>([]);
const desktopCardRefs = ref<HTMLElement[]>([]);

let ctx: gsap.Context | null = null;
let mm: gsap.MatchMedia | null = null;

const createCardsAnimation = (items: HTMLElement[], isDesktop: boolean) => {
  if (!testimonialsSectionRef.value || !items.length) return;

  gsap.set(items, {
    y: isDesktop ? 36 : 20,
    opacity: 0,
    scale: isDesktop ? 0.96 : 0.9,
  });

  gsap.to(items, {
    y: 0,
    opacity: 1,
    scale: 1,
    ease: isDesktop ? "power3.out" : "back.out(2.2)",
    stagger: {
      each: isDesktop ? 0.08 : 0.06,
      from: isDesktop ? "start" : "random",
    },
    scrollTrigger: {
      trigger: testimonialsSectionRef.value,
      start: "top 75%",
      end: "top 20%",
      scrub: 1,
      invalidateOnRefresh: true,
    },
  });
};

onMounted(async () => {
  await nextTick();

  if (!testimonialsSectionRef.value) return;

  ctx = gsap.context(() => {
    mm = gsap.matchMedia();

    mm.add("(min-width: 768px)", () => {
      createCardsAnimation(desktopCardRefs.value, true);
    });

    mm.add("(max-width: 767px)", () => {
      createCardsAnimation(mobileCardRefs.value, false);
    });
  }, testimonialsSectionRef.value);
});

onBeforeUnmount(() => {
  mm?.revert();
  ctx?.revert();

  mm = null;
  ctx = null;
});
</script>
