"use client";

import { useEffect, useMemo, useRef, useState } from "react";
import { useSearchParams } from "next/navigation";
import { BlurFade } from "@/components/magicui/blur-fade";
import { HomeDock } from "./home-dock";
import {
  Dialog,
  DialogContent,
  DialogHeader,
  DialogTitle,
} from "@/components/ui/dialog";
import { LoginForm } from "./login/login-form";
import { Card, CardContent } from "@/components/ui/card";
import { Input } from "@/components/ui/input";
import {
  Globe,
  ExternalLink,
  Link2,
  Search,
  X,
} from "lucide-react";
import Link from "next/link";
import { hostnameOf, faviconFallback } from "@/lib/bookmarks";

interface Bookmark {
  id: number;
  title: string;
  url: string;
  description: string;
  icon: string;
  category: string;
}

const DEFAULT_CATEGORY = "默认";
const MAX_DELAY = 0.6;

function clampDelay(value: number) {
  return Math.min(value, MAX_DELAY);
}

export function HomePageClient({
  isAuthenticated,
  isAdmin,
  hasKeycloak,
  bookmarks,
}: {
  isAuthenticated: boolean;
  isAdmin: boolean;
  hasKeycloak: boolean;
  bookmarks: Bookmark[];
}) {
  const searchParams = useSearchParams();
  const [loginOpen, setLoginOpen] = useState(false);
  const [search, setSearch] = useState("");
  const [activeCategory, setActiveCategory] = useState<string | null>(null);
  const searchInputRef = useRef<HTMLInputElement>(null);

  const wantLogin = searchParams.get("login") === "1" && !isAuthenticated;
  const [prevWantLogin, setPrevWantLogin] = useState(false);
  if (wantLogin !== prevWantLogin) {
    setPrevWantLogin(wantLogin);
    if (wantLogin) setLoginOpen(true);
  }

  useEffect(() => {
    function onKey(e: KeyboardEvent) {
      if (e.key !== "/" || e.metaKey || e.ctrlKey || e.altKey) return;
      const target = e.target as HTMLElement | null;
      if (
        target &&
        (target.tagName === "INPUT" ||
          target.tagName === "TEXTAREA" ||
          target.isContentEditable)
      ) {
        return;
      }
      e.preventDefault();
      searchInputRef.current?.focus();
    }
    window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
  }, []);

  const categories = useMemo(() => {
    const set = new Set<string>();
    for (const b of bookmarks) set.add(b.category || DEFAULT_CATEGORY);
    return Array.from(set).sort((a, b) => a.localeCompare(b, "zh"));
  }, [bookmarks]);

  const counts = useMemo(() => {
    const m = new Map<string, number>();
    for (const b of bookmarks) {
      const cat = b.category || DEFAULT_CATEGORY;
      m.set(cat, (m.get(cat) || 0) + 1);
    }
    return m;
  }, [bookmarks]);

  const filtered = useMemo(() => {
    const q = search.trim().toLowerCase();
    return bookmarks.filter((b) => {
      if (
        activeCategory &&
        (b.category || DEFAULT_CATEGORY) !== activeCategory
      ) {
        return false;
      }
      if (!q) return true;
      return (
        b.title.toLowerCase().includes(q) ||
        b.url.toLowerCase().includes(q) ||
        (b.description || "").toLowerCase().includes(q) ||
        hostnameOf(b.url).toLowerCase().includes(q)
      );
    });
  }, [bookmarks, search, activeCategory]);

  const grouped = useMemo(() => {
    const map = new Map<string, Bookmark[]>();
    for (const b of filtered) {
      const cat = b.category || DEFAULT_CATEGORY;
      if (!map.has(cat)) map.set(cat, []);
      map.get(cat)!.push(b);
    }
    return Array.from(map.entries()).sort(([a], [b]) =>
      a.localeCompare(b, "zh"),
    );
  }, [filtered]);

  return (
    <div className="relative flex min-h-screen flex-col items-center bg-gradient-to-br from-background via-background to-muted/40 px-4 pb-32 pt-4">
      <div className="flex flex-col items-center justify-center pb-8 pt-12">
        <BlurFade inView delay={0.1}>
          <h1 className="mb-3 text-center text-4xl font-extrabold tracking-tight text-foreground">
            EvanPage
          </h1>
        </BlurFade>
      </div>

      {bookmarks.length > 0 && (
        <div className="w-full max-w-5xl space-y-5">
          <BlurFade inView delay={0.3}>
            <div className="flex items-center justify-between gap-2">
              <div className="relative w-full max-w-sm">
                <Search className="pointer-events-none absolute left-3 top-1/2 size-4 -translate-y-1/2 text-muted-foreground" />
                <Input
                  ref={searchInputRef}
                  value={search}
                  onChange={(e) => setSearch(e.target.value)}
                  placeholder="搜索书签…  按 / 聚焦"
                  className="bg-background/70 pl-9 backdrop-blur"
                  aria-label="搜索书签"
                />
                {search && (
                  <button
                    type="button"
                    onClick={() => setSearch("")}
                    aria-label="清空搜索"
                    className="absolute right-2 top-1/2 -translate-y-1/2 rounded-md p-1 text-muted-foreground hover:bg-muted"
                  >
                    <X className="size-3.5" />
                  </button>
                )}
              </div>
              {isAdmin && (
                <Link
                  href="/dashboard/bookmarks"
                  className="text-xs text-muted-foreground transition-colors hover:text-primary hover:underline"
                >
                  管理书签 →
                </Link>
              )}
            </div>
          </BlurFade>

          <BlurFade inView delay={0.35}>
            <div className="flex flex-wrap gap-2">
              <CategoryChip
                label="全部"
                count={bookmarks.length}
                active={activeCategory === null}
                onClick={() => setActiveCategory(null)}
              />
              {categories.map((c) => (
                <CategoryChip
                  key={c}
                  label={c}
                  count={counts.get(c) || 0}
                  active={activeCategory === c}
                  onClick={() => setActiveCategory(c)}
                />
              ))}
            </div>
          </BlurFade>

          {filtered.length === 0 ? (
            <BlurFade inView delay={0.4}>
              <div className="rounded-xl border border-dashed border-border bg-card/50 py-10 text-center text-sm text-muted-foreground backdrop-blur">
                没有匹配「{search || activeCategory}」的书签
              </div>
            </BlurFade>
          ) : (
            grouped.map(([cat, items], catIdx) => (
              <BlurFade key={cat} inView delay={clampDelay(0.4 + catIdx * 0.05)}>
                <div>
                  <h3 className="mb-3 px-1 text-xs font-semibold uppercase tracking-wide text-muted-foreground">
                    {cat}
                    <span className="ml-2 text-muted-foreground/60">
                      {items.length}
                    </span>
                  </h3>
                  <div className="grid gap-3 sm:grid-cols-2 lg:grid-cols-3">
                    {items.map((bm) => (
                      <BookmarkCard key={bm.id} bookmark={bm} />
                    ))}
                  </div>
                </div>
              </BlurFade>
            ))
          )}
        </div>
      )}

      {bookmarks.length === 0 && (
        <BlurFade inView delay={0.4}>
          <div className="w-full max-w-md rounded-2xl border border-dashed border-border bg-card/60 py-10 text-center backdrop-blur">
            <Link2 className="mx-auto mb-3 size-8 text-muted-foreground" />
            <p className="mb-2 text-muted-foreground">还没有书签</p>
            {isAdmin && (
              <Link
                href="/dashboard/bookmarks"
                className="text-sm font-medium text-primary hover:underline"
              >
                添加第一个书签 →
              </Link>
            )}
          </div>
        </BlurFade>
      )}

      <HomeDock
        isAuthenticated={isAuthenticated}
        isAdmin={isAdmin}
        onLoginClick={() => !isAuthenticated && setLoginOpen(true)}
      />

      <Dialog open={loginOpen} onOpenChange={setLoginOpen}>
        <DialogContent className="sm:max-w-md">
          <DialogHeader>
            <DialogTitle className="text-center">登录</DialogTitle>
          </DialogHeader>
          <LoginForm
            hasKeycloak={hasKeycloak}
            onSuccess={() => setLoginOpen(false)}
          />
        </DialogContent>
      </Dialog>
    </div>
  );
}

