"use client";

import * as React from "react";
import Link from "next/link";
import Image from "next/image";
import useEmblaCarousel from "embla-carousel-react";
import { ArrowUpRight, ChevronLeft, ChevronRight } from "lucide-react";
import type { PublicPostCard } from "@/lib/blog-service";

/**
 * Homepage "latest from the blog" carousel (Embla). Receives at most 6 minimal,
 * public post DTOs from the server — it never fetches data itself (§74). Cards
 * are real anchor links (crawlable, JS-independent navigation — §59) and images
 * are Cloudinary-backed via next/image with responsive sizes (§57/§58).
 */
export function HomeBlogCarousel({ posts }: { posts: PublicPostCard[] }) {
  const reduced = usePrefersReducedMotion();
  const [emblaRef, embla] = useEmblaCarousel({
    align: "start",
    loop: false,
    dragFree: false,
    duration: reduced ? 0 : 22,
  });

  const [canPrev, setCanPrev] = React.useState(false);
  const [canNext, setCanNext] = React.useState(false);
  const [snaps, setSnaps] = React.useState<number[]>([]);
  const [selected, setSelected] = React.useState(0);

  const onSelect = React.useCallback((e: NonNullable<typeof embla>) => {
    setCanPrev(e.canScrollPrev());
    setCanNext(e.canScrollNext());
    setSelected(e.selectedScrollSnap());
  }, []);

  React.useEffect(() => {
    if (!embla) return;
    // Syncing React state with the Embla instance (an external system) — the
    // exact use case effects are for.
    // eslint-disable-next-line react-hooks/set-state-in-effect
    setSnaps(embla.scrollSnapList());
    onSelect(embla);
    embla.on("select", onSelect).on("reInit", onSelect);
    return () => {
      embla.off("select", onSelect).off("reInit", onSelect);
    };
  }, [embla, onSelect]);

  if (!posts || posts.length === 0) return null;

  const scrollPrev = () => embla?.scrollPrev();
  const scrollNext = () => embla?.scrollNext();

  return (
    <div
      className="relative"
      role="group"
      aria-roledescription="carousel"
      aria-label="Latest Quto AI articles"
      onKeyDown={(e) => {
        if (e.key === "ArrowLeft") {
          e.preventDefault();
          scrollPrev();
        } else if (e.key === "ArrowRight") {
          e.preventDefault();
          scrollNext();
        }
      }}
    >
      {/* Viewport */}
      <div className="overflow-hidden" ref={emblaRef}>
        <div className="-ml-4 flex touch-pan-y">
          {posts.map((post, i) => (
            <div
              key={post.slug}
              role="group"
              aria-roledescription="slide"
              aria-label={`${i + 1} of ${posts.length}`}
              className="min-w-0 shrink-0 grow-0 basis-full pl-4 sm:basis-1/2 lg:basis-1/3"
            >
              <CarouselCard post={post} priority={i === 0} />
            </div>
          ))}
        </div>
      </div>

      {/* Controls */}
      <div className="mt-6 flex items-center justify-between">
        <div className="flex items-center gap-2" role="tablist" aria-label="Choose slide">
          {snaps.map((_, i) => (
            <button
              key={i}
              type="button"
              role="tab"
              aria-label={`Go to slide ${i + 1}`}
              aria-selected={i === selected}
              onClick={() => embla?.scrollTo(i)}
              className={`h-1.5 rounded-full transition-all ${
                i === selected ? "w-6 bg-foreground" : "w-1.5 bg-border hover:bg-foreground/40"
              }`}
            />
          ))}
        </div>

        <div className="flex items-center gap-2">
          <button
            type="button"
            onClick={scrollPrev}
            disabled={!canPrev}
            aria-label="Previous articles"
            className="flex size-10 items-center justify-center rounded-full border border-border bg-background text-foreground transition hover:bg-muted disabled:cursor-not-allowed disabled:opacity-40 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
          >
            <ChevronLeft className="size-4" />
          </button>
          <button
            type="button"
            onClick={scrollNext}
            disabled={!canNext}
            aria-label="Next articles"
            className="flex size-10 items-center justify-center rounded-full border border-border bg-background text-foreground transition hover:bg-muted disabled:cursor-not-allowed disabled:opacity-40 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
          >
            <ChevronRight className="size-4" />
          </button>
        </div>
      </div>
    </div>
  );
}

