"use client";

/**
 * Client-side filterable list for /studies.
 *
 * The server page (`./page.tsx`) fetches the cached `Study[]` from PubMed and
 * passes it here as props. All interactivity — search, journal filter, year
 * filter, sort order — lives in this component. Using a single array in state
 * means we can filter instantly without another network roundtrip.
 *
 * Visual style mirrors `components/blog/BlogGrid.tsx` so the Studies surface
 * reads as a sibling of the Blog surface: mist-gradient hero, rounded-full
 * topic pills, card borders with hover lift.
 */

import Link from "next/link";
import { useMemo, useState } from "react";
import { FileText } from "lucide-react";

import { labelForJournal, ORTHO_JOURNALS } from "@/lib/studies/journals";
import type { Study } from "@/lib/studies/types";

type Props = {
  studies: Study[];
};

type SortKey = "newest" | "journal";

const DATE_FMT = new Intl.DateTimeFormat("en-GB", {
  year: "numeric",
  month: "short",
  day: "numeric",
});

function formatPubDate(iso: string): string {
  const d = new Date(iso);
  if (Number.isNaN(d.getTime())) return "";
  return DATE_FMT.format(d);
}

function truncate(text: string, n: number): string {
  if (!text) return "";
  if (text.length <= n) return text;
  return text.slice(0, n).replace(/\s+\S*$/, "") + "…";
}

function formatAuthors(authors: string[]): string {
  if (authors.length === 0) return "";
  if (authors.length <= 3) return authors.join(", ");
  return `${authors.slice(0, 3).join(", ")}, et al`;
}

