"use client";

import { ChevronUpIcon, SearchIcon } from "@/assets/icons";
import { cn } from "@/lib/utils";
import gsap from "gsap";
import { type ReactNode, useLayoutEffect, useRef, useState } from "react";
import IsVisible from "./IsVisible";

export interface InlineListFiltersPanelProps {
  title: string;
  description?: string;
  /** Computed by the parent from watched form values */
  activeFilterCount: number;
  children: ReactNode;
  /** Initial collapsed state (default false) */
  defaultOpen?: boolean;
  panelToggleDataCy?: string;
  expandAriaLabel: string;
  collapseAriaLabel: string;
  className?: string;
}

/**
 * Shared inline filter shell: collapsible header + GSAP height animation for the panel body.
 * Wrap your `<form>...</form>` (or fragment) as `children`.
 */
export default function InlineListFiltersPanel({
  title,
  description,
  activeFilterCount,
  children,
  defaultOpen = false,
  panelToggleDataCy,
  expandAriaLabel,
  collapseAriaLabel,
  className,
}: InlineListFiltersPanelProps) {
  const [panelOpen, setPanelOpen] = useState(Boolean(defaultOpen));
  /** Header stays square-bottom until collapse GSAP finishes so radius does not pop early */
  const [headerFlushBottom, setHeaderFlushBottom] = useState(false);

  const panelOuterRef = useRef<HTMLDivElement>(null);
  const panelInnerRef = useRef<HTMLDivElement>(null);
  const chevronRef = useRef<HTMLSpanElement>(null);
  const prevPanelOpen = useRef(panelOpen);

  useLayoutEffect(() => {
    const outer = panelOuterRef.current;
    const inner = panelInnerRef.current;
    const chevron = chevronRef.current;
    if (!outer || !inner) return;

    gsap.set(outer, { height: panelOpen ? "auto" : 0 });
    gsap.set(inner, {
      opacity: panelOpen ? 1 : 0,
      y: panelOpen ? 0 : -14,
      scale: panelOpen ? 1 : 0.995,
    });
    if (chevron)
      gsap.set(chevron, {
        rotation: panelOpen ? 0 : 180,
        transformOrigin: "50% 50%",
      });
    if (!panelOpen) {
      setHeaderFlushBottom(false);
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps -- mount sync only
  }, []);

  useLayoutEffect(() => {
    const outer = panelOuterRef.current;
    const inner = panelInnerRef.current;
    const chevron = chevronRef.current;
    if (!outer || !inner) return;

    if (prevPanelOpen.current === panelOpen) return;
    prevPanelOpen.current = panelOpen;

    const reduced =
      typeof window !== "undefined" &&
      window.matchMedia("(prefers-reduced-motion: reduce)").matches;

    gsap.killTweensOf([outer, inner, chevron].filter(Boolean));

    if (reduced) {
      gsap.set(outer, { height: panelOpen ? "auto" : 0 });
      gsap.set(inner, {
        opacity: panelOpen ? 1 : 0,
        y: panelOpen ? 0 : -10,
        scale: 1,
      });
      if (chevron) gsap.set(chevron, { rotation: panelOpen ? 0 : 180 });
      setHeaderFlushBottom(panelOpen);
      return;
    }

    const ctx = gsap.context(() => {
      if (panelOpen) {
        setHeaderFlushBottom(true);
        const targetH = inner.scrollHeight;
        gsap.set(outer, { height: 0 });
        gsap.set(inner, { opacity: 0, y: -36, scale: 0.985 });

        const tl = gsap.timeline({ defaults: { ease: "none" } });
        tl.to(outer, {
          height: targetH,
          duration: 0.62,
          ease: "power4.out",
          onComplete: () => {
            gsap.set(outer, { height: "auto" });
          },
        }).to(
          inner,
          {
            opacity: 1,
            y: 0,
            scale: 1,
            duration: 0.52,
            ease: "power3.out",
          },
          "-=0.5",
        );

        if (chevron) {
          tl.to(
            chevron,
            { rotation: 0, duration: 0.48, ease: "back.out(1.35)" },
            "-=0.52",
          );
        }
      } else {
        const currentH = Math.max(outer.offsetHeight, inner.scrollHeight);
        gsap.set(outer, { height: currentH });

        const tl = gsap.timeline({
          onComplete: () => {
            setHeaderFlushBottom(false);
          },
        });
        tl.to(inner, {
          opacity: 0,
          y: -22,
          scale: 0.992,
          duration: 0.3,
          ease: "power2.in",
        }).to(
          outer,
          {
            height: 0,
            duration: 0.48,
            ease: "power3.inOut",
          },
          "-=0.12",
        );
        if (chevron) {
          tl.to(
            chevron,
            { rotation: 180, duration: 0.42, ease: "power2.inOut" },
            0,
          );
        }
      }
    }, outer);

    return () => ctx.revert();
  }, [panelOpen]);

  return (
    <div className={cn("relative mb-8", className)}>
      <div className="relative overflow-hidden rounded-[1.75rem] border border-stroke/60 bg-white dark:border-dark-3 dark:bg-dark-2">
        <button
          type="button"
          onClick={() => setPanelOpen((o) => !o)}
          aria-expanded={panelOpen}
          aria-label={panelOpen ? collapseAriaLabel : expandAriaLabel}
          data-cy={panelToggleDataCy}
          className={cn(
            "flex w-full flex-col gap-3 px-4 py-4 text-start transition-colors sm:flex-row sm:items-center sm:justify-between sm:gap-4 sm:px-6 sm:py-5",
            "rounded-[1.65rem] border border-transparent",
            "hover:border-stroke/50 hover:bg-white/70 dark:hover:border-white/[0.08] dark:hover:bg-dark-3/50",
            "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/40 focus-visible:ring-offset-2 focus-visible:ring-offset-white dark:focus-visible:ring-offset-dark-2",
            headerFlushBottom &&
              "rounded-b-none border-b border-stroke/45 dark:border-white/[0.07]",
          )}
        >
          <div className="flex min-w-0 flex-1 items-start gap-3 sm:items-center">
            <span className="mt-0.5 flex h-11 w-11 shrink-0 items-center justify-center rounded-2xl bg-gradient-to-br from-primary to-violet-600 text-white sm:mt-0">
              <SearchIcon className="h-5 w-5 opacity-95" />
            </span>
            <div className="min-w-0 flex-1">
              <span className="block text-balance text-lg font-bold leading-snug tracking-tight text-dark dark:text-white">
                {title}
              </span>
              <IsVisible condition={!!description}>
                <p className="mt-0.5 max-w-xl text-sm text-dark-5 dark:text-dark-6">
                  {description}
                </p>
              </IsVisible>
            </div>
          </div>
          <div className="flex w-full min-w-0 items-center justify-between gap-3 pl-14 sm:ml-auto sm:w-auto sm:shrink-0 sm:justify-end sm:pl-0">
            {activeFilterCount > 0 ? (
              <div className="flex items-center gap-2 rounded-full border border-primary/25 bg-primary/10 px-3 py-1.5 dark:border-primary/35 dark:bg-primary/15">
                <span className="text-xs font-semibold uppercase tracking-wide text-primary">
                  {activeFilterCount} active
                </span>
              </div>
            ) : (
              <span className="inline-flex min-w-0 max-w-[calc(100%-2rem)] items-center truncate rounded-full border border-stroke/50 bg-white/60 px-3 py-1.5 text-xs font-medium text-dark-5 dark:border-white/10 dark:bg-dark-3/80 dark:text-dark-6">
                No filters applied
              </span>
            )}
            <span
              ref={chevronRef}
              className="inline-flex h-5 w-5 shrink-0 text-primary dark:text-primary/90"
              aria-hidden
            >
              <ChevronUpIcon className="h-5 w-5" />
            </span>
          </div>
        </button>

        <div
          ref={panelOuterRef}
          className="overflow-hidden"
          aria-hidden={!panelOpen}
        >
          <div ref={panelInnerRef} className="will-change-transform">
            {children}
          </div>
        </div>
      </div>
    </div>
  );
}
