import React, { useCallback, useState } from "react";
import { useRouter } from "next/router";
import { observer } from "mobx-react-lite";
import { mutate } from "swr";
import { Controller, UseFormWatch } from "react-hook-form";
// mobx store
import { useMobxStore } from "lib/mobx/store-provider";
// hooks
import useToast from "hooks/use-toast";
import useUserIssueNotificationSubscription from "hooks/use-issue-notification-subscription";
import useEstimateOption from "hooks/use-estimate-option";
// services
import { IssueService } from "services/issue";
import { ModuleService } from "services/module.service";
// components
import { LinkModal, LinksList } from "components/core";
import {
  DeleteIssueModal,
  SidebarAssigneeSelect,
  SidebarBlockedSelect,
  SidebarBlockerSelect,
  SidebarCycleSelect,
  SidebarModuleSelect,
  SidebarParentSelect,
  SidebarPrioritySelect,
  SidebarStateSelect,
  SidebarEstimateSelect,
  SidebarLabelSelect,
  SidebarDuplicateSelect,
  SidebarRelatesSelect,
} from "components/issues";
// ui
import { CustomDatePicker } from "components/ui";
// icons
import { Bell, CalendarDays, LinkIcon, Plus, Signal, Tag, Trash2, Triangle, LayoutPanelTop } from "lucide-react";
import { Button, ContrastIcon, DiceIcon, DoubleCircleIcon, StateGroupIcon, UserGroupIcon } from "@plane/ui";
// helpers
import { copyTextToClipboard } from "helpers/string.helper";
// types
import type { IIssue, IIssueLink, ILinkDetails } from "types";
// fetch-keys
import { ISSUE_DETAILS, PROJECT_ISSUES_ACTIVITY } from "constants/fetch-keys";
import { EUserWorkspaceRoles } from "constants/workspace";

type Props = {
  control: any;
  submitChanges: (formData: any) => void;
  issueDetail: IIssue | undefined;
  watch: UseFormWatch<IIssue>;
  fieldsToShow?: (
    | "state"
    | "assignee"
    | "priority"
    | "estimate"
    | "parent"
    | "blocker"
    | "blocked"
    | "startDate"
    | "dueDate"
    | "cycle"
    | "module"
    | "label"
    | "link"
    | "delete"
    | "all"
    | "subscribe"
    | "duplicate"
    | "relates_to"
  )[];
  uneditable?: boolean;
};

const issueService = new IssueService();
const moduleService = new ModuleService();