function CarouselCard({ post, priority }: { post: PublicPostCard; priority?: boolean }) {
  return (
    <article className="group relative flex h-full flex-col overflow-hidden rounded-2xl border border-border/80 bg-card text-card-foreground shadow-xs transition-all duration-300 hover:-translate-y-1 hover:border-foreground/30 hover:shadow-lg motion-reduce:transition-none motion-reduce:hover:translate-y-0">
      <Link
        href={`/blog/${post.slug}`}
        aria-label={post.title}
        className="block overflow-hidden focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
      >
        <div className="relative aspect-[16/9] w-full overflow-hidden bg-neutral-100 dark:bg-neutral-800">
          {post.featuredImage ? (
            <Image
              src={post.featuredImage}
              alt={post.featuredImageAlt || post.title}
              fill
              sizes="(max-width: 640px) 90vw, (max-width: 1024px) 45vw, 33vw"
              className="object-cover transition-transform duration-500 group-hover:scale-105 motion-reduce:transition-none"
              priority={priority}
            />
          ) : (
            <div className="flex h-full w-full items-center justify-center bg-gradient-to-br from-neutral-200 to-neutral-300 text-2xl font-black text-neutral-400 dark:from-neutral-800 dark:to-neutral-900">
              {post.title.slice(0, 1)}
            </div>
          )}
        </div>
      </Link>

      <div className="flex flex-1 flex-col justify-between p-5 sm:p-6">
        <div className="space-y-2.5">
          <div className="flex items-center justify-between">
            <span className="text-[11px] font-bold uppercase tracking-wider text-muted-foreground">
              {post.category}
            </span>
            <span className="text-[11px] font-medium text-muted-foreground/80">{post.readTime}</span>
          </div>
          <h3 className="text-base font-bold leading-snug tracking-tight text-foreground sm:text-lg">
            <Link
              href={`/blog/${post.slug}`}
              className="line-clamp-2 transition-colors duration-200 hover:text-[var(--accent-cyan-text)] group-hover:text-[var(--accent-cyan-text)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 rounded-xs"
            >
              {post.title}
            </Link>
          </h3>
          <p className="line-clamp-3 text-xs leading-relaxed text-muted-foreground sm:text-sm">
            {post.excerpt}
          </p>
        </div>

        <div className="mt-5 flex items-center justify-between border-t border-border/50 pt-4 text-xs text-muted-foreground">
          <span>{post.publishedDate}</span>
          <Link
            href={`/blog/${post.slug}`}
            className="flex items-center gap-1 font-semibold text-foreground transition-colors duration-200 group-hover:text-[var(--accent-cyan-text)] hover:text-[var(--accent-cyan-text)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring rounded-xs"
          >
            <span>Read</span>
            <ArrowUpRight className="size-3.5 transition-transform group-hover:translate-x-0.5 group-hover:-translate-y-0.5 motion-reduce:transition-none" />
          </Link>
        </div>
      </div>
    </article>
  );
}

function usePrefersReducedMotion() {
  const [reduced, setReduced] = React.useState(false);
  React.useEffect(() => {
    const mq = window.matchMedia("(prefers-reduced-motion: reduce)");
    // Syncing with the matchMedia external system.
    // eslint-disable-next-line react-hooks/set-state-in-effect
    setReduced(mq.matches);
    const handler = (e: MediaQueryListEvent) => setReduced(e.matches);
    mq.addEventListener("change", handler);
    return () => mq.removeEventListener("change", handler);
  }, []);
  return reduced;
}
