"use client";

import * as React from "react";
import type { LucideIcon } from "lucide-react";
import {
  FileText,
  Globe,
  Code2,
  Newspaper,
  Database,
  File,
  ExternalLink,
} from "lucide-react";
import { cn, Popover, PopoverContent, PopoverTrigger } from "./_adapter";

import { openSafeNavigationHref, sanitizeHref } from "../shared/media";
import type {
  SerializableCitation,
  CitationType,
  CitationVariant,
} from "./schema";

const FALLBACK_LOCALE = "en-US";

const TYPE_ICONS: Record<CitationType, LucideIcon> = {
  webpage: Globe,
  document: FileText,
  article: Newspaper,
  api: Database,
  code: Code2,
  other: File,
};

function extractDomain(url: string): string | undefined {
  try {
    const urlObj = new URL(url);
    return urlObj.hostname.replace(/^www\./, "");
  } catch {
    return undefined;
  }
}

function formatDate(isoString: string, locale: string): string {
  try {
    const date = new Date(isoString);
    return date.toLocaleDateString(locale, {
      year: "numeric",
      month: "short",
    });
  } catch {
    return isoString;
  }
}

function useHoverPopover(delay = 100) {
  const [open, setOpen] = React.useState(false);
  const timeoutRef = React.useRef<ReturnType<typeof setTimeout> | null>(null);

  const handleMouseEnter = React.useCallback(() => {
    if (timeoutRef.current) clearTimeout(timeoutRef.current);
    timeoutRef.current = setTimeout(() => setOpen(true), delay);
  }, [delay]);

  const handleMouseLeave = React.useCallback(() => {
    if (timeoutRef.current) clearTimeout(timeoutRef.current);
    timeoutRef.current = setTimeout(() => setOpen(false), delay);
  }, [delay]);

  React.useEffect(() => {
    return () => {
      if (timeoutRef.current) clearTimeout(timeoutRef.current);
    };
  }, []);

  return { open, setOpen, handleMouseEnter, handleMouseLeave };
}

export interface CitationProps extends SerializableCitation {
  variant?: CitationVariant;
  className?: string;
  onNavigate?: (href: string, citation: SerializableCitation) => void;
}