function CategoryChip({
  label,
  count,
  active,
  onClick,
}: {
  label: string;
  count: number;
  active: boolean;
  onClick: () => void;
}) {
  return (
    <button
      type="button"
      onClick={onClick}
      className={`inline-flex items-center gap-1.5 rounded-full border px-3 py-1 text-xs transition-colors ${
        active
          ? "border-primary bg-primary text-primary-foreground"
          : "border-border bg-card/60 text-foreground/70 hover:bg-muted hover:text-foreground"
      }`}
    >
      <span>{label}</span>
      <span
        className={`rounded-full px-1.5 text-[10px] ${
          active
            ? "bg-primary-foreground/20"
            : "bg-muted text-muted-foreground"
        }`}
      >
        {count}
      </span>
    </button>
  );
}

function BookmarkCard({ bookmark }: { bookmark: Bookmark }) {
  const host = hostnameOf(bookmark.url);
  return (
    <Card className="group transition-all hover:-translate-y-0.5 hover:shadow-md focus-within:ring-2 focus-within:ring-ring/40 active:translate-y-0">
      <CardContent className="p-0">
        <a
          href={bookmark.url}
          target="_blank"
          rel="noopener noreferrer"
          className="flex items-center gap-3 p-3 outline-none"
        >
          <BookmarkIcon icon={bookmark.icon} url={bookmark.url} />
          <div className="min-w-0 flex-1">
            <p className="truncate font-medium text-foreground">
              {bookmark.title}
            </p>
            {host && (
              <p className="truncate text-[11px] text-muted-foreground/70">{host}</p>
            )}
            {bookmark.description && (
              <p className="mt-0.5 line-clamp-1 text-xs text-muted-foreground">
                {bookmark.description}
              </p>
            )}
          </div>
          <ExternalLink className="size-4 shrink-0 text-muted-foreground/50 transition-colors group-hover:text-primary" />
        </a>
      </CardContent>
    </Card>
  );
}

function BookmarkIcon({ icon, url }: { icon: string; url: string }) {
  const initial = icon || faviconFallback(url);
  const [prevInitial, setPrevInitial] = useState(initial);
  const [src, setSrc] = useState(initial);
  const [failed, setFailed] = useState(false);

  if (prevInitial !== initial) {
    setPrevInitial(initial);
    setSrc(initial);
    setFailed(false);
  }

  if (!src || failed) {
    return (
      <div className="flex size-9 shrink-0 items-center justify-center rounded-lg bg-muted">
        <Globe className="size-4 text-muted-foreground" />
      </div>
    );
  }
  return (
    <div className="flex size-9 shrink-0 items-center justify-center overflow-hidden rounded-lg bg-muted">
      <img
        src={src}
        alt=""
        width={20}
        height={20}
        loading="lazy"
        className="size-5 object-contain"
        onError={() => {
          if (icon && src === icon) setSrc(faviconFallback(url));
          else setFailed(true);
        }}
      />
    </div>
  );
}
