"use client";

import { useMemo, useState } from "react";
import { motion } from "motion/react";

import type { NewsItem } from "@/lib/news/types";
import { formatLongDate } from "@/lib/news/format";

/**
 * Client-side filter + search UI for the /news list page.
 *
 * Everything lives in component state — we don't push filter values to
 * the URL because the aggregate list is small (a few hundred items at
 * most) and a full server round-trip per keystroke would defeat the
 * caching strategy. Debouncing isn't needed for this dataset size.
 *
 * Each card renders an internal link to /news/[id] AND an outbound
 * "Read at source" link to the publisher. The internal page is a
 * neutral landing zone — we do NOT rehost article content for legal
 * reasons.
 *
 * Colocated with `page.tsx` under `/src/app/news/` because the only
 * consumer is the news list page; no other route needs this component.
 */

type Props = {
  items: NewsItem[];
  sources: Array<{ id: string; name: string }>;
  years: number[];
};

export function NewsFilters({ items, sources, years }: Props) {
  const [sourceId, setSourceId] = useState<string>("");
  const [year, setYear] = useState<string>("");
  const [query, setQuery] = useState<string>("");

  const filtered = useMemo(() => {
    const q = query.trim().toLowerCase();
    return items.filter((item) => {
      if (sourceId && item.sourceId !== sourceId) return false;
      if (year && String(item.year) !== year) return false;
      if (q) {
        const haystack =
          `${item.title} ${item.excerpt} ${item.sourceName}`.toLowerCase();
        if (!haystack.includes(q)) return false;
      }
      return true;
    });
  }, [items, sourceId, year, query]);

  return (
    <div>
      <div className="flex flex-col gap-4 border-b border-[var(--color-line)] pb-8 md:flex-row md:items-end md:gap-6">
        <div className="flex-1">
          <label
            htmlFor="news-search"
            className="block text-[11px] font-bold uppercase tracking-wider text-[var(--color-slate)]"
          >
            Search
          </label>
          <input
            id="news-search"
            type="search"
            value={query}
            onChange={(e) => setQuery(e.target.value)}
            placeholder="Title, excerpt, or source…"
            className="mt-2 w-full rounded-lg border border-[var(--color-line)] bg-white px-4 py-3 text-[15px] text-[var(--color-ink)] outline-none transition-colors focus:border-[var(--color-blue)] focus:ring-2 focus:ring-[var(--color-blue)]/20"
          />
        </div>
        <div className="md:w-56">
          <label
            htmlFor="news-source"
            className="block text-[11px] font-bold uppercase tracking-wider text-[var(--color-slate)]"
          >
            Source
          </label>
          <select
            id="news-source"
            value={sourceId}
            onChange={(e) => setSourceId(e.target.value)}
            className="mt-2 w-full rounded-lg border border-[var(--color-line)] bg-white px-4 py-3 text-[15px] text-[var(--color-ink)] outline-none transition-colors focus:border-[var(--color-blue)] focus:ring-2 focus:ring-[var(--color-blue)]/20"
          >
            <option value="">All sources</option>
            {sources.map((s) => (
              <option key={s.id} value={s.id}>
                {s.name}
              </option>
            ))}
          </select>
        </div>
        <div className="md:w-40">
          <label
            htmlFor="news-year"
            className="block text-[11px] font-bold uppercase tracking-wider text-[var(--color-slate)]"
          >
            Year
          </label>
          <select
            id="news-year"
            value={year}
            onChange={(e) => setYear(e.target.value)}
            className="mt-2 w-full rounded-lg border border-[var(--color-line)] bg-white px-4 py-3 text-[15px] text-[var(--color-ink)] outline-none transition-colors focus:border-[var(--color-blue)] focus:ring-2 focus:ring-[var(--color-blue)]/20"
          >
            <option value="">All years</option>
            {years.map((y) => (
              <option key={y} value={String(y)}>
                {y}
              </option>
            ))}
          </select>
        </div>
      </div>

      <div className="mt-6 text-[13px] text-[var(--color-slate)]">
        {filtered.length} {filtered.length === 1 ? "article" : "articles"}
        {sourceId || year || query ? " match your filters" : ""}
      </div>

      {filtered.length === 0 ? (
        <div className="mx-auto mt-16 flex max-w-xl flex-col items-center rounded-xl 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 articles match your filters yet.
          </h3>
          <p className="mt-2 max-w-sm text-[14px] leading-relaxed text-[var(--color-slate)]">
            Try a different source, another year, or broaden your search
            terms.
          </p>
          <button
            type="button"
            onClick={() => {
              setSourceId("");
              setYear("");
              setQuery("");
            }}
            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="mt-10 grid grid-cols-1 gap-6 md:grid-cols-2 lg:grid-cols-3">
          {filtered.map((item, index) => (
            <NewsCard key={item.id} item={item} index={index} />
          ))}
        </div>
      )}
    </div>
  );
}

