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

import type { Dispatch, SetStateAction } from "react";
import { useEffect, useMemo, useRef } from "react";
import { observer } from "mobx-react";
import type { EditorRefApi } from "@plane/editor";
import { ISSUE_PRIORITIES } from "@plane/constants";
import { useTranslation } from "@plane/i18n";
import { LabelPropertyIcon, PriorityIcon, PriorityPropertyIcon } from "@plane/propel/icons";
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
import type { TExternalContourRequest, TIssue, TNameDescriptionLoader } from "@plane/types";
import { EFileAssetType } from "@plane/types";
import { getTextContent } from "@plane/utils";
import { DescriptionVersionsRoot } from "@/components/core/description-versions";
import { DescriptionInput } from "@/components/editor/rich-text/description-input";
import { DescriptionInputLoader } from "@/components/editor/rich-text/description-input/loader";
import { IssueAttachmentRoot } from "@/components/issues/attachment";
import type { TIssueOperations } from "@/components/issues/issue-detail";
import { IssueActivity } from "@/components/issues/issue-detail/issue-activity";
import { IssueReaction } from "@/components/issues/issue-detail/reactions";
import { IssueTitleInput } from "@/components/issues/title-input";
import { useProjectExternalContours } from "@/hooks/store/use-project-external-contours";
import { useUser } from "@/hooks/store/user";
import useReloadConfirmations from "@/hooks/use-reload-confirmation";
import { DeDupeIssuePopoverRoot } from "@/plane-web/components/de-dupe/duplicate-popover";
import { useDebouncedDuplicateIssues } from "@/plane-web/hooks/use-debounced-duplicate-issues";
import { IssueService } from "@/services/issue/issue.service";
import { WorkItemVersionService } from "@/services/issue/work_item_version.service";
import { ExternalContoursMirroredActivity } from "./mirrored-activity";
import { ExternalContoursMirroredAttachments } from "./mirrored-attachments";
import { ExternalContoursMirroredComments } from "./mirrored-comments";
import { ExternalContoursIssueContentProperties } from "./issue-properties";
import { ExternalContoursRequestTraceability } from "./request-traceability";
import { ExternalContoursSourceReplyBox } from "./source-reply-box";

const workItemVersionService = new WorkItemVersionService();
const issueService = new IssueService();

type Props = {
  workspaceSlug: string;
  sourceProjectId: string;
  contourRequest: TExternalContourRequest;
  hasDirectTargetAccess: boolean;
  isEditable: boolean;
  isSourceEditable: boolean;
  isSubmitting: TNameDescriptionLoader;
  setIsSubmitting: Dispatch<SetStateAction<TNameDescriptionLoader>>;
};

