import { useQueryClient } from "@tanstack/react-query";
import copy from "copy-to-clipboard";
import { useCallback } from "react";
import toast from "react-hot-toast";
import { useLocation } from "react-router-dom";
import { useInstance } from "@/contexts/InstanceContext";
import { memoKeys, useDeleteMemo, useUpdateMemo } from "@/hooks/useMemoQueries";
import useNavigateTo from "@/hooks/useNavigateTo";
import { userKeys } from "@/hooks/useUserQueries";
import { handleError } from "@/lib/error";
import { State } from "@/types/proto/api/v1/common_pb";
import type { Memo } from "@/types/proto/api/v1/memo_service_pb";
import { useTranslate } from "@/utils/i18n";
import { removeCompletedTasks } from "@/utils/markdown-manipulation";

interface UseMemoActionHandlersOptions {
  memo: Memo;
  onEdit?: () => void;
  setDeleteDialogOpen: (open: boolean) => void;
  setRemoveTasksDialogOpen: (open: boolean) => void;
}

export const useMemoActionHandlers = ({ memo, onEdit, setDeleteDialogOpen, setRemoveTasksDialogOpen }: UseMemoActionHandlersOptions) => {
  const t = useTranslate();
  const location = useLocation();
  const navigateTo = useNavigateTo();
  const queryClient = useQueryClient();
  const { profile } = useInstance();
  const { mutateAsync: updateMemo } = useUpdateMemo();
  const { mutateAsync: deleteMemo } = useDeleteMemo();
  const isInMemoDetailPage = location.pathname.startsWith(`/${memo.name}`);

  const memoUpdatedCallback = useCallback(() => {
    // Invalidate user stats to trigger refetch
    queryClient.invalidateQueries({ queryKey: userKeys.stats() });
  }, [queryClient]);

  const handleTogglePinMemoBtnClick = useCallback(async () => {
    try {
      await updateMemo({
        update: {
          name: memo.name,
          pinned: !memo.pinned,
        },
        updateMask: ["pinned"],
      });
    } catch {
      // do nothing
    }
  }, [memo.name, memo.pinned, updateMemo]);

  const handleEditMemoClick = useCallback(() => {
    onEdit?.();
  }, [onEdit]);

  const handleToggleMemoStatusClick = useCallback(async () => {
    const isArchiving = memo.state !== State.ARCHIVED;
    const newState = isArchiving ? State.ARCHIVED : State.NORMAL;
    const message = isArchiving ? t("message.archived-successfully") : t("message.restored-successfully");

    // Optimistic: remove memo from current list cache immediately
    const listQueries = queryClient.getQueriesData<{ pages?: Array<{ memos: Memo[] }>; memos?: Memo[] }>({ queryKey: memoKeys.lists() });
    const snapshots: Array<{ queryKey: readonly unknown[]; data: unknown }> = [];
    for (const [queryKey, data] of listQueries) {
      snapshots.push({ queryKey, data });
      if (data && "pages" in data && data.pages) {
        // Infinite query format
        queryClient.setQueryData(queryKey, {
          ...data,
          pages: data.pages.map((page) => ({
            ...page,
            memos: page.memos.filter((m) => m.name !== memo.name),
          })),
        });
      }
    }

    // Show success toast immediately
    toast.success(message);

    // Navigate if on detail page
    if (isInMemoDetailPage) {
      navigateTo(isArchiving ? "/" : "/archived");
    }

    // Fire API call in the background
    try {
      await updateMemo({
        update: {
          name: memo.name,
          state: newState,
        },
        updateMask: ["state"],
      });
    } catch (error: unknown) {
      // Rollback: restore previous cache
      for (const { queryKey, data } of snapshots) {
        queryClient.setQueryData(queryKey, data);
      }
      toast.error(`Failed to ${isArchiving ? "archive" : "restore"} memo`);
      handleError(error, () => { }, {
        context: `${isArchiving ? "Archive" : "Restore"} memo`,
        fallbackMessage: "An error occurred",
      });
      return;
    }

    memoUpdatedCallback();
  }, [memo.name, memo.state, t, isInMemoDetailPage, navigateTo, memoUpdatedCallback, updateMemo, queryClient]);

  const handleCopyLink = useCallback(() => {
    // Always use frontend URL (window.location.origin) instead of backend URL
    // This ensures the link points to the frontend (port 3001) not backend (port 5000)
    // memo.name format: "memos/{uid}" or "memos/{id}"
    // URL should be: /memos/{uid} (direct path, no /app prefix for sharing)
    const host = window.location.origin;
    const memoPath = memo.name.startsWith("memos/") ? memo.name : `memos/${memo.name}`;
    copy(`${host}/${memoPath}`);
    toast.success(t("message.succeed-copy-link"));
  }, [memo.name, t]);

  const handleCopyContent = useCallback(() => {
    copy(memo.content);
    toast.success(t("message.succeed-copy-content"));
  }, [memo.content, t]);

  const handleDeleteMemoClick = useCallback(() => {
    setDeleteDialogOpen(true);
  }, [setDeleteDialogOpen]);

  const confirmDeleteMemo = useCallback(async () => {
    await deleteMemo(memo.name);
    toast.success(t("message.deleted-successfully"));
    if (isInMemoDetailPage) {
      navigateTo("/");
    }
    memoUpdatedCallback();
  }, [memo.name, t, isInMemoDetailPage, navigateTo, memoUpdatedCallback, deleteMemo]);

  const handleRemoveCompletedTaskListItemsClick = useCallback(() => {
    setRemoveTasksDialogOpen(true);
  }, [setRemoveTasksDialogOpen]);

  const confirmRemoveCompletedTaskListItems = useCallback(async () => {
    const newContent = removeCompletedTasks(memo.content);
    await updateMemo({
      update: {
        name: memo.name,
        content: newContent,
      },
      updateMask: ["content"],
    });
    toast.success(t("message.remove-completed-task-list-items-successfully"));
    memoUpdatedCallback();
  }, [memo.name, memo.content, t, memoUpdatedCallback, updateMemo]);

  return {
    handleTogglePinMemoBtnClick,
    handleEditMemoClick,
    handleToggleMemoStatusClick,
    handleCopyLink,
    handleCopyContent,
    handleDeleteMemoClick,
    confirmDeleteMemo,
    handleRemoveCompletedTaskListItemsClick,
    confirmRemoveCompletedTaskListItems,
  };
};