function NewsCard({ item, index }: { item: NewsItem; index: number }) {
  return (
    <motion.a
      href={item.link}
      target="_blank"
      rel="noopener noreferrer"
      aria-label={`Read "${item.title}" at ${item.sourceName}`}
      initial={{ opacity: 0, y: 12 }}
      whileInView={{ opacity: 1, y: 0 }}
      viewport={{ once: true, margin: "-50px" }}
      transition={{ duration: 0.35, delay: Math.min(index * 0.03, 0.3) }}
      className="group flex h-full flex-col overflow-hidden rounded-xl border border-[var(--color-line)] bg-white shadow-sm transition-all duration-200 hover:-translate-y-1 hover:border-[var(--color-blue)]/40 hover:shadow-lg motion-reduce:transform-none"
    >
      <div className="relative aspect-[16/9] w-full overflow-hidden bg-[var(--color-mist)]">
        {item.imageUrl ? (
          // eslint-disable-next-line @next/next/no-img-element
          <img
            src={item.imageUrl}
            alt=""
            loading="lazy"
            decoding="async"
            referrerPolicy="no-referrer"
            className="h-full w-full object-cover transition-transform duration-300 group-hover:scale-[1.03] motion-reduce:transform-none"
          />
        ) : (
          <div
            aria-hidden
            className="flex h-full w-full items-center justify-center bg-gradient-to-br from-[var(--color-blue)]/10 via-[var(--color-mist)] to-white"
          >
            <span className="font-display text-[15px] font-bold uppercase tracking-wider text-[var(--color-blue-deep)]/70">
              {item.sourceName}
            </span>
          </div>
        )}
      </div>

      <div className="flex flex-1 flex-col p-6">
        <div className="flex flex-wrap items-center gap-2 text-[11px] font-bold uppercase tracking-wider">
          <span className="inline-flex items-center gap-1.5 rounded-full border border-[var(--color-blue)]/20 bg-[var(--color-blue)]/10 px-3 py-1 text-[var(--color-blue-deep)]">
            <span
              aria-hidden
              className="inline-block h-1.5 w-1.5 rounded-full bg-[var(--color-blue)]"
            />
            {item.sourceName}
          </span>
          <span className="text-[var(--color-slate)]">
            {formatLongDate(item.pubDate)}
          </span>
        </div>
        <h3 className="mt-4 font-display text-[20px] font-extrabold leading-[1.25] tracking-[-0.015em] text-[var(--color-ink)] group-hover:text-[var(--color-blue)]">
          {item.title}
        </h3>
        {item.excerpt && (
          <p className="mt-3 flex-1 text-[14px] leading-relaxed text-[var(--color-slate)]">
            {item.excerpt}
          </p>
        )}
        <div className="mt-5 flex items-center justify-between text-[13px]">
          {item.author ? (
            <span className="truncate text-[var(--color-slate)]">
              {item.author}
            </span>
          ) : (
            <span />
          )}
          <span className="whitespace-nowrap font-semibold text-[var(--color-blue)] group-hover:text-[var(--color-blue-deep)]">
            Read at source →
          </span>
        </div>
      </div>
    </motion.a>
  );
}