export const IssueDetailsSidebar: React.FC<Props> = observer((props) => {
  const { control, submitChanges, issueDetail, watch: watchIssue, fieldsToShow = ["all"], uneditable = false } = props;

  const [deleteIssueModal, setDeleteIssueModal] = useState(false);
  const [linkModal, setLinkModal] = useState(false);
  const [selectedLinkToUpdate, setSelectedLinkToUpdate] = useState<ILinkDetails | null>(null);

  const {
    user: { currentUser, currentProjectRole },
    projectState: { states },
    projectIssues: { removeIssue },
    issueDetail: { createIssueLink, updateIssueLink, deleteIssueLink },
  } = useMobxStore();

  const router = useRouter();
  const { workspaceSlug, projectId, issueId, inboxIssueId } = router.query;

  const { isEstimateActive } = useEstimateOption();

  const { loading, handleSubscribe, handleUnsubscribe, subscribed } = useUserIssueNotificationSubscription(
    workspaceSlug,
    projectId,
    issueId
  );

  const { setToastAlert } = useToast();

  const handleCycleChange = useCallback(
    (cycleId: string) => {
      if (!workspaceSlug || !projectId || !issueDetail || !currentUser) return;

      issueService
        .addIssueToCycle(workspaceSlug as string, projectId as string, cycleId, {
          issues: [issueDetail.id],
        })
        .then(() => {
          mutate(ISSUE_DETAILS(issueId as string));
        });
    },
    [workspaceSlug, projectId, issueId, issueDetail, currentUser]
  );

  const handleModuleChange = useCallback(
    (moduleId: string) => {
      if (!workspaceSlug || !projectId || !issueDetail || !currentUser) return;

      moduleService
        .addIssuesToModule(workspaceSlug as string, projectId as string, moduleId, {
          issues: [issueDetail.id],
        })
        .then(() => {
          mutate(ISSUE_DETAILS(issueId as string));
        });
    },
    [workspaceSlug, projectId, issueId, issueDetail, currentUser]
  );

  const issueLinkCreate = (formData: IIssueLink) => {
    if (!workspaceSlug || !projectId || !issueId) return;
    createIssueLink(workspaceSlug.toString(), projectId.toString(), issueId.toString(), formData);
  };

  const issueLinkUpdate = (formData: IIssueLink, linkId: string) => {
    if (!workspaceSlug || !projectId || !issueId) return;
    updateIssueLink(workspaceSlug.toString(), projectId.toString(), issueId.toString(), linkId, formData);
  };

  const issueLinkDelete = (linkId: string) => {
    if (!workspaceSlug || !projectId || !issueId) return;
    deleteIssueLink(workspaceSlug.toString(), projectId.toString(), issueId.toString(), linkId);
  };

  const handleCopyText = () => {
    const originURL = typeof window !== "undefined" && window.location.origin ? window.location.origin : "";

    copyTextToClipboard(`${originURL}/${workspaceSlug}/projects/${projectId}/issues/${issueDetail?.id}`).then(() => {
      setToastAlert({
        type: "success",
        title: "Link Copied!",
        message: "Issue link copied to clipboard.",
      });
    });
  };

  const showFirstSection =
    fieldsToShow.includes("all") ||
    fieldsToShow.includes("state") ||
    fieldsToShow.includes("assignee") ||
    fieldsToShow.includes("priority") ||
    fieldsToShow.includes("estimate");

  const showSecondSection =
    fieldsToShow.includes("all") ||
    fieldsToShow.includes("parent") ||
    fieldsToShow.includes("blocker") ||
    fieldsToShow.includes("blocked") ||
    fieldsToShow.includes("dueDate");

  const showThirdSection =
    fieldsToShow.includes("all") || fieldsToShow.includes("cycle") || fieldsToShow.includes("module");

  const startDate = watchIssue("start_date");
  const targetDate = watchIssue("target_date");

  const minDate = startDate ? new Date(startDate) : null;
  minDate?.setDate(minDate.getDate());

  const maxDate = targetDate ? new Date(targetDate) : null;
  maxDate?.setDate(maxDate.getDate());

  const handleEditLink = (link: ILinkDetails) => {
    setSelectedLinkToUpdate(link);
    setLinkModal(true);
  };

  const isAllowed = !!currentProjectRole && currentProjectRole >= EUserWorkspaceRoles.MEMBER;

  const currentIssueState = projectId
    ? states[projectId.toString()]?.find((s) => s.id === issueDetail?.state)
    : undefined;

  return (
    <>
      <LinkModal
        isOpen={linkModal}
        handleClose={() => {
          setLinkModal(false);
          setSelectedLinkToUpdate(null);
        }}
        data={selectedLinkToUpdate}
        status={selectedLinkToUpdate ? true : false}
        createIssueLink={issueLinkCreate}
        updateIssueLink={issueLinkUpdate}
      />
      {workspaceSlug && projectId && issueDetail && (
        <DeleteIssueModal
          handleClose={() => setDeleteIssueModal(false)}
          isOpen={deleteIssueModal}
          data={issueDetail}
          onSubmit={async () => {
            await removeIssue(workspaceSlug.toString(), projectId.toString(), issueDetail.id);
            router.push(`/${workspaceSlug}/projects/${projectId}/issues`);
          }}
        />
      )}
      <div className="flex h-full w-full flex-col divide-y-2 divide-custom-border-200 overflow-hidden">
        <div className="flex items-center justify-between px-5 pb-3">
          <div className="flex items-center gap-x-2">
            {currentIssueState ? (
              <StateGroupIcon
                className="h-4 w-4"
                stateGroup={currentIssueState.group}
                color={currentIssueState.color}
              />
            ) : inboxIssueId ? (
              <StateGroupIcon className="h-4 w-4" stateGroup="backlog" color="#ff7700" />
            ) : null}
            <h4 className="text-lg font-medium text-custom-text-300">
              {issueDetail?.project_detail?.identifier}-{issueDetail?.sequence_id}
            </h4>
          </div>
          <div className="flex flex-wrap items-center gap-2">
            {issueDetail?.created_by !== currentUser?.id &&
              !issueDetail?.assignees.includes(currentUser?.id ?? "") &&
              !router.pathname.includes("[archivedIssueId]") &&
              (fieldsToShow.includes("all") || fieldsToShow.includes("subscribe")) && (
                <Button
                  size="sm"
                  prependIcon={<Bell className="h-3 w-3" />}
                  variant="outline-primary"
                  className="hover:!bg-custom-primary-100/20"
                  onClick={() => {
                    if (subscribed) handleUnsubscribe();
                    else handleSubscribe();
                  }}
                >
                  {loading ? "Loading..." : subscribed ? "Unsubscribe" : "Subscribe"}
                </Button>
              )}
            {(fieldsToShow.includes("all") || fieldsToShow.includes("link")) && (
              <button
                type="button"
                className="rounded-md border border-custom-border-200 p-2 shadow-sm duration-300 hover:bg-custom-background-90 focus:border-custom-primary focus:outline-none focus:ring-1 focus:ring-custom-primary"
                onClick={handleCopyText}
              >
                <LinkIcon className="h-3.5 w-3.5" />
              </button>
            )}
            {isAllowed && (fieldsToShow.includes("all") || fieldsToShow.includes("delete")) && (
              <button
                type="button"
                className="rounded-md border border-red-500 p-2 text-red-500 shadow-sm duration-300 hover:bg-red-500/20 focus:outline-none"
                onClick={() => setDeleteIssueModal(true)}
              >
                <Trash2 className="h-3.5 w-3.5" />
              </button>
            )}
          </div>
        </div>

        <div className="h-full w-full overflow-y-auto px-5">
          <div className={`divide-y-2 divide-custom-border-200 ${uneditable ? "opacity-60" : ""}`}>
            {showFirstSection && (
              <div className="py-1">
                {(fieldsToShow.includes("all") || fieldsToShow.includes("state")) && (
                  <div className="flex flex-wrap items-center py-2">
                    <div className="flex items-center gap-x-2 text-sm text-custom-text-200 sm:basis-1/2">
                      <DoubleCircleIcon className="h-4 w-4 flex-shrink-0" />
                      <p>State</p>
                    </div>
                    <div>
                      <Controller
                        control={control}
                        name="state"
                        render={({ field: { value } }) => (
                          <SidebarStateSelect
                            value={value}
                            projectId={projectId as string}
                            onChange={(val: string) => submitChanges({ state: val })}
                            disabled={!isAllowed || uneditable}
                          />
                        )}
                      />
                    </div>
                  </div>
                )}
                {(fieldsToShow.includes("all") || fieldsToShow.includes("assignee")) && (
                  <div className="flex flex-wrap items-center py-2">
                    <div className="flex items-center gap-x-2 text-sm text-custom-text-200 sm:basis-1/2">
                      <UserGroupIcon className="h-4 w-4 flex-shrink-0" />
                      <p>Assignees</p>
                    </div>
                    <div>
                      <Controller
                        control={control}
                        name="assignees"
                        render={({ field: { value } }) => (
                          <SidebarAssigneeSelect
                            value={value}
                            projectId={projectId as string}
                            onChange={(val: string[]) => submitChanges({ assignees: val })}
                            disabled={!isAllowed || uneditable}
                          />
                        )}
                      />
                    </div>
                  </div>
                )}
                {(fieldsToShow.includes("all") || fieldsToShow.includes("priority")) && (
                  <div className="flex flex-wrap items-center py-2">
                    <div className="flex items-center gap-x-2 text-sm text-custom-text-200 sm:basis-1/2">
                      <Signal className="h-4 w-4 flex-shrink-0" />
                      <p>Priority</p>
                    </div>
                    <div>
                      <Controller
                        control={control}
                        name="priority"
                        render={({ field: { value } }) => (
                          <SidebarPrioritySelect
                            value={value}
                            onChange={(val) => submitChanges({ priority: val })}
                            disabled={!isAllowed || uneditable}
                          />
                        )}
                      />
                    </div>
                  </div>
                )}
                {(fieldsToShow.includes("all") || fieldsToShow.includes("estimate")) && isEstimateActive && (
                  <div className="flex flex-wrap items-center py-2">
                    <div className="flex items-center gap-x-2 text-sm text-custom-text-200 sm:basis-1/2">
                      <Triangle className="h-4 w-4 flex-shrink-0 " />
                      <p>Estimate</p>
                    </div>
                    <div className="sm:basis-1/2">
                      <Controller
                        control={control}
                        name="estimate_point"
                        render={({ field: { value } }) => (
                          <SidebarEstimateSelect
                            value={value}
                            onChange={(val: number | null) => submitChanges({ estimate_point: val })}
                            disabled={!isAllowed || uneditable}
                          />
                        )}
                      />
                    </div>
                  </div>
                )}
              </div>
            )}
            {showSecondSection && (
              <div className="py-1">
                {(fieldsToShow.includes("all") || fieldsToShow.includes("parent")) && (
                  <div className="flex flex-wrap items-center py-2">
                    <div className="flex items-center gap-x-2 text-sm text-custom-text-200 sm:basis-1/2">
                      <LayoutPanelTop className="h-4 w-4 flex-shrink-0" />
                      <p>Parent</p>
                    </div>
                    <div className="sm:basis-1/2">
                      <Controller
                        control={control}
                        name="parent"
                        render={({ field: { onChange } }) => (
                          <SidebarParentSelect
                            onChange={(val: string) => {
                              submitChanges({ parent: val });
                              onChange(val);
                            }}
                            issueDetails={issueDetail}
                            projectId={projectId as string}
                            disabled={!isAllowed || uneditable}
                          />
                        )}
                      />
                    </div>
                  </div>
                )}
                {(fieldsToShow.includes("all") || fieldsToShow.includes("blocker")) && (
                  <SidebarBlockerSelect
                    issueId={issueId as string}
                    submitChanges={(data: any) => {
                      mutate<IIssue>(
                        ISSUE_DETAILS(issueId as string),
                        (prevData) => {
                          if (!prevData) return prevData;
                          return {
                            ...prevData,
                            ...data,
                          };
                        },
                        false
                      );
                      mutate(PROJECT_ISSUES_ACTIVITY(issueId as string));
                    }}
                    watch={watchIssue}
                    disabled={!isAllowed || uneditable}
                  />
                )}
                {(fieldsToShow.includes("all") || fieldsToShow.includes("blocked")) && (
                  <SidebarBlockedSelect
                    issueId={issueId as string}
                    submitChanges={(data: any) => {
                      mutate<IIssue>(
                        ISSUE_DETAILS(issueId as string),
                        (prevData) => {
                          if (!prevData) return prevData;
                          return {
                            ...prevData,
                            ...data,
                          };
                        },
                        false
                      );
                      mutate(PROJECT_ISSUES_ACTIVITY(issueId as string));
                    }}
                    watch={watchIssue}
                    disabled={!isAllowed || uneditable}
                  />
                )}
                {(fieldsToShow.includes("all") || fieldsToShow.includes("duplicate")) && (
                  <SidebarDuplicateSelect
                    issueId={issueId as string}
                    submitChanges={(data: any) => {
                      if (!data) return mutate(ISSUE_DETAILS(issueId as string));
                      mutate<IIssue>(ISSUE_DETAILS(issueId as string), (prevData) => {
                        if (!prevData) return prevData;
                        return {
                          ...prevData,
                          ...data,
                        };
                      });
                      mutate(PROJECT_ISSUES_ACTIVITY(issueId as string));
                    }}
                    watch={watchIssue}
                    disabled={!isAllowed || uneditable}
                  />
                )}
                {(fieldsToShow.includes("all") || fieldsToShow.includes("relates_to")) && (
                  <SidebarRelatesSelect
                    issueId={issueId as string}
                    submitChanges={(data: any) => {
                      if (!data) return mutate(ISSUE_DETAILS(issueId as string));
                      mutate<IIssue>(ISSUE_DETAILS(issueId as string), (prevData) => {
                        if (!prevData) return prevData;
                        return {
                          ...prevData,
                          ...data,
                        };
                      });
                      mutate(PROJECT_ISSUES_ACTIVITY(issueId as string));
                    }}
                    watch={watchIssue}
                    disabled={!isAllowed || uneditable}
                  />
                )}
                {(fieldsToShow.includes("all") || fieldsToShow.includes("startDate")) && (
                  <div className="flex flex-wrap items-center py-2">
                    <div className="flex items-center gap-x-2 text-sm text-custom-text-200 sm:basis-1/2">
                      <CalendarDays className="h-4 w-4 flex-shrink-0" />
                      <p>Start date</p>
                    </div>
                    <div className="sm:basis-1/2">
                      <Controller
                        control={control}
                        name="start_date"
                        render={({ field: { value } }) => (
                          <CustomDatePicker
                            placeholder="Start date"
                            value={value}
                            onChange={(val) =>
                              submitChanges({
                                start_date: val,
                              })
                            }
                            className="border-none bg-custom-background-80"
                            maxDate={maxDate ?? undefined}
                            disabled={!isAllowed || uneditable}
                          />
                        )}
                      />
                    </div>
                  </div>
                )}
                {(fieldsToShow.includes("all") || fieldsToShow.includes("dueDate")) && (
                  <div className="flex flex-wrap items-center py-2">
                    <div className="flex items-center gap-x-2 text-sm text-custom-text-200 sm:basis-1/2">
                      <CalendarDays className="h-4 w-4 flex-shrink-0" />
                      <p>Due date</p>
                    </div>
                    <div className="sm:basis-1/2">
                      <Controller
                        control={control}
                        name="target_date"
                        render={({ field: { value } }) => (
                          <CustomDatePicker
                            placeholder="Due date"
                            value={value}
                            onChange={(val) =>
                              submitChanges({
                                target_date: val,
                              })
                            }
                            className="border-none bg-custom-background-80"
                            minDate={minDate ?? undefined}
                            disabled={!isAllowed || uneditable}
                          />
                        )}
                      />
                    </div>
                  </div>
                )}
              </div>
            )}
            {showThirdSection && (
              <div className="py-1">
                {(fieldsToShow.includes("all") || fieldsToShow.includes("cycle")) && (
                  <div className="flex flex-wrap items-center py-2">
                    <div className="flex items-center gap-x-2 text-sm text-custom-text-200 sm:w-1/2">
                      <ContrastIcon className="h-4 w-4 flex-shrink-0" />
                      <p>Cycle</p>
                    </div>
                    <div className="space-y-1">
                      <SidebarCycleSelect
                        issueDetail={issueDetail}
                        projectId={projectId as string}
                        handleCycleChange={handleCycleChange}
                        disabled={!isAllowed || uneditable}
                      />
                    </div>
                  </div>
                )}
                {(fieldsToShow.includes("all") || fieldsToShow.includes("module")) && (
                  <div className="flex flex-wrap items-center py-2">
                    <div className="flex items-center gap-x-2 text-sm text-custom-text-200 sm:w-1/2">
                      <DiceIcon className="h-4 w-4 flex-shrink-0" />
                      <p>Module</p>
                    </div>
                    <div className="space-y-1">
                      <SidebarModuleSelect
                        issueDetail={issueDetail}
                        projectId={projectId as string}
                        handleModuleChange={handleModuleChange}
                        disabled={!isAllowed || uneditable}
                      />
                    </div>
                  </div>
                )}
              </div>
            )}
          </div>
          {(fieldsToShow.includes("all") || fieldsToShow.includes("label")) && (
            <div className="flex flex-wrap items-start py-2">
              <div className="flex items-center gap-x-2 text-sm text-custom-text-200 sm:w-1/2">
                <Tag className="h-4 w-4 flex-shrink-0" />
                <p>Label</p>
              </div>
              <div className="space-y-1 sm:w-1/2">
                <SidebarLabelSelect
                  issueDetails={issueDetail}
                  projectId={projectId as string}
                  labelList={issueDetail?.labels ?? []}
                  submitChanges={submitChanges}
                  isNotAllowed={!isAllowed}
                  uneditable={uneditable || !isAllowed}
                />
              </div>
            </div>
          )}
          {(fieldsToShow.includes("all") || fieldsToShow.includes("link")) && (
            <div className={`py-1 text-xs ${uneditable ? "opacity-60" : ""}`}>
              <div className="flex items-center justify-between gap-2">
                <h4>Links</h4>
                {isAllowed && (
                  <button
                    type="button"
                    className={`grid h-7 w-7 place-items-center rounded p-1 outline-none duration-300 hover:bg-custom-background-90 ${
                      uneditable ? "cursor-not-allowed" : "cursor-pointer"
                    }`}
                    onClick={() => setLinkModal(true)}
                    disabled={uneditable}
                  >
                    <Plus className="h-4 w-4" />
                  </button>
                )}
              </div>
              {issueDetail?.issue_link && issueDetail.issue_link.length > 0 && (
                <div className="mt-2 space-y-2">
                  {
                    <LinksList
                      links={issueDetail.issue_link}
                      handleDeleteLink={issueLinkDelete}
                      handleEditLink={handleEditLink}
                      userAuth={{
                        isGuest: currentProjectRole === 5,
                        isViewer: currentProjectRole === 10,
                        isMember: currentProjectRole === 15,
                        isOwner: currentProjectRole === 20,
                      }}
                    />
                  }
                </div>
              )}
            </div>
          )}
        </div>
      </div>
    </>
  );
});
