"use client";

import { useEffect, useMemo } from "react";
import Link from "next/link";
import BookmarkFormattedCreatedAt from "@/components/dashboard/bookmarks/BookmarkFormattedCreatedAt";
import { BookmarkMarkdownComponent } from "@/components/dashboard/bookmarks/BookmarkMarkdownComponent";
import FooterLinkURL from "@/components/dashboard/bookmarks/FooterLinkURL";
import { ActionButton } from "@/components/ui/action-button";
import { badgeVariants } from "@/components/ui/badge";
import { Card, CardContent } from "@/components/ui/card";
import { Dialog, DialogContent, DialogTrigger } from "@/components/ui/dialog";
import { api } from "@/lib/trpc";
import { cn } from "@/lib/utils";
import tailwindConfig from "@/tailwind.config";
import { Expand, FileIcon, ImageIcon } from "lucide-react";
import { useInView } from "react-intersection-observer";
import Masonry from "react-masonry-css";
import resolveConfig from "tailwindcss/resolveConfig";

import {
  BookmarkTypes,
  ZPublicBookmark,
} from "@karakeep/shared/types/bookmarks";
import { ZCursor } from "@karakeep/shared/types/pagination";

function TagPill({ tag }: { tag: string }) {
  return (
    <div
      className={cn(
        badgeVariants({ variant: "secondary" }),
        "text-nowrap font-light text-gray-700 hover:bg-foreground hover:text-secondary dark:text-gray-400",
      )}
      key={tag}
    >
      {tag}
    </div>
  );
}

function BookmarkCard({ bookmark }: { bookmark: ZPublicBookmark }) {
  const renderContent = () => {
    switch (bookmark.content.type) {
      case BookmarkTypes.LINK:
        return (
          <div className="space-y-2">
            {bookmark.bannerImageUrl && (
              <div className="aspect-video w-full overflow-hidden rounded bg-gray-100">
                <Link href={bookmark.content.url} target="_blank">
                  <img
                    src={bookmark.bannerImageUrl}
                    alt={bookmark.title ?? "Link preview"}
                    className="h-full w-full object-cover"
                  />
                </Link>
              </div>
            )}
            <div className="space-y-2">
              <Link
                href={bookmark.content.url}
                target="_blank"
                className="line-clamp-2 text-ellipsis text-lg font-medium leading-tight"
              >
                {bookmark.title}
              </Link>
            </div>
          </div>
        );

      case BookmarkTypes.TEXT:
        return (
          <div className="space-y-2">
            {bookmark.title && (
              <h3 className="line-clamp-2 text-ellipsis text-lg font-medium leading-tight">
                {bookmark.title}
              </h3>
            )}
            <div className="group relative max-h-64 overflow-hidden">
              <BookmarkMarkdownComponent readOnly={true}>
                {{
                  id: bookmark.id,
                  content: {
                    text: bookmark.content.text,
                  },
                }}
              </BookmarkMarkdownComponent>
              <Dialog>
                <DialogTrigger className="absolute bottom-2 right-2 z-50 h-4 w-4 opacity-0 group-hover:opacity-100">
                  <Expand className="h-4 w-4" />
                </DialogTrigger>
                <DialogContent className="max-h-96 max-w-3xl overflow-auto">
                  <BookmarkMarkdownComponent readOnly={true}>
                    {{
                      id: bookmark.id,
                      content: {
                        text: bookmark.content.text,
                      },
                    }}
                  </BookmarkMarkdownComponent>
                </DialogContent>
              </Dialog>
            </div>
          </div>
        );

      case BookmarkTypes.ASSET:
        return (
          <div className="space-y-2">
            {bookmark.bannerImageUrl ? (
              <div className="aspect-video w-full overflow-hidden rounded bg-gray-100">
                <Link href={bookmark.content.assetUrl} target="_blank">
                  <img
                    src={bookmark.bannerImageUrl}
                    alt={bookmark.title ?? "Asset preview"}
                    className="h-full w-full object-cover"
                  />
                </Link>
              </div>
            ) : (
              <div className="flex aspect-video w-full items-center justify-center overflow-hidden rounded bg-gray-100">
                {bookmark.content.assetType === "image" ? (
                  <ImageIcon className="h-8 w-8 text-gray-400" />
                ) : (
                  <FileIcon className="h-8 w-8 text-gray-400" />
                )}
              </div>
            )}
            <div className="space-y-1">
              <Link
                href={bookmark.content.assetUrl}
                target="_blank"
                className="line-clamp-2 text-ellipsis text-lg font-medium leading-tight"
              >
                {bookmark.title}
              </Link>
            </div>
          </div>
        );
    }
  };

  return (
    <Card className="group mb-3 border-0 shadow-sm transition-all duration-200 hover:shadow-lg">
      <CardContent className="p-3">
        {renderContent()}

        {/* Tags */}
        {bookmark.tags.length > 0 && (
          <div className="mt-2 flex flex-wrap gap-1">
            {bookmark.tags.map((tag, index) => (
              <TagPill key={index} tag={tag} />
            ))}
          </div>
        )}

        {/* Footer */}
        <div className="mt-3 flex items-center justify-between pt-2">
          <div className="flex items-center gap-2 text-xs text-gray-500">
            {bookmark.content.type === BookmarkTypes.LINK && (
              <>
                <FooterLinkURL url={bookmark.content.url} />
                <span>•</span>
              </>
            )}
            <BookmarkFormattedCreatedAt createdAt={bookmark.createdAt} />
          </div>
        </div>
      </CardContent>
    </Card>
  );
}

