import { Heart, Search, SlidersHorizontal, X } from "lucide-react";
import { useEffect, useMemo, useState } from "react";
import { Link } from "react-router-dom";
import {
  assetUrl,
  getJSON,
  itemsOrEmpty,
  readJSONCache,
  type Category,
  type Resource,
} from "../../api";
import { FavoriteButton } from "../../favorites/FavoriteButton";
import { listFavorites, type FavoriteSort } from "../../favorites/api";
import { useFavorites } from "../../favorites/FavoritesProvider";
import { langQuery, useI18n, type Lang } from "../../i18n";
import { homePathForLang } from "../../languageRoutes";
import { Reveal } from "../../motion";
import { useSetPageTitle } from "../../components/PageTitleContext";
import { Skeleton } from "../../components/Skeleton";
import { useWallet } from "../../wallet/WalletProvider";
import { useLocalizedPath } from "../../useLocalizedPath";
import { cleanCategoryDisplayName } from "../../utils/categoryDisplay";
import { formatDateYmd } from "../../utils/format";

const pageSize = 24;

function useCategories(lang: Lang) {
  const [categories, setCategories] = useState<Category[]>([]);

  useEffect(() => {
    const url = `/api/categories?lang=${encodeURIComponent(langQuery(lang))}`;
    const cached = readJSONCache<Category[]>(url);
    if (cached) setCategories(itemsOrEmpty(cached));
    let cancelled = false;
    getJSON<Category[]>(url)
      .then((items) => {
        if (!cancelled) setCategories(itemsOrEmpty(items));
      })
      .catch(() => {
        if (!cancelled && !cached) setCategories([]);
      });
    return () => {
      cancelled = true;
    };
  }, [lang]);

  return categories;
}

function FavoriteResourceCard({ resource }: { resource: Resource }) {
  const { t } = useI18n();
  const lp = useLocalizedPath();
  const unavailable = resource.availability === "unavailable";
  const cover = resource.coverImage || resource.previewUrl;
  return (
    <article
      className={`group relative flex min-h-[132px] gap-4 rounded-2xl border bg-[#272632] p-3 transition md:p-4 ${
        unavailable
          ? "border-yellow-500/25 opacity-80"
          : "border-[#27292E] hover:border-ark-gold/50"
      }`}
    >
      {!unavailable ? (
        <Link
          to={lp(`/resource/${resource.id}`)}
          aria-label={resource.title}
          className="absolute inset-0 z-0 rounded-2xl outline-none focus-visible:ring-2 focus-visible:ring-ark-gold/80"
        />
      ) : null}
      <div className="relative z-10 h-[96px] w-[112px] shrink-0 overflow-hidden rounded-xl bg-[#111116] md:h-[116px] md:w-[150px]">
        {cover && !unavailable ? (
          <img
            src={assetUrl(cover)}
            alt=""
            className="h-full w-full object-cover transition group-hover:scale-[1.02]"
            loading="lazy"
            decoding="async"
          />
        ) : (
          <div className="flex h-full w-full items-center justify-center bg-gradient-to-br from-neutral-900 to-neutral-950">
            <Heart className="h-8 w-8 text-ark-gold/50" strokeWidth={1.6} />
          </div>
        )}
        {unavailable ? (
          <span className="absolute left-2 top-2 rounded-full bg-yellow-500 px-2 py-0.5 text-[11px] font-bold text-black">
            {t("favoritesUnavailable")}
          </span>
        ) : null}
      </div>

      <div className="pointer-events-none relative z-10 flex min-w-0 flex-1 flex-col gap-2 pr-11">
        <h2 className="line-clamp-2 text-base font-bold leading-snug text-white md:text-lg">
          {resource.title}
        </h2>
        {resource.description ? (
          <p className="line-clamp-2 text-sm leading-6 text-neutral-400">
            {resource.description}
          </p>
        ) : null}
        <div className="mt-auto flex flex-wrap items-center gap-2 text-xs text-neutral-400">
          <span className="rounded-full bg-[#1f2028] px-2.5 py-1 text-neutral-200">
            {cleanCategoryDisplayName(resource.categoryName)}
          </span>
          <span>{resource.type}</span>
          <span>·</span>
          <time dateTime={resource.updatedAt}>
            {formatDateYmd(resource.updatedAt)}
          </time>
          {typeof resource.favoriteCount === "number" ? (
            <span>· ♥ {resource.favoriteCount}</span>
          ) : null}
        </div>
      </div>

      <FavoriteButton
        resourceId={resource.id}
        className="absolute right-3 top-3 z-20"
      />
    </article>
  );
}