export function StudiesList({ studies }: Props) {
  const [query, setQuery] = useState("");
  const [journal, setJournal] = useState<string>("All");
  const [year, setYear] = useState<string>("All");
  const [sort, setSort] = useState<SortKey>("newest");

  const journalOptions = useMemo(() => {
    const present = new Set(studies.map((s) => s.journal).filter(Boolean));
    // Preserve the allowlist order, only include journals that actually have results.
    return ORTHO_JOURNALS.filter((j) => present.has(j.pubmed));
  }, [studies]);

  const yearOptions = useMemo(() => {
    const years = Array.from(new Set(studies.map((s) => s.year))).sort(
      (a, b) => b - a,
    );
    return years;
  }, [studies]);

  const filtered = useMemo(() => {
    const q = query.trim().toLowerCase();
    const matched = studies.filter((s) => {
      if (journal !== "All" && s.journal !== journal) return false;
      if (year !== "All" && String(s.year) !== year) return false;
      if (!q) return true;
      return (
        s.title.toLowerCase().includes(q) ||
        s.abstract.toLowerCase().includes(q) ||
        s.authors.some((a) => a.toLowerCase().includes(q))
      );
    });

    if (sort === "journal") {
      return [...matched].sort((a, b) => {
        const aLabel = labelForJournal(a.journal);
        const bLabel = labelForJournal(b.journal);
        const byJournal = aLabel.localeCompare(bLabel);
        if (byJournal !== 0) return byJournal;
        // Stable secondary sort: newest first within a journal.
        return (
          new Date(b.pubDate).getTime() - new Date(a.pubDate).getTime()
        );
      });
    }

    // Newest first (server already sorts, but we re-sort defensively so the
    // control is authoritative after filtering).
    return [...matched].sort(
      (a, b) => new Date(b.pubDate).getTime() - new Date(a.pubDate).getTime(),
    );
  }, [studies, query, journal, year, sort]);

  const hasActiveFilters =
    query.trim() !== "" || journal !== "All" || year !== "All";

  function clearFilters() {
    setQuery("");
    setJournal("All");
    setYear("All");
  }

  return (
    <div>
      <div className="mb-6 grid grid-cols-1 gap-3 md:grid-cols-[1fr_auto_auto_auto]">
        <input
          type="search"
          value={query}
          onChange={(e) => setQuery(e.target.value)}
          placeholder="Search studies, authors, abstracts…"
          className="w-full rounded-lg border border-[var(--color-line)] bg-white px-4 py-3 text-[15px] text-[var(--color-ink)] placeholder:text-[var(--color-slate)] focus:border-[var(--color-blue)] focus:outline-none focus:ring-2 focus:ring-[var(--color-blue)]/20"
          aria-label="Search studies"
        />
        <select
          value={journal}
          onChange={(e) => setJournal(e.target.value)}
          className="rounded-lg border border-[var(--color-line)] bg-white px-4 py-3 text-[14px] font-semibold text-[var(--color-ink)] focus:border-[var(--color-blue)] focus:outline-none focus:ring-2 focus:ring-[var(--color-blue)]/20"
          aria-label="Filter by journal"
        >
          <option value="All">All journals</option>
          {journalOptions.map((j) => (
            <option key={j.pubmed} value={j.pubmed}>
              {j.label}
            </option>
          ))}
        </select>
        <select
          value={year}
          onChange={(e) => setYear(e.target.value)}
          className="rounded-lg border border-[var(--color-line)] bg-white px-4 py-3 text-[14px] font-semibold text-[var(--color-ink)] focus:border-[var(--color-blue)] focus:outline-none focus:ring-2 focus:ring-[var(--color-blue)]/20"
          aria-label="Filter by year"
        >
          <option value="All">All years</option>
          {yearOptions.map((y) => (
            <option key={y} value={String(y)}>
              {y}
            </option>
          ))}
        </select>
        <select
          value={sort}
          onChange={(e) => setSort(e.target.value as SortKey)}
          className="rounded-lg border border-[var(--color-line)] bg-white px-4 py-3 text-[14px] font-semibold text-[var(--color-ink)] focus:border-[var(--color-blue)] focus:outline-none focus:ring-2 focus:ring-[var(--color-blue)]/20"
          aria-label="Sort studies"
        >
          <option value="newest">Sort: Newest</option>
          <option value="journal">Sort: Journal A–Z</option>
        </select>
      </div>

      <div className="mb-8 flex flex-wrap items-center justify-between gap-3 text-[13px] text-[var(--color-slate)]">
        <div>
          Showing{" "}
          <span className="font-semibold text-[var(--color-ink)]">
            {filtered.length}
          </span>{" "}
          of {studies.length} recent studies
        </div>
        {hasActiveFilters && (
          <button
            type="button"
            onClick={clearFilters}
            className="text-[13px] font-semibold text-[var(--color-blue)] hover:text-[var(--color-blue-deep)]"
          >
            Clear filters
          </button>
        )}
      </div>

      {filtered.length === 0 ? (
        <div className="mx-auto flex max-w-xl flex-col items-center rounded-lg border border-dashed border-[var(--color-line)] bg-[var(--color-mist)]/40 px-6 py-16 text-center">
          <div
            aria-hidden
            className="flex h-16 w-16 items-center justify-center rounded-full border border-[var(--color-line)] bg-white text-[var(--color-blue)]"
          >
            <svg
              xmlns="http://www.w3.org/2000/svg"
              viewBox="0 0 24 24"
              fill="none"
              stroke="currentColor"
              strokeWidth="1.8"
              strokeLinecap="round"
              strokeLinejoin="round"
              className="h-7 w-7"
            >
              <circle cx="11" cy="11" r="7" />
              <path d="m20 20-3.5-3.5" />
            </svg>
          </div>
          <h3 className="mt-5 font-display text-[20px] font-extrabold text-[var(--color-ink)]">
            No studies match your filters.
          </h3>
          <p className="mt-2 max-w-sm text-[14px] leading-relaxed text-[var(--color-slate)]">
            Try broadening your search terms, picking a different journal, or
            clearing the year filter.
          </p>
          <button
            type="button"
            onClick={clearFilters}
            className="mt-5 inline-flex items-center gap-1 rounded-lg bg-[var(--color-blue)] px-5 py-2.5 text-[13px] font-semibold text-white transition-all duration-200 hover:scale-[1.02] hover:bg-[var(--color-blue-deep)]"
          >
            Clear filters
          </button>
        </div>
      ) : (
        <div className="grid grid-cols-1 gap-6 md:grid-cols-2 lg:grid-cols-3">
          {filtered.map((s) => {
            // Prefer the journal's own article page via DOI so a click takes
            // the reader straight to the publisher (where the journal lives).
            // Fall back to PubMed if this record hasn't had a DOI indexed yet.
            const journalLabel = labelForJournal(s.journal);
            const hasDoi = Boolean(s.doi);
            const targetUrl = hasDoi
              ? `https://doi.org/${s.doi}`
              : s.pubmedUrl;
            const targetLabel = hasDoi
              ? `Open at ${journalLabel}`
              : "Read on PubMed";
            const ariaLabel = hasDoi
              ? `Open "${s.title}" at ${journalLabel}`
              : `Read "${s.title}" on PubMed`;
            return (
              <article
                key={s.pmid}
                className="group relative flex flex-col rounded-lg border border-[var(--color-line)] bg-white p-6 transition-all duration-200 hover:-translate-y-0.5 hover:border-[var(--color-blue)] hover:shadow-md motion-reduce:transform-none motion-reduce:transition-none"
              >
                {/*
                  Whole-card outbound link to the journal via DOI (falls back
                  to PubMed when no DOI is available). Stretched anchor makes
                  the entire card clickable; internal links sit above via z-index.
                */}
                <a
                  href={targetUrl}
                  target="_blank"
                  rel="noopener noreferrer"
                  aria-label={ariaLabel}
                  className="absolute inset-0 z-0 rounded-lg"
                />
                <div className="relative z-[1] flex items-start gap-3">
                  <div
                    aria-hidden
                    className="flex h-11 w-11 shrink-0 items-center justify-center rounded-md border border-[var(--color-blue)]/20 bg-[var(--color-blue)]/10 text-[var(--color-blue-deep)]"
                  >
                    <FileText className="h-5 w-5" strokeWidth={1.8} />
                  </div>
                  <div className="flex min-w-0 flex-wrap items-center gap-2">
                    <span
                      className="inline-flex max-w-full items-center gap-1 truncate rounded-full border border-[var(--color-blue)]/20 bg-[var(--color-blue)]/10 px-3 py-1 text-[11px] font-bold uppercase tracking-wider text-[var(--color-blue-deep)]"
                      title={s.journal}
                    >
                      <span
                        aria-hidden
                        className="inline-block h-1.5 w-1.5 shrink-0 rounded-full bg-[var(--color-blue)]"
                      />
                      <span className="truncate">{journalLabel}</span>
                    </span>
                    {s.pubDate && (
                      <span className="text-[11px] font-semibold uppercase tracking-wider text-[var(--color-slate)]">
                        {formatPubDate(s.pubDate)}
                      </span>
                    )}
                  </div>
                </div>
                <h3 className="relative z-[1] mt-4 font-display text-[17px] font-bold leading-snug text-[var(--color-ink)] group-hover:text-[var(--color-blue)]">
                  {s.title}
                </h3>
                {s.authors.length > 0 && (
                  <p className="relative z-[1] mt-2 text-[13px] italic text-[var(--color-slate)]">
                    {formatAuthors(s.authors)}
                  </p>
                )}
                {s.abstract && (
                  <p className="relative z-[1] mt-3 text-[13px] leading-relaxed text-[var(--color-slate)]">
                    {truncate(s.abstract, 200)}
                  </p>
                )}
                <div className="relative z-[2] mt-auto flex items-center justify-between gap-3 pt-4 text-[13px] font-semibold">
                  <span className="text-[var(--color-blue)]">
                    {targetLabel}
                    <span className="ml-1 transition-transform duration-200 group-hover:translate-x-1 motion-reduce:transform-none">
                      ↗
                    </span>
                  </span>
                  <Link
                    href={`/studies/${s.pmid}`}
                    className="whitespace-nowrap rounded-md border border-[var(--color-line)] px-3 py-1.5 text-[12px] text-[var(--color-slate)] transition-colors hover:border-[var(--color-blue)] hover:text-[var(--color-blue)]"
                  >
                    Read summary
                  </Link>
                </div>
              </article>
            );
          })}
        </div>
      )}
    </div>
  );
}
