"use client";

import React, { useEffect, useState } from "react";
import { usePathname } from "next/navigation";
import {
  ActionButton,
  ActionButtonWithTooltip,
} from "@/components/ui/action-button";
import ActionConfirmingDialog from "@/components/ui/action-confirming-dialog";
import { toast } from "@/components/ui/sonner";
import useBulkActionsStore from "@/lib/bulkActions";
import { useTranslation } from "@/lib/i18n/client";
import {
  CheckCheck,
  FileDown,
  Hash,
  Link,
  List,
  ListMinus,
  Pencil,
  RotateCw,
  Trash2,
  X,
} from "lucide-react";

import {
  useDeleteBookmark,
  useRecrawlBookmark,
  useUpdateBookmark,
} from "@karakeep/shared-react/hooks/bookmarks";
import { useRemoveBookmarkFromList } from "@karakeep/shared-react/hooks/lists";
import { limitConcurrency } from "@karakeep/shared/concurrency";
import { BookmarkTypes } from "@karakeep/shared/types/bookmarks";

import BulkManageListsModal from "./bookmarks/BulkManageListsModal";
import BulkTagModal from "./bookmarks/BulkTagModal";
import { ArchivedActionIcon, FavouritedActionIcon } from "./bookmarks/icons";

const MAX_CONCURRENT_BULK_ACTIONS = 50;

