import React, { useState } from "react";

import Link from "next/link";
import { useRouter } from "next/router";

import useSWR, { mutate } from "swr";

// services
import issuesService from "services/issues.service";
import workspaceService from "services/workspace.service";
import stateService from "services/state.service";
// headless ui
import { Listbox, Transition } from "@headlessui/react";
// ui
import { CustomMenu, CustomSelect, AssigneesList, Avatar, CustomDatePicker } from "components/ui";
// components
import ConfirmIssueDeletion from "components/project/issues/confirm-issue-deletion";
// helpers
import { renderShortNumericDateFormat, findHowManyDaysLeft } from "helpers/date-time.helper";
import { addSpaceIfCamelCase } from "helpers/string.helper";
// types
import {
  CycleIssueResponse,
  IIssue,
  IssueResponse,
  IWorkspaceMember,
  ModuleIssueResponse,
  Properties,
  UserAuth,
} from "types";
// fetch-keys
import {
  CYCLE_ISSUES,
  MODULE_ISSUES,
  PROJECT_ISSUES_LIST,
  STATE_LIST,
  WORKSPACE_MEMBERS,
} from "constants/fetch-keys";
// constants
import { getPriorityIcon } from "constants/global";
import { PRIORITIES } from "constants/";

type Props = {
  type?: string;
  typeId?: string;
  issue: IIssue;
  properties: Properties;
  editIssue: () => void;
  removeIssue?: () => void;
  userAuth: UserAuth;
};