export function Citation(props: CitationProps) {
  const { variant = "default", className, onNavigate, ...serializable } = props;

  const {
    id,
    href: rawHref,
    title,
    snippet,
    domain: providedDomain,
    favicon,
    author,
    publishedAt,
    type = "webpage",
    locale: providedLocale,
  } = serializable;

  const locale = providedLocale ?? FALLBACK_LOCALE;
  const sanitizedHref = sanitizeHref(rawHref);
  const domain = providedDomain ?? extractDomain(rawHref);

  const citationData: SerializableCitation = {
    ...serializable,
    href: sanitizedHref ?? rawHref,
    domain,
    locale,
  };

  const TypeIcon = TYPE_ICONS[type] ?? Globe;

  const handleClick = () => {
    if (!sanitizedHref) return;
    if (onNavigate) {
      onNavigate(sanitizedHref, citationData);
    } else {
      openSafeNavigationHref(sanitizedHref);
    }
  };

  const handleKeyDown = (e: React.KeyboardEvent) => {
    if (sanitizedHref && (e.key === "Enter" || e.key === " ")) {
      e.preventDefault();
      handleClick();
    }
  };

  const iconElement = favicon ? (
    <img
      src={favicon}
      alt=""
      aria-hidden="true"
      width={14}
      height={14}
      className="bg-muted size-3.5 shrink-0 rounded object-cover"
    />
  ) : (
    <TypeIcon className="size-3.5 shrink-0 opacity-60" aria-hidden="true" />
  );

  // 站内引用往往没有 domain/author/date，拼不出内容时整行不渲染，避免留空行
  const metaParts: React.ReactNode[] = [];
  if (domain) metaParts.push(<span key="domain">{domain}</span>);
  if (author) metaParts.push(<span key="author">{author}</span>);
  if (publishedAt) {
    metaParts.push(
      <time key="date" dateTime={publishedAt} className="tabular-nums">
        {formatDate(publishedAt, locale)}
      </time>,
    );
  }

  const { open, handleMouseEnter, handleMouseLeave } = useHoverPopover();

  // Inline variant: compact chip with hover popover
  if (variant === "inline") {
    return (
      <Popover open={open}>
        <PopoverTrigger asChild>
          <button
            type="button"
            aria-label={title}
            data-tool-ui-id={id}
            data-slot="citation"
            onClick={handleClick}
            onMouseEnter={handleMouseEnter}
            onMouseLeave={handleMouseLeave}
            className={cn(
              "inline-flex cursor-pointer items-center gap-1.5 rounded-md px-2 py-1",
              "bg-muted/60 text-sm outline-none",
              "transition-colors duration-150",
              "hover:bg-muted",
              "focus-visible:ring-ring focus-visible:ring-2",
              className,
            )}
          >
            {iconElement}
            <span className="text-muted-foreground">{domain}</span>
          </button>
        </PopoverTrigger>
        <PopoverContent
          side="top"
          align="start"
          className="w-72 cursor-pointer p-0"
          onMouseEnter={handleMouseEnter}
          onMouseLeave={handleMouseLeave}
          onOpenAutoFocus={(e) => e.preventDefault()}
          onCloseAutoFocus={(e) => e.preventDefault()}
          onClick={handleClick}
        >
          <div className="hover:bg-muted/50 flex flex-col gap-2 p-3 transition-colors">
            <div className="flex items-start gap-2">
              {iconElement}
              <span className="text-muted-foreground text-xs">{domain}</span>
            </div>
            <p className="text-sm leading-snug font-medium">{title}</p>
            {snippet && (
              <p className="text-muted-foreground line-clamp-2 text-xs leading-relaxed">
                {snippet}
              </p>
            )}
          </div>
        </PopoverContent>
      </Popover>
    );
  }

  // Default variant: full card
  return (
    <article
      className={cn("relative w-full max-w-md min-w-72", className)}
      lang={locale}
      data-tool-ui-id={id}
      data-slot="citation"
    >
      <div
        className={cn(
          "group @container relative isolate flex w-full min-w-0 flex-col overflow-hidden rounded-xl",
          "border-border bg-card border text-sm shadow-xs",
          "transition-colors duration-150",
          sanitizedHref && [
            "cursor-pointer",
            "hover:border-foreground/25",
            "focus-visible:ring-ring focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none",
          ],
        )}
        onClick={sanitizedHref ? handleClick : undefined}
        role={sanitizedHref ? "link" : undefined}
        tabIndex={sanitizedHref ? 0 : undefined}
        onKeyDown={handleKeyDown}
      >
        <div className="flex items-start gap-2.5 px-3 py-2.5">
          <span className="mt-0.5 flex">{iconElement}</span>

          <div className="flex min-w-0 flex-1 flex-col gap-0.5">
            <div className="flex min-w-0 items-start gap-1.5">
              <h3 className="text-foreground min-w-0 flex-1 text-[13.5px] leading-snug font-medium text-pretty">
                <span className="group-hover:decoration-foreground/30 line-clamp-2 group-hover:underline group-hover:underline-offset-2">
                  {title}
                </span>
              </h3>
              {sanitizedHref && (
                <ExternalLink className="text-muted-foreground mt-0.5 size-3 shrink-0 opacity-0 transition-opacity group-hover:opacity-100" />
              )}
            </div>

            {snippet && (
              <p className="text-muted-foreground line-clamp-2 text-[12.5px] leading-[1.5] text-pretty">
                {snippet}
              </p>
            )}

            {metaParts.length > 0 && (
              <p className="text-muted-foreground/70 truncate text-[11px]">
                {metaParts.map((part, index) => (
                  <React.Fragment key={index}>
                    {index > 0 && <span className="opacity-60"> · </span>}
                    {part}
                  </React.Fragment>
                ))}
              </p>
            )}
          </div>
        </div>
      </div>
    </article>
  );
}