export default function BulkBookmarksAction() {
  const { t } = useTranslation();
  const {
    selectedBookmarks,
    isBulkEditEnabled,
    listContext: withinListContext,
  } = useBulkActionsStore();
  const setIsBulkEditEnabled = useBulkActionsStore(
    (state) => state.setIsBulkEditEnabled,
  );
  const selectAllBookmarks = useBulkActionsStore((state) => state.selectAll);
  const unSelectAllBookmarks = useBulkActionsStore(
    (state) => state.unSelectAll,
  );
  const isEverythingSelected = useBulkActionsStore(
    (state) => state.isEverythingSelected,
  );
  const [isDeleteDialogOpen, setIsDeleteDialogOpen] = useState(false);
  const [isRemoveFromListDialogOpen, setIsRemoveFromListDialogOpen] =
    useState(false);
  const [manageListsModal, setManageListsModalOpen] = useState(false);
  const [bulkTagModal, setBulkTagModalOpen] = useState(false);
  const pathname = usePathname();
  const [currentPathname, setCurrentPathname] = useState("");

  // Reset bulk edit state when the route changes
  useEffect(() => {
    if (pathname !== currentPathname) {
      setCurrentPathname(pathname);
      setIsBulkEditEnabled(false);
    }
  }, [pathname, currentPathname]);

  const onError = () => {
    toast({
      variant: "destructive",
      title: "Something went wrong",
      description: "There was a problem with your request.",
    });
  };

  const deleteBookmarkMutator = useDeleteBookmark({
    onSuccess: () => {
      setIsBulkEditEnabled(false);
    },
    onError,
  });

  const updateBookmarkMutator = useUpdateBookmark({
    onSuccess: () => {
      setIsBulkEditEnabled(false);
    },
    onError,
  });

  const recrawlBookmarkMutator = useRecrawlBookmark({
    onSuccess: () => {
      setIsBulkEditEnabled(false);
    },
    onError,
  });

  const removeBookmarkFromListMutator = useRemoveBookmarkFromList({
    onSuccess: () => {
      setIsBulkEditEnabled(false);
    },
    onError,
  });

  interface UpdateBookmarkProps {
    favourited?: boolean;
    archived?: boolean;
  }

  const recrawlBookmarks = async (archiveFullPage: boolean) => {
    const links = selectedBookmarks.filter(
      (item) => item.content.type === BookmarkTypes.LINK,
    );
    await Promise.all(
      limitConcurrency(
        links.map(
          (item) => () =>
            recrawlBookmarkMutator.mutateAsync({
              bookmarkId: item.id,
              archiveFullPage,
            }),
        ),
        MAX_CONCURRENT_BULK_ACTIONS,
      ),
    );
    toast({
      description: `${links.length} bookmarks will be ${archiveFullPage ? "re-crawled and archived!" : "refreshed!"}`,
    });
  };

  function isClipboardAvailable() {
    if (typeof window === "undefined") {
      return false;
    }
    return window && window.navigator && window.navigator.clipboard;
  }

  const copyLinks = async () => {
    if (!isClipboardAvailable()) {
      toast({
        description: `Copying is only available over https`,
      });
      return;
    }
    const copyString = selectedBookmarks
      .map((item) => {
        return item.content.type === BookmarkTypes.LINK && item.content.url;
      })
      .filter(Boolean)
      .join("\n");

    await navigator.clipboard.writeText(copyString);

    toast({
      description: `Added ${selectedBookmarks.length} bookmark links into the clipboard!`,
    });
  };

  const updateBookmarks = async ({
    favourited,
    archived,
  }: UpdateBookmarkProps) => {
    await Promise.all(
      limitConcurrency(
        selectedBookmarks.map(
          (item) => () =>
            updateBookmarkMutator.mutateAsync({
              bookmarkId: item.id,
              favourited,
              archived,
            }),
        ),
        MAX_CONCURRENT_BULK_ACTIONS,
      ),
    );
    toast({
      description: `${selectedBookmarks.length} bookmarks have been updated!`,
    });
  };

  const deleteBookmarks = async () => {
    await Promise.all(
      limitConcurrency(
        selectedBookmarks.map(
          (item) => () =>
            deleteBookmarkMutator.mutateAsync({ bookmarkId: item.id }),
        ),
        MAX_CONCURRENT_BULK_ACTIONS,
      ),
    );
    toast({
      description: `${selectedBookmarks.length} bookmarks have been deleted!`,
    });
    setIsDeleteDialogOpen(false);
  };

  const removeBookmarksFromList = async () => {
    if (!withinListContext) return;

    const results = await Promise.allSettled(
      limitConcurrency(
        selectedBookmarks.map(
          (item) => () =>
            removeBookmarkFromListMutator.mutateAsync({
              bookmarkId: item.id,
              listId: withinListContext.id,
            }),
        ),
        MAX_CONCURRENT_BULK_ACTIONS,
      ),
    );

    const successes = results.filter((r) => r.status === "fulfilled").length;
    if (successes > 0) {
      toast({
        description: `${successes} bookmarks have been removed from the list!`,
      });
    }
    setIsRemoveFromListDialogOpen(false);
  };

  const alreadyFavourited =
    selectedBookmarks.length &&
    selectedBookmarks.every((item) => item.favourited === true);

  const alreadyArchived =
    selectedBookmarks.length &&
    selectedBookmarks.every((item) => item.archived === true);

  const actionList = [
    {
      name: isClipboardAvailable()
        ? t("actions.copy_link")
        : "Copying is only available over https",
      icon: <Link size={18} />,
      action: () => copyLinks(),
      isPending: false,
      hidden: !isBulkEditEnabled,
    },
    {
      name: t("actions.remove_from_list"),
      icon: <ListMinus size={18} />,
      action: () => setIsRemoveFromListDialogOpen(true),
      isPending: removeBookmarkFromListMutator.isPending,
      hidden:
        !isBulkEditEnabled ||
        !withinListContext ||
        withinListContext.type !== "manual" ||
        (withinListContext.userRole !== "editor" &&
          withinListContext.userRole !== "owner"),
    },
    {
      name: t("actions.add_to_list"),
      icon: <List size={18} />,
      action: () => setManageListsModalOpen(true),
      isPending: false,
      hidden: !isBulkEditEnabled,
    },
    {
      name: t("actions.edit_tags"),
      icon: <Hash size={18} />,
      action: () => setBulkTagModalOpen(true),
      isPending: false,
      hidden: !isBulkEditEnabled,
    },
    {
      name: alreadyFavourited ? t("actions.unfavorite") : t("actions.favorite"),
      icon: <FavouritedActionIcon favourited={!!alreadyFavourited} size={18} />,
      action: () => updateBookmarks({ favourited: !alreadyFavourited }),
      isPending: updateBookmarkMutator.isPending,
      hidden: !isBulkEditEnabled,
    },
    {
      name: alreadyArchived ? t("actions.unarchive") : t("actions.archive"),
      icon: <ArchivedActionIcon size={18} archived={!!alreadyArchived} />,
      action: () => updateBookmarks({ archived: !alreadyArchived }),
      isPending: updateBookmarkMutator.isPending,
      hidden: !isBulkEditEnabled,
    },
    {
      name: t("actions.download_full_page_archive"),
      icon: <FileDown size={18} />,
      action: () => recrawlBookmarks(true),
      isPending: recrawlBookmarkMutator.isPending,
      hidden: !isBulkEditEnabled,
    },
    {
      name: t("actions.refresh"),
      icon: <RotateCw size={18} />,
      action: () => recrawlBookmarks(false),
      isPending: recrawlBookmarkMutator.isPending,
      hidden: !isBulkEditEnabled,
    },
    {
      name: t("actions.delete"),
      icon: <Trash2 size={18} color="red" />,
      action: () => setIsDeleteDialogOpen(true),
      hidden: !isBulkEditEnabled,
    },
    {
      name: isEverythingSelected()
        ? t("actions.unselect_all")
        : t("actions.select_all"),
      icon: (
        <p className="flex items-center gap-2">
          ( <CheckCheck size={18} /> {selectedBookmarks.length} )
        </p>
      ),
      action: () =>
        isEverythingSelected() ? unSelectAllBookmarks() : selectAllBookmarks(),
      alwaysEnable: true,
      hidden: !isBulkEditEnabled,
    },
    {
      name: t("actions.close_bulk_edit"),
      icon: <X size={18} />,
      action: () => setIsBulkEditEnabled(false),
      alwaysEnable: true,
      hidden: !isBulkEditEnabled,
    },
    {
      name: t("actions.bulk_edit"),
      icon: <Pencil size={18} />,
      action: () => setIsBulkEditEnabled(true),
      alwaysEnable: true,
      hidden: isBulkEditEnabled,
    },
  ];

  return (
    <div>
      <ActionConfirmingDialog
        open={isDeleteDialogOpen}
        setOpen={setIsDeleteDialogOpen}
        title={"Delete Bookmarks"}
        description={<p>Are you sure you want to delete these bookmarks?</p>}
        actionButton={() => (
          <ActionButton
            type="button"
            variant="destructive"
            loading={deleteBookmarkMutator.isPending}
            onClick={() => deleteBookmarks()}
          >
            {t("actions.delete")}
          </ActionButton>
        )}
      />
      <ActionConfirmingDialog
        open={isRemoveFromListDialogOpen}
        setOpen={setIsRemoveFromListDialogOpen}
        title={"Remove Bookmarks from List"}
        description={
          <p>
            Are you sure you want to remove {selectedBookmarks.length} bookmarks
            from this list?
          </p>
        }
        actionButton={() => (
          <ActionButton
            type="button"
            variant="destructive"
            loading={removeBookmarkFromListMutator.isPending}
            onClick={() => removeBookmarksFromList()}
          >
            {t("actions.remove")}
          </ActionButton>
        )}
      />
      <BulkManageListsModal
        bookmarkIds={selectedBookmarks.map((b) => b.id)}
        open={manageListsModal}
        setOpen={setManageListsModalOpen}
      />
      <BulkTagModal
        bookmarkIds={selectedBookmarks.map((b) => b.id)}
        open={bulkTagModal}
        setOpen={setBulkTagModalOpen}
      />
      <div className="flex items-center">
        {actionList.map(
          ({ name, icon: Icon, action, isPending, hidden, alwaysEnable }) => (
            <ActionButtonWithTooltip
              className={hidden ? "hidden" : "block"}
              tooltip={name}
              disabled={!selectedBookmarks.length && !alwaysEnable}
              delayDuration={100}
              loading={!!isPending}
              variant="ghost"
              key={name}
              onClick={action}
            >
              {Icon}
            </ActionButtonWithTooltip>
          ),
        )}
      </div>
    </div>
  );
}