export default function Favorites() {
  const { lang, t } = useI18n();
  const wallet = useWallet();
  const { markFavorite } = useFavorites();
  const categories = useCategories(lang);
  const [sort, setSort] = useState<FavoriteSort>("favorited_at");
  const [category, setCategory] = useState("");
  const [queryInput, setQueryInput] = useState("");
  const [query, setQuery] = useState("");
  const [page, setPage] = useState(1);
  const [items, setItems] = useState<Resource[]>([]);
  const [total, setTotal] = useState(0);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState("");

  useSetPageTitle(t("favorites"));

  useEffect(() => {
    setPage(1);
  }, [sort, category, query]);

  useEffect(() => {
    if (!wallet.token || wallet.status !== "loggedIn") {
      setItems([]);
      setTotal(0);
      return;
    }
    let cancelled = false;
    setLoading(true);
    setError("");
    listFavorites(wallet.token, {
      sort,
      category,
      q: query,
      page,
      limit: pageSize,
      includeUnavailable: true,
      lang: langQuery(lang),
    })
      .then((data) => {
        if (cancelled) return;
        const resources = itemsOrEmpty(data.items).map((item) => item.resource);
        setItems(resources);
        setTotal(data.total);
        resources.forEach((resource) => markFavorite(resource.id, true));
      })
      .catch((err) => {
        if (!cancelled)
          setError(err instanceof Error ? err.message : t("loadFailed"));
      })
      .finally(() => {
        if (!cancelled) setLoading(false);
      });
    return () => {
      cancelled = true;
    };
  }, [
    category,
    lang,
    markFavorite,
    page,
    query,
    sort,
    t,
    wallet.status,
    wallet.token,
  ]);

  const totalPages = Math.max(1, Math.ceil(total / pageSize));
  const hasFilters = Boolean(category || query || sort !== "favorited_at");

  const sortOptions = useMemo(
    () => [
      { value: "favorited_at" as const, label: t("favoritesSortFavoritedAt") },
      { value: "published_at" as const, label: t("favoritesSortPublishedAt") },
      { value: "hot" as const, label: t("favoritesSortHot") },
    ],
    [t],
  );

  if (wallet.status !== "loggedIn") {
    return (
      <Reveal className="flex min-h-[60vh] flex-col items-center justify-center gap-5 px-4 py-12 text-center">
        <div className="flex h-20 w-20 items-center justify-center rounded-full border border-ark-gold/30 bg-ark-gold/5">
          <Heart className="h-10 w-10 text-ark-gold/70" strokeWidth={1.8} />
        </div>
        <h1 className="text-2xl font-semibold text-neutral-100 md:text-3xl">
          {t("favorites")}
        </h1>
        <p className="max-w-md text-sm leading-relaxed text-neutral-400 md:text-base">
          {t("favoritesLoginDesc")}
        </p>
        <button
          type="button"
          onClick={wallet.openLoginModal}
          className="mt-2 inline-flex h-11 items-center justify-center rounded-full bg-ark-gold px-6 text-sm font-bold text-black transition hover:bg-ark-gold2 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ark-gold/80 focus-visible:ring-offset-2 focus-visible:ring-offset-ark-bg"
        >
          {t("walletConnect")}
        </button>
      </Reveal>
    );
  }

  return (
    <Reveal className="mx-auto grid max-w-[980px] gap-5 px-0 py-2 md:py-4">
      <div className="rounded-3xl border border-white/10 bg-[#17171d] p-4 shadow-xl shadow-black/20 md:p-5">
        <div className="flex flex-col gap-4 md:flex-row md:items-end md:justify-between">
          <div>
            <p className="text-sm font-semibold text-ark-gold2">
              {t("favorites")}
            </p>
            <h1 className="mt-1 text-2xl font-bold text-white md:text-3xl">
              {t("favoritesLibraryTitle")}
            </h1>
          </div>
          <Link
            to={homePathForLang(lang)}
            className="inline-flex h-10 items-center justify-center rounded-full border border-ark-gold/50 px-4 text-sm font-semibold text-ark-gold transition hover:bg-ark-gold/10"
          >
            {t("backToHome")}
          </Link>
        </div>

        <form
          className="mt-5 grid gap-3 md:grid-cols-[1fr_180px_180px_auto]"
          onSubmit={(event) => {
            event.preventDefault();
            setQuery(queryInput.trim());
          }}
        >
          <label className="relative block">
            <Search className="absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-neutral-500" />
            <input
              value={queryInput}
              onChange={(event) => setQueryInput(event.target.value)}
              placeholder={t("favoritesSearchPlaceholder")}
              className="h-11 w-full rounded-full border border-white/10 bg-[#101016] pl-10 pr-4 text-sm text-white outline-none transition placeholder:text-neutral-500 focus:border-ark-gold/60"
            />
          </label>

          <label className="relative block">
            <SlidersHorizontal className="absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-neutral-500" />
            <select
              value={sort}
              onChange={(event) => setSort(event.target.value as FavoriteSort)}
              className="h-11 w-full appearance-none rounded-full border border-white/10 bg-[#101016] pl-10 pr-4 text-sm text-white outline-none focus:border-ark-gold/60"
            >
              {sortOptions.map((option) => (
                <option key={option.value} value={option.value}>
                  {option.label}
                </option>
              ))}
            </select>
          </label>

          <select
            value={category}
            onChange={(event) => setCategory(event.target.value)}
            className="h-11 w-full rounded-full border border-white/10 bg-[#101016] px-4 text-sm text-white outline-none focus:border-ark-gold/60"
          >
            <option value="">{t("favoritesFilterAllCategories")}</option>
            {categories.map((cat) => (
              <option key={cat.slug} value={cat.slug}>
                {cleanCategoryDisplayName(cat.name)}
              </option>
            ))}
          </select>

          <button
            type="submit"
            className="inline-flex h-11 items-center justify-center rounded-full bg-ark-gold px-5 text-sm font-bold text-black transition hover:bg-ark-gold2"
          >
            {t("search")}
          </button>
        </form>

        {hasFilters ? (
          <button
            type="button"
            onClick={() => {
              setSort("favorited_at");
              setCategory("");
              setQuery("");
              setQueryInput("");
            }}
            className="mt-3 inline-flex items-center gap-1 rounded-full border border-white/10 px-3 py-1.5 text-xs font-medium text-neutral-300 transition hover:border-ark-gold/40 hover:text-ark-gold"
          >
            <X className="h-3.5 w-3.5" />
            {t("favoritesClearFilters")}
          </button>
        ) : null}
      </div>

      {loading ? (
        <div className="grid gap-3">
          {Array.from({ length: 4 }).map((_, index) => (
            <Skeleton key={index} className="h-[132px] rounded-2xl" />
          ))}
        </div>
      ) : error ? (
        <div className="rounded-2xl border border-red-500/30 bg-red-500/10 p-4 text-sm text-red-200">
          {error}
        </div>
      ) : items.length === 0 ? (
        <div className="flex min-h-[280px] flex-col items-center justify-center gap-4 rounded-3xl border border-white/10 bg-[#17171d] p-8 text-center">
          <Heart className="h-10 w-10 text-ark-gold/60" strokeWidth={1.8} />
          <h2 className="text-xl font-semibold text-white">
            {hasFilters
              ? t("favoritesNoFilteredTitle")
              : t("favoritesEmptyTitle")}
          </h2>
          <p className="max-w-md text-sm leading-6 text-neutral-400">
            {hasFilters
              ? t("favoritesNoFilteredDesc")
              : t("favoritesEmptyDesc")}
          </p>
        </div>
      ) : (
        <div className="grid gap-3">
          {items.map((resource) => (
            <FavoriteResourceCard key={resource.id} resource={resource} />
          ))}
        </div>
      )}

      {totalPages > 1 ? (
        <div className="flex items-center justify-center gap-3">
          <button
            type="button"
            disabled={page <= 1}
            onClick={() => setPage((value) => Math.max(1, value - 1))}
            className="rounded-full border border-white/10 px-4 py-2 text-sm text-neutral-200 transition hover:border-ark-gold/50 disabled:cursor-not-allowed disabled:opacity-40"
          >
            {t("paginationPrev")}
          </button>
          <span className="text-sm text-neutral-400">
            {t("pageIndicator")
              .replace("{{c}}", String(page))
              .replace("{{p}}", String(totalPages))}
          </span>
          <button
            type="button"
            disabled={page >= totalPages}
            onClick={() => setPage((value) => Math.min(totalPages, value + 1))}
            className="rounded-full border border-white/10 px-4 py-2 text-sm text-neutral-200 transition hover:border-ark-gold/50 disabled:cursor-not-allowed disabled:opacity-40"
          >
            {t("paginationNext")}
          </button>
        </div>
      ) : null}
    </Reveal>
  );
}