export const ExternalContoursIssueMainContent = observer(function ExternalContoursIssueMainContent(props: Props) {
  const {
    workspaceSlug,
    sourceProjectId,
    contourRequest,
    hasDirectTargetAccess,
    isEditable,
    isSourceEditable,
    isSubmitting,
    setIsSubmitting,
  } = props;
  const { t } = useTranslation();
  const editorRef = useRef<EditorRefApi>(null);
  const { data: currentUser } = useUser();
  const { loader, updateRequest, updateRequestIssue } = useProjectExternalContours();
  const { setShowAlert } = useReloadConfirmations(isSubmitting === "submitting");

  useEffect(() => {
    if (isSubmitting === "submitted") {
      setShowAlert(false);
      setTimeout(async () => setIsSubmitting("saved"), 3000);
    } else if (isSubmitting === "submitting") {
      setShowAlert(true);
    }
  }, [isSubmitting, setIsSubmitting, setShowAlert]);

  const issue = contourRequest.issue;
  const mirroredActivity = contourRequest.mirrored_activity ?? [];
  const mirroredAttachments = contourRequest.mirrored_attachments ?? [];
  const mirroredComments = contourRequest.mirrored_comments ?? [];
  const targetProjectId = issue.project_id || sourceProjectId;
  const priorityDetails = ISSUE_PRIORITIES.find((priority) => priority.key === issue.priority);

  const { duplicateIssues } = useDebouncedDuplicateIssues(
    workspaceSlug,
    targetProjectId,
    targetProjectId,
    {
      name: issue?.name,
      description_html: getTextContent(issue?.description_html),
      issueId: issue?.id,
    }
  );

  const issueOperations: TIssueOperations = useMemo(
    () => ({
      fetch: async () => undefined,
      remove: async (_workspaceSlug: string, _projectId: string, issueId: string) => {
        try {
          await issueService.deleteIssue(workspaceSlug, targetProjectId, issueId);
          setToast({ title: t("success"), type: TOAST_TYPE.SUCCESS, message: t("inbox_issue.modals.delete.success") });
        } catch {
          setToast({ title: t("error"), type: TOAST_TYPE.ERROR, message: t("something_went_wrong_please_try_again") });
        }
      },
      update: async (_workspaceSlug: string, _projectId: string, issueId: string, data: Partial<TIssue>) => {
        try {
          const updatedIssue = await issueService.patchIssue(workspaceSlug, targetProjectId, issueId, data);
          updateRequestIssue(contourRequest.id, { ...data, ...updatedIssue });
        } catch {
          setToast({ title: t("error"), type: TOAST_TYPE.ERROR, message: t("issue_could_not_be_updated") });
        }
      },
      archive: async () => undefined,
    }),
    [contourRequest.id, targetProjectId, t, updateRequestIssue, workspaceSlug]
  );

  const sourceIssueOperations: TIssueOperations = useMemo(
    () => ({
      fetch: async () => undefined,
      remove: async () => undefined,
      update: async (_workspaceSlug: string, _projectId: string, requestId: string, data: Partial<TIssue>) => {
        try {
          await updateRequest(workspaceSlug, sourceProjectId, requestId, {
            name: data.name,
            description_html: data.description_html,
          });
        } catch {
          setToast({ title: t("error"), type: TOAST_TYPE.ERROR, message: t("issue_could_not_be_updated") });
        }
      },
    }),
    [sourceProjectId, t, updateRequest, workspaceSlug]
  );

  if (!issue || !issue.project_id || !issue.id) return <></>;

  if (!hasDirectTargetAccess) {
    return (
      <div className="space-y-4">
        <div className="nodedc-external-content-shell space-y-4 p-5">
          {isSourceEditable ? (
            <>
              <IssueTitleInput
                workspaceSlug={workspaceSlug}
                projectId={sourceProjectId}
                issueId={contourRequest.id}
                isSubmitting={isSubmitting}
                setIsSubmitting={(value) => setIsSubmitting(value)}
                issueOperations={sourceIssueOperations}
                disabled={false}
                value={issue.name}
                containerClassName="-ml-3"
              />

              {loader === "issue-loading" || issue.description_html === undefined ? (
                <DescriptionInputLoader />
              ) : (
                <DescriptionInput
                  issueSequenceId={issue.sequence_id}
                  containerClassName="-ml-3 border-none"
                  disabled={false}
                  disabledExtensions={["image"]}
                  editorRef={editorRef}
                  entityId={issue.id}
                  fileAssetType={EFileAssetType.ISSUE_DESCRIPTION}
                  initialValue={!issue.description_html || issue.description_html === "" ? "<p></p>" : issue.description_html}
                  key={`${issue.id}-source`}
                  onSubmit={async (value) => {
                    await sourceIssueOperations.update(workspaceSlug, sourceProjectId, contourRequest.id, {
                      description_html: value.description_html,
                    });
                  }}
                  projectId={sourceProjectId}
                  setIsSubmitting={(value) => setIsSubmitting(value)}
                  workspaceSlug={workspaceSlug}
                />
              )}
            </>
          ) : (
            <>
              <h1 className="text-xl font-semibold text-primary">{issue.name}</h1>
              <div
                className="prose prose-invert max-w-none text-sm text-secondary [&_p]:mb-3"
                dangerouslySetInnerHTML={{ __html: issue.description_html || "<p></p>" }}
              />
            </>
          )}
        </div>

        <ExternalContoursRequestTraceability contourRequest={contourRequest} />

        <div className="nodedc-external-section flex flex-col gap-3 px-4 py-4">
          <div className="text-body-sm-medium">{t("external_contours_page.properties.section_title")}</div>
          <div className="flex flex-col gap-3 text-13 text-secondary">
            <div className="nodedc-external-property-row">
              <div className="nodedc-external-property-label">
                <PriorityPropertyIcon className="h-4 w-4 flex-shrink-0" />
                <span>{t("priority")}</span>
              </div>
              <div className="nodedc-external-property-value flex-1 text-[13px] font-medium">
                <PriorityIcon priority={issue.priority ?? "none"} className="h-3.5 w-3.5 flex-shrink-0 text-tertiary" />
                <span className="text-12 font-medium text-primary">
                  {issue.priority && issue.priority !== "none"
                    ? priorityDetails?.title ?? t(issue.priority)
                    : t("external_contours_page.form.priority")}
                </span>
              </div>
            </div>

            <div className="nodedc-external-property-row">
              <div className="nodedc-external-property-label">
                <LabelPropertyIcon className="h-4 w-4 flex-shrink-0" />
                <span>{t("labels")}</span>
              </div>
              {issue.label_details?.length ? (
                <div className="nodedc-external-property-value flex-1 flex-wrap text-[13px] font-medium">
                  <LabelPropertyIcon className="h-3.5 w-3.5 flex-shrink-0 text-tertiary" />
                  <span className="text-12 font-medium text-primary">
                    {issue.label_details.map((label) => label.name).join(", ")}
                  </span>
                </div>
              ) : (
                <div className="nodedc-external-property-value flex-1 text-[13px] font-medium">
                  <LabelPropertyIcon className="h-3.5 w-3.5 flex-shrink-0 text-tertiary" />
                  <span className="text-12 font-medium text-tertiary">{t("labels")}</span>
                </div>
              )}
            </div>
          </div>
        </div>

        <ExternalContoursMirroredAttachments attachments={mirroredAttachments} />

        <ExternalContoursSourceReplyBox
          workspaceSlug={workspaceSlug}
          sourceProjectId={sourceProjectId}
          requestId={contourRequest.id}
        />

        <ExternalContoursMirroredComments comments={mirroredComments} />

        <ExternalContoursMirroredActivity activity={mirroredActivity} />

        {!isSourceEditable && (
          <div className="nodedc-external-empty px-4 py-4 text-13 text-secondary">
            {t("external_contours_page.readonly_source_view")}
          </div>
        )}
      </div>
    );
  }

  return (
    <div className="space-y-4">
      <div className="nodedc-external-content-shell space-y-4 p-5">
        {duplicateIssues.length > 0 && (
          <DeDupeIssuePopoverRoot
            workspaceSlug={workspaceSlug}
            projectId={targetProjectId}
            rootIssueId={issue.id}
            issues={duplicateIssues}
            issueOperations={issueOperations}
          />
        )}
        <IssueTitleInput
          workspaceSlug={workspaceSlug}
          projectId={targetProjectId}
          issueId={issue.id}
          isSubmitting={isSubmitting}
          setIsSubmitting={(value) => setIsSubmitting(value)}
          issueOperations={issueOperations}
          disabled={!isEditable}
          value={issue.name}
          containerClassName="-ml-3"
        />

        {loader === "issue-loading" || issue.description_html === undefined ? (
          <DescriptionInputLoader />
        ) : (
          <DescriptionInput
            issueSequenceId={issue.sequence_id}
            containerClassName="-ml-3 border-none"
            disabled={!isEditable}
            editorRef={editorRef}
            entityId={issue.id}
            fileAssetType={EFileAssetType.ISSUE_DESCRIPTION}
            initialValue={!issue.description_html || issue.description_html === "" ? "<p></p>" : issue.description_html}
            key={issue.id}
            onSubmit={async (value, isMigrationUpdate) => {
              await issueOperations.update(workspaceSlug, targetProjectId, issue.id, {
                description_html: value.description_html,
                ...(isMigrationUpdate ? { skip_activity: "true" } : {}),
              });
            }}
            projectId={targetProjectId}
            setIsSubmitting={(value) => setIsSubmitting(value)}
            workspaceSlug={workspaceSlug}
          />
        )}

        <div className="flex items-center justify-between gap-2">
          {currentUser && (
            <IssueReaction workspaceSlug={workspaceSlug} projectId={targetProjectId} issueId={issue.id} currentUser={currentUser} />
          )}
          {isEditable && (
            <DescriptionVersionsRoot
              className="flex-shrink-0"
              entityInformation={{
                createdAt: issue.created_at ? new Date(issue.created_at) : new Date(),
                createdByDisplayName: issue.created_by_detail?.display_name ?? "",
                id: issue.id,
                isRestoreDisabled: !isEditable,
              }}
              fetchHandlers={{
                listDescriptionVersions: (issueId) =>
                  workItemVersionService.listDescriptionVersions(workspaceSlug, targetProjectId, issueId),
                retrieveDescriptionVersion: (issueId, versionId) =>
                  workItemVersionService.retrieveDescriptionVersion(workspaceSlug, targetProjectId, issueId, versionId),
              }}
              handleRestore={(descriptionHTML) => editorRef.current?.setEditorValue(descriptionHTML, true)}
              projectId={targetProjectId}
              workspaceSlug={workspaceSlug}
            />
          )}
        </div>
      </div>

      <ExternalContoursRequestTraceability contourRequest={contourRequest} />

      <div className="nodedc-external-section overflow-visible px-4 py-4">
        <IssueAttachmentRoot workspaceSlug={workspaceSlug} projectId={targetProjectId} issueId={issue.id} disabled={!isEditable} />
      </div>

      <div className="nodedc-external-section overflow-visible px-4 py-4">
        <ExternalContoursIssueContentProperties
          workspaceSlug={workspaceSlug}
          targetProjectId={targetProjectId}
          issue={issue}
          issueOperations={issueOperations}
          isEditable={isEditable}
        />
      </div>

      <div className="nodedc-external-section overflow-visible px-4 py-4">
        <IssueActivity workspaceSlug={workspaceSlug} projectId={targetProjectId} issueId={issue.id} />
      </div>
    </div>
  );
});