const SingleListIssue: React.FC<Props> = ({
  type,
  typeId,
  issue,
  properties,
  editIssue,
  removeIssue,
  userAuth,
}) => {
  const [deleteIssue, setDeleteIssue] = useState<IIssue | undefined>();

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

  const { data: states } = useSWR(
    workspaceSlug && projectId ? STATE_LIST(projectId as string) : null,
    workspaceSlug && projectId
      ? () => stateService.getStates(workspaceSlug as string, projectId as string)
      : null
  );

  const { data: people } = useSWR<IWorkspaceMember[]>(
    workspaceSlug ? WORKSPACE_MEMBERS : null,
    workspaceSlug ? () => workspaceService.workspaceMembers(workspaceSlug as string) : null
  );

  const partialUpdateIssue = (formData: Partial<IIssue>) => {
    if (!workspaceSlug || !projectId) return;

    if (typeId) {
      mutate<CycleIssueResponse[]>(
        CYCLE_ISSUES(typeId ?? ""),
        (prevData) => {
          const updatedIssues = (prevData ?? []).map((p) => {
            if (p.issue_detail.id === issue.id) {
              return {
                ...p,
                issue_detail: {
                  ...p.issue_detail,
                  ...formData,
                },
              };
            }
            return p;
          });
          return [...updatedIssues];
        },
        false
      );

      mutate<ModuleIssueResponse[]>(
        MODULE_ISSUES(typeId ?? ""),
        (prevData) => {
          const updatedIssues = (prevData ?? []).map((p) => {
            if (p.issue_detail.id === issue.id) {
              return {
                ...p,
                issue_detail: {
                  ...p.issue_detail,
                  ...formData,
                },
              };
            }
            return p;
          });
          return [...updatedIssues];
        },
        false
      );
    }

    mutate<IssueResponse>(
      PROJECT_ISSUES_LIST(workspaceSlug as string, projectId as string),
      (prevData) => ({
        ...(prevData as IssueResponse),
        results: (prevData?.results ?? []).map((p) => {
          if (p.id === issue.id) return { ...p, ...formData };
          return p;
        }),
      }),
      false
    );

    issuesService
      .patchIssue(workspaceSlug as string, projectId as string, issue.id, formData)
      .then((res) => {
        if (typeId) {
          mutate(CYCLE_ISSUES(typeId ?? ""));
          mutate(MODULE_ISSUES(typeId ?? ""));
        }

        mutate(PROJECT_ISSUES_LIST(workspaceSlug as string, projectId as string));
      })
      .catch((error) => {
        console.log(error);
      });
  };

  const isNotAllowed = userAuth.isGuest || userAuth.isViewer;

  return (
    <>
      <ConfirmIssueDeletion
        handleClose={() => setDeleteIssue(undefined)}
        isOpen={!!deleteIssue}
        data={deleteIssue}
      />
      <div className="flex items-center justify-between gap-2 px-4 py-3 text-sm">
        <div className="flex items-center gap-2">
          <span
            className={`block h-1.5 w-1.5 flex-shrink-0 rounded-full`}
            style={{
              backgroundColor: issue.state_detail.color,
            }}
          />
          <Link href={`/${workspaceSlug}/projects/${issue?.project_detail?.id}/issues/${issue.id}`}>
            <a className="group relative flex items-center gap-2">
              {properties.key && (
                <span className="flex-shrink-0 text-xs text-gray-500">
                  {issue.project_detail?.identifier}-{issue.sequence_id}
                </span>
              )}
              <span>{issue.name}</span>
            </a>
          </Link>
        </div>
        <div className="flex flex-shrink-0 flex-wrap items-center gap-x-1 gap-y-2 text-xs">
          {properties.priority && (
            <Listbox
              as="div"
              value={issue.priority}
              onChange={(data: string) => {
                partialUpdateIssue({ priority: data });
              }}
              className="group relative flex-shrink-0"
              disabled={isNotAllowed}
            >
              {({ open }) => (
                <>
                  <div>
                    <Listbox.Button
                      className={`flex ${
                        isNotAllowed ? "cursor-not-allowed" : "cursor-pointer"
                      } items-center gap-x-2 rounded px-2 py-0.5 capitalize shadow-sm focus:border-indigo-500 focus:outline-none focus:ring-1 focus:ring-indigo-500 ${
                        issue.priority === "urgent"
                          ? "bg-red-100 text-red-600"
                          : issue.priority === "high"
                          ? "bg-orange-100 text-orange-500"
                          : issue.priority === "medium"
                          ? "bg-yellow-100 text-yellow-500"
                          : issue.priority === "low"
                          ? "bg-green-100 text-green-500"
                          : "bg-gray-100"
                      }`}
                    >
                      {getPriorityIcon(
                        issue.priority && issue.priority !== "" ? issue.priority ?? "" : "None",
                        "text-sm"
                      )}
                    </Listbox.Button>

                    <Transition
                      show={open}
                      as={React.Fragment}
                      leave="transition ease-in duration-100"
                      leaveFrom="opacity-100"
                      leaveTo="opacity-0"
                    >
                      <Listbox.Options className="absolute right-0 z-10 mt-1 max-h-48 w-36 overflow-auto rounded-md bg-white py-1 text-xs shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none">
                        {PRIORITIES?.map((priority) => (
                          <Listbox.Option
                            key={priority}
                            className={({ active }) =>
                              `flex cursor-pointer select-none items-center gap-x-2 px-3 py-2 capitalize ${
                                active ? "bg-indigo-50" : "bg-white"
                              }`
                            }
                            value={priority}
                          >
                            {getPriorityIcon(priority, "text-sm")}
                            {priority ?? "None"}
                          </Listbox.Option>
                        ))}
                      </Listbox.Options>
                    </Transition>
                  </div>
                  <div className="absolute bottom-full right-0 z-10 mb-2 hidden whitespace-nowrap rounded-md bg-white p-2 shadow-md group-hover:block">
                    <h5 className="mb-1 font-medium text-gray-900">Priority</h5>
                    <div
                      className={`capitalize ${
                        issue.priority === "urgent"
                          ? "text-red-600"
                          : issue.priority === "high"
                          ? "text-orange-500"
                          : issue.priority === "medium"
                          ? "text-yellow-500"
                          : issue.priority === "low"
                          ? "text-green-500"
                          : ""
                      }`}
                    >
                      {issue.priority ?? "None"}
                    </div>
                  </div>
                </>
              )}
            </Listbox>
          )}
          {properties.state && (
            <CustomSelect
              label={
                <>
                  <span
                    className="h-1.5 w-1.5 flex-shrink-0 rounded-full"
                    style={{
                      backgroundColor: issue.state_detail.color,
                    }}
                  />
                  {addSpaceIfCamelCase(issue.state_detail.name)}
                </>
              }
              value={issue.state}
              onChange={(data: string) => {
                partialUpdateIssue({ state: data });
              }}
              maxHeight="md"
              noChevron
              disabled={isNotAllowed}
            >
              {states?.map((state) => (
                <CustomSelect.Option key={state.id} value={state.id}>
                  <>
                    <span
                      className="h-1.5 w-1.5 flex-shrink-0 rounded-full"
                      style={{
                        backgroundColor: state.color,
                      }}
                    />
                    {addSpaceIfCamelCase(state.name)}
                  </>
                </CustomSelect.Option>
              ))}
            </CustomSelect>
          )}
          {/* {properties.cycle && !typeId && (
            <div className="flex flex-shrink-0 items-center gap-1 rounded border px-2 py-1 text-xs shadow-sm duration-300 hover:bg-gray-100 focus:border-indigo-500 focus:outline-none focus:ring-1 focus:ring-indigo-500">
              {issue.issue_cycle ? issue.issue_cycle.cycle_detail.name : "None"}
            </div>
          )} */}
          {properties.due_date && (
            <div
              className={`group relative ${
                issue.target_date === null
                  ? ""
                  : issue.target_date < new Date().toISOString()
                  ? "text-red-600"
                  : findHowManyDaysLeft(issue.target_date) <= 3 && "text-orange-400"
              }`}
            >
              <CustomDatePicker
                placeholder="N/A"
                value={issue?.target_date}
                onChange={(val) =>
                  partialUpdateIssue({
                    target_date: val,
                  })
                }
                className={issue?.target_date ? "w-[6.5rem]" : "w-[3rem] text-center"}
              />
              <div className="absolute bottom-full right-0 z-10 mb-2 hidden whitespace-nowrap rounded-md bg-white p-2 shadow-md group-hover:block">
                <h5 className="mb-1 font-medium text-gray-900">Due date</h5>
                <div>{renderShortNumericDateFormat(issue.target_date ?? "")}</div>
                <div>
                  {issue.target_date
                    ? issue.target_date < new Date().toISOString()
                      ? `Due date has passed by ${findHowManyDaysLeft(issue.target_date)} days`
                      : findHowManyDaysLeft(issue.target_date) <= 3
                      ? `Due date is in ${findHowManyDaysLeft(issue.target_date)} days`
                      : "Due date"
                    : "N/A"}
                </div>
              </div>
            </div>
          )}
          {properties.sub_issue_count && (
            <div className="flex flex-shrink-0 items-center gap-1 rounded border px-2 py-1 text-xs shadow-sm">
              {issue.sub_issues_count} {issue.sub_issues_count === 1 ? "sub-issue" : "sub-issues"}
            </div>
          )}
          {properties.assignee && (
            <Listbox
              as="div"
              value={issue.assignees}
              onChange={(data: any) => {
                const newData = issue.assignees ?? [];

                if (newData.includes(data)) newData.splice(newData.indexOf(data), 1);
                else newData.push(data);

                partialUpdateIssue({ assignees_list: newData });
              }}
              className="group relative flex-shrink-0"
              disabled={isNotAllowed}
            >
              {({ open }) => (
                <>
                  <div>
                    <Listbox.Button>
                      <div
                        className={`flex ${
                          isNotAllowed ? "cursor-not-allowed" : "cursor-pointer"
                        } items-center gap-1 text-xs`}
                      >
                        <AssigneesList userIds={issue.assignees ?? []} />
                      </div>
                    </Listbox.Button>

                    <Transition
                      show={open}
                      as={React.Fragment}
                      leave="transition ease-in duration-100"
                      leaveFrom="opacity-100"
                      leaveTo="opacity-0"
                    >
                      <Listbox.Options className="absolute right-0 z-10 mt-1 max-h-48 overflow-auto rounded-md bg-white py-1 text-xs shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none">
                        {people?.map((person) => (
                          <Listbox.Option
                            key={person.id}
                            className={({ active, selected }) =>
                              `flex items-center gap-x-1 cursor-pointer select-none p-2 ${
                                active ? "bg-indigo-50" : ""
                              } ${
                                selected || issue.assignees?.includes(person.member.id)
                                  ? "bg-indigo-50 font-medium"
                                  : "font-normal"
                              }`
                            }
                            value={person.member.id}
                          >
                            <Avatar user={person.member} />
                            <p>
                              {person.member.first_name && person.member.first_name !== ""
                                ? person.member.first_name
                                : person.member.email}
                            </p>
                          </Listbox.Option>
                        ))}
                      </Listbox.Options>
                    </Transition>
                  </div>
                  <div className="absolute bottom-full right-0 z-10 mb-2 hidden whitespace-nowrap rounded-md bg-white p-2 shadow-md group-hover:block">
                    <h5 className="mb-1 font-medium">Assigned to</h5>
                    <div>
                      {issue.assignee_details?.length > 0
                        ? issue.assignee_details.map((assignee) => assignee.first_name).join(", ")
                        : "No one"}
                    </div>
                  </div>
                </>
              )}
            </Listbox>
          )}
          {type && !isNotAllowed && (
            <CustomMenu width="auto" ellipsis>
              <CustomMenu.MenuItem onClick={editIssue}>Edit</CustomMenu.MenuItem>
              {type !== "issue" && (
                <CustomMenu.MenuItem onClick={removeIssue}>
                  <>Remove from {type}</>
                </CustomMenu.MenuItem>
              )}
              <CustomMenu.MenuItem onClick={() => setDeleteIssue(issue)}>
                Delete permanently
              </CustomMenu.MenuItem>
            </CustomMenu>
          )}
        </div>
      </div>
    </>
  );
};

export default SingleListIssue;