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

import { isNil } from "lodash-es";
// types
import { EIconSize, ISSUE_PRIORITIES } from "@plane/constants";
import { CycleGroupIcon, CycleIcon, ModuleIcon, PriorityIcon, StateGroupIcon } from "@plane/propel/icons";
import type {
  GroupByColumnTypes,
  IGroupByColumn,
  TCycleGroups,
  IIssueDisplayProperties,
  TGroupedIssues,
} from "@plane/types";
// ui
import { Avatar } from "@plane/ui";
// components
// constants
// stores
import type { ICycleStore } from "@/store/cycle.store";
import type { IIssueLabelStore } from "@/store/label.store";
import type { IIssueMemberStore } from "@/store/members.store";
import type { IIssueModuleStore } from "@/store/module.store";
import type { IStateStore } from "@/store/state.store";

export const HIGHLIGHT_CLASS = "highlight";
export const HIGHLIGHT_WITH_LINE = "highlight-with-line";

export const getGroupByColumns = (
  groupBy: GroupByColumnTypes | null,
  cycle: ICycleStore,
  module: IIssueModuleStore,
  label: IIssueLabelStore,
  projectState: IStateStore,
  member: IIssueMemberStore,
  includeNone?: boolean
): IGroupByColumn[] | undefined => {
  switch (groupBy) {
    case "cycle":
      return getCycleColumns(cycle);
    case "module":
      return getModuleColumns(module);
    case "state":
      return getStateColumns(projectState);
    case "priority":
      return getPriorityColumns();
    case "labels":
      return getLabelsColumns(label) as any;
    case "assignees":
      return getAssigneeColumns(member);
    case "created_by":
      return getCreatedByColumns(member) as any;
    default:
      if (includeNone) return [{ id: `All Issues`, name: `All work items`, payload: {}, icon: undefined }];
  }
};

const getCycleColumns = (cycleStore: ICycleStore): IGroupByColumn[] | undefined => {
  const { cycles } = cycleStore;

  if (!cycles) return;

  const cycleGroups: IGroupByColumn[] = [];

  cycles.map((cycle) => {
    if (cycle) {
      const cycleStatus = cycle?.status ? (cycle.status.toLocaleLowerCase() as TCycleGroups) : "draft";
      cycleGroups.push({
        id: cycle.id,
        name: cycle.name,
        icon: <CycleGroupIcon cycleGroup={cycleStatus} className="h-3.5 w-3.5" />,
        payload: { cycle_id: cycle.id },
      });
    }
  });
  cycleGroups.push({
    id: "None",
    name: "None",
    icon: <CycleIcon className="h-3.5 w-3.5" />,
    payload: { cycle_id: null },
  });

  return cycleGroups;
};

const getModuleColumns = (moduleStore: IIssueModuleStore): IGroupByColumn[] | undefined => {
  const { modules } = moduleStore;

  if (!modules) return;

  const moduleGroups: IGroupByColumn[] = [];

  modules.map((moduleInfo) => {
    if (moduleInfo)
      moduleGroups.push({
        id: moduleInfo.id,
        name: moduleInfo.name,
        icon: <ModuleIcon className="h-3.5 w-3.5" />,
        payload: { module_ids: [moduleInfo.id] },
      });
  }) as any;
  moduleGroups.push({
    id: "None",
    name: "None",
    icon: <ModuleIcon className="h-3.5 w-3.5" />,
    payload: { module_ids: [] },
  });

  return moduleGroups as any;
};

const getStateColumns = (projectState: IStateStore): IGroupByColumn[] | undefined => {
  const { sortedStates } = projectState;
  if (!sortedStates) return;

  return sortedStates.map((state) => ({
    id: state.id,
    name: state.name,
    icon: (
      <div className="h-3.5 w-3.5 rounded-full">
        <StateGroupIcon stateGroup={state.group} color={state.color} size={EIconSize.MD} />
      </div>
    ),
    payload: { state_id: state.id },
  })) as any;
};

const getPriorityColumns = () => {
  const priorities = ISSUE_PRIORITIES;

  return priorities.map((priority) => ({
    id: priority.key,
    name: priority.title,
    icon: <PriorityIcon priority={priority?.key} />,
    payload: { priority: priority.key },
  }));
};

const getLabelsColumns = (label: IIssueLabelStore) => {
  const { labels: storeLabels } = label;

  if (!storeLabels) return;

  const labels = [...storeLabels, { id: "None", name: "None", color: "#666" }];

  return labels.map((label) => ({
    id: label.id,
    name: label.name,
    icon: (
      <div className="h-[12px] w-[12px] rounded-full" style={{ backgroundColor: label.color ? label.color : "#666" }} />
    ),
    payload: label?.id === "None" ? {} : { label_ids: [label.id] },
  }));
};

const getAssigneeColumns = (member: IIssueMemberStore) => {
  const { members } = member;

  if (!members) return;

  const assigneeColumns: any = members.map((member) => ({
    id: member.id,
    name: member?.member__display_name || "",
    icon: <Avatar name={member?.member__display_name} src={undefined} size="md" />,
    payload: { assignee_ids: [member.id] },
  }));

  assigneeColumns.push({ id: "None", name: "None", icon: <Avatar size="md" />, payload: {} });

  return assigneeColumns;
};

const getCreatedByColumns = (member: IIssueMemberStore) => {
  const { members } = member;

  if (!members) return;

  return members.map((member) => ({
    id: member.id,
    name: member?.member__display_name || "",
    icon: <Avatar name={member?.member__display_name} src={undefined} size="md" />,
    payload: {},
  }));
};

export const getDisplayPropertiesCount = (
  displayProperties: IIssueDisplayProperties,
  ignoreFields?: (keyof IIssueDisplayProperties)[]
) => {
  const propertyKeys = Object.keys(displayProperties) as (keyof IIssueDisplayProperties)[];

  let count = 0;

  for (const propertyKey of propertyKeys) {
    if (ignoreFields && ignoreFields.includes(propertyKey)) continue;
    if (displayProperties[propertyKey]) count++;
  }

  return count;
};

export const getIssueBlockId = (issueId: string | undefined, groupId: string | undefined, subGroupId?: string) =>
  `issue_${issueId}_${groupId}_${subGroupId}`;

/**
 * returns empty Array if groupId is None
 * @param groupId
 * @returns
 */
export const getGroupId = (groupId: string) => {
  if (groupId === "None") return [];
  return [groupId];
};

/**
 * method that removes Null or undefined Keys from object
 * @param obj
 * @returns
 */
export const removeNillKeys = <T,>(obj: T) =>
  Object.fromEntries(Object.entries(obj ?? {}).filter(([key, value]) => key && !isNil(value)));

/**
 * This Method returns if the grouped values are subGrouped
 * @param groupedIssueIds
 * @returns
 */
export const isSubGrouped = (groupedIssueIds: TGroupedIssues) => {
  if (!groupedIssueIds || Array.isArray(groupedIssueIds)) {
    return false;
  }

  if (Array.isArray(groupedIssueIds[Object.keys(groupedIssueIds)[0]])) {
    return false;
  }

  return true;
};