function getBreakpointConfig() {
  const fullConfig = resolveConfig(tailwindConfig);

  const breakpointColumnsObj: { [key: number]: number; default: number } = {
    default: 3,
  };
  breakpointColumnsObj[parseInt(fullConfig.theme.screens.lg)] = 2;
  breakpointColumnsObj[parseInt(fullConfig.theme.screens.md)] = 1;
  breakpointColumnsObj[parseInt(fullConfig.theme.screens.sm)] = 1;
  return breakpointColumnsObj;
}

export default function PublicBookmarkGrid({
  bookmarks: initialBookmarks,
  nextCursor,
  list,
}: {
  list: {
    id: string;
    name: string;
    description: string | null | undefined;
    icon: string;
    numItems: number;
    ownerName: string;
  };
  bookmarks: ZPublicBookmark[];
  nextCursor: ZCursor | null;
}) {
  const { ref: loadMoreRef, inView: loadMoreButtonInView } = useInView();
  const { data, fetchNextPage, hasNextPage, isFetchingNextPage } =
    api.publicBookmarks.getPublicBookmarksInList.useInfiniteQuery(
      { listId: list.id },
      {
        initialData: () => ({
          pages: [{ bookmarks: initialBookmarks, nextCursor, list }],
          pageParams: [null],
        }),
        initialCursor: null,
        getNextPageParam: (lastPage) => lastPage.nextCursor,
        refetchOnMount: true,
      },
    );

  useEffect(() => {
    if (loadMoreButtonInView && hasNextPage && !isFetchingNextPage) {
      fetchNextPage();
    }
  }, [loadMoreButtonInView]);

  const breakpointConfig = useMemo(() => getBreakpointConfig(), []);

  const bookmarks = useMemo(() => {
    return data.pages.flatMap((b) => b.bookmarks);
  }, [data]);
  return (
    <>
      <Masonry className="flex gap-4" breakpointCols={breakpointConfig}>
        {bookmarks.map((bookmark) => (
          <BookmarkCard key={bookmark.id} bookmark={bookmark} />
        ))}
      </Masonry>
      {hasNextPage && (
        <div className="flex justify-center">
          <ActionButton
            ref={loadMoreRef}
            ignoreDemoMode={true}
            loading={isFetchingNextPage}
            onClick={() => fetchNextPage()}
            variant="ghost"
          >
            Load More
          </ActionButton>
        </div>
      )}
    </>
  );
}
