/**
 * Copyright (c) 2023-present Plane Software, Inc. and contributors
 * SPDX-License-Identifier: AGPL-3.0-only
 * See the LICENSE file for details.
 */

import { useEffect, useState } from "react";
import { observer } from "mobx-react";
import { Bell, BellOff } from "lucide-react";
import { useTranslation } from "@plane/i18n";
import { Button } from "@plane/propel/button";
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
import { Loader } from "@plane/ui";
import { cn } from "@plane/utils";
import { IssueService } from "@/services/issue/issue.service";

const issueService = new IssueService();

type TSubscriptionIdentity = {
  workspaceSlug: string;
  projectId: string;
  issueId: string;
};

type Props = TSubscriptionIdentity & {
  buttonClassName?: string;
};

export const useExternalContourSubscription = ({ workspaceSlug, projectId, issueId }: TSubscriptionIdentity) => {
  const [isSubscribed, setIsSubscribed] = useState<boolean | undefined>(undefined);
  const [loading, setLoading] = useState(false);

  useEffect(() => {
    let isMounted = true;

    const fetchSubscription = async () => {
      try {
        const response = await issueService.getIssueNotificationSubscriptionStatus(workspaceSlug, projectId, issueId);
        if (isMounted) setIsSubscribed(response?.subscribed ?? false);
      } catch {
        if (isMounted) setIsSubscribed(false);
      }
    };

    if (workspaceSlug && projectId && issueId) {
      void fetchSubscription();
    }

    return () => {
      isMounted = false;
    };
  }, [workspaceSlug, projectId, issueId]);

  const toggleSubscription = async () => {
    if (!workspaceSlug || !projectId || !issueId) return;

    const nextValue = !isSubscribed;
    setLoading(true);
    setIsSubscribed(nextValue);

    try {
      if (nextValue) {
        await issueService.subscribeToIssueNotifications(workspaceSlug, projectId, issueId);
      } else {
        await issueService.unsubscribeFromIssueNotifications(workspaceSlug, projectId, issueId);
      }
    } catch {
      setIsSubscribed(!nextValue);
      throw new Error("subscription-toggle-failed");
    } finally {
      setLoading(false);
    }
  };

  return {
    isSubscribed,
    loading,
    toggleSubscription,
  };
};

type TExternalContourSubscriptionButtonProps = {
  isSubscribed: boolean | undefined;
  loading: boolean;
  onToggle: () => Promise<void>;
  buttonClassName?: string;
  iconOnly?: boolean;
};

export const ExternalContourSubscriptionButton = observer(function ExternalContourSubscriptionButton(
  props: TExternalContourSubscriptionButtonProps
) {
  const { isSubscribed, loading, onToggle, buttonClassName, iconOnly = false } = props;
  const { t } = useTranslation();

  if (isSubscribed === undefined) {
    return (
      <Loader>
        <Loader.Item width={iconOnly ? "40px" : "106px"} height="40px" />
      </Loader>
    );
  }

  return (
    <Button
      prependIcon={isSubscribed ? <BellOff /> : <Bell className="h-3 w-3" />}
      variant="secondary"
      className={cn("hover:!bg-accent-primary/20", buttonClassName)}
      onClick={() => void onToggle()}
      disabled={loading}
      size="lg"
    >
      {!iconOnly &&
        (loading ? (
          <span className="hidden sm:block">{t("common.loading")}</span>
        ) : isSubscribed ? (
          <span className="hidden sm:block">{t("common.actions.unsubscribe")}</span>
        ) : (
          <span className="hidden sm:block">{t("common.actions.subscribe")}</span>
        ))}
    </Button>
  );
});

export const ExternalContourSubscription = observer(function ExternalContourSubscription(props: Props) {
  const { workspaceSlug, projectId, issueId, buttonClassName } = props;
  const { t } = useTranslation();
  const { isSubscribed, loading, toggleSubscription } = useExternalContourSubscription({
    workspaceSlug,
    projectId,
    issueId,
  });

  const handleToggle = async () => {
    try {
      const nextValue = !isSubscribed;
      await toggleSubscription();
      setToast({
        type: TOAST_TYPE.SUCCESS,
        title: t("toast.success"),
        message: nextValue ? t("issue.subscription.actions.subscribed") : t("issue.subscription.actions.unsubscribed"),
      });
    } catch {
      setToast({
        type: TOAST_TYPE.ERROR,
        title: t("toast.error"),
        message: t("common.error.message"),
      });
    }
  };

  return (
    <ExternalContourSubscriptionButton
      isSubscribed={isSubscribed}
      loading={loading}
      onToggle={handleToggle}
      buttonClassName={buttonClassName}
    />
  );
});
