import { differenceInDays } from 'date-fns';

import {
  PillsProps as HuPillsProps,
  PillsProps,
} from '@material-hu/components/design-system/Pills/types';

import { queryClient } from 'src/config/react-query';
import { LokaliseTFunction } from 'src/utils/i18n';

import { employeeLifecycleKeys } from './queries';
import {
  JourneyAssignee,
  JourneyProcessStatusType,
  JourneyProgressStatusType,
  JourneyStep,
  JourneyStepStatusType,
  JourneyTask,
  JourneyTaskDetail,
} from './types';

type GroupStepsBySectionProps = {
  steps: JourneyStep[] | JourneyTask[];
  isTasks?: boolean;
};

export const getJourneyPillStatus = (status: JourneyProgressStatusType) => {
  const statuses: Record<JourneyProgressStatusType, PillsProps['type']> = {
    NOT_STARTED: 'neutral',
    IN_PROGRESS: 'warning',
    DONE: 'success',
    PAUSED: 'neutral',
  };

  return statuses[status];
};

export const getMyTeamJourneyPillStatus = (
  status: JourneyProgressStatusType,
) => {
  const statuses: Record<JourneyProgressStatusType, PillsProps['type']> = {
    NOT_STARTED: 'info',
    IN_PROGRESS: 'warning',
    DONE: 'success',
    PAUSED: 'disabled',
  };
  return statuses[status];
};

export const getProcessPillStatus = (status: JourneyProcessStatusType) => {
  const statuses: Record<JourneyProcessStatusType, PillsProps['type']> = {
    ACTIVE: 'success',
    DRAFT: 'warning',
    PAUSED: 'disabled',
  };

  return statuses[status];
};

export const getStepPillStatus = (status: JourneyStepStatusType) => {
  const statuses: Record<JourneyStepStatusType, PillsProps['type']> = {
    IN_PROGRESS: 'warning',
    AVAILABLE: 'neutral',
    NOT_AVAILABLE: 'neutral',
    COMPLETED: 'success',
  };

  return statuses[status];
};

export const groupStepsBySection = ({
  steps,
  isTasks,
}: GroupStepsBySectionProps) => {
  const availableSteps: (JourneyStep | JourneyTask)[] = [];
  const notAvailableSteps: (JourneyStep | JourneyTask)[] = [];

  if (!steps || !steps.length)
    return { availableSteps: [], notAvailableSteps: [] };

  steps.forEach(step => {
    const isAvailable = isTasks
      ? (step as JourneyTask).isAvailable
      : (step as JourneyStep).status !== 'NOT_AVAILABLE';

    if (isAvailable) availableSteps.push(step);
    else notAvailableSteps.push(step);
  });

  return { availableSteps, notAvailableSteps };
};

export const getTaskPill = (
  task: JourneyTask,
  t: LokaliseTFunction,
): HuPillsProps | undefined => {
  if (task.status === 'DONE') {
    return {
      label: t('tasks.status.completed'),
      type: 'success',
    };
  }

  if (!task.expiresAfter || !task.isAvailable) return undefined;

  const diffInDays = differenceInDays(new Date(), new Date(task.expiresAfter));

  if (diffInDays < -5) return undefined;

  if (diffInDays === 0) {
    return {
      label: t('tasks.status.expires_today'),
      type: 'error',
    };
  }

  return diffInDays < 0
    ? {
        label: t('tasks.status.expires_in_days', {
          count: Math.abs(diffInDays),
        }),
        type: 'warning',
      }
    : {
        label: t('tasks.status.expired_days_ago', {
          count: diffInDays,
        }),
        type: 'error',
      };
};

export const getExpiredPill = (
  task: JourneyTaskDetail | undefined,
  t: LokaliseTFunction,
) => {
  if (!task || !task.expiresAfter || task.status === 'DONE') return undefined;

  const diffInDays = differenceInDays(new Date(), new Date(task.expiresAfter));

  let label;
  let type: PillsProps['type'] = 'error';

  if (diffInDays === -1) {
    label = t('custom_task_detail.expires_tomorrow');
    type = 'warning';
  } else if (diffInDays === 0) {
    label = t('custom_task_detail.expires_today');
  } else if (diffInDays > 0) {
    label = t('custom_task_detail.expired');
  }
  return label ? ({ label, type } as HuPillsProps) : undefined;
};

export const invalidateJourneyStepTasksQueries = (task?: JourneyTaskDetail) => {
  if (!task) return;

  const { stepId, userJourneyId: journeyId } = task;

  const [journeysKey] = employeeLifecycleKeys.journeys.all();

  queryClient.invalidateQueries(journeysKey);
  queryClient.invalidateQueries(
    employeeLifecycleKeys.journeys.steps(journeyId),
  );
  queryClient.invalidateQueries(
    employeeLifecycleKeys.journeys.step(journeyId, stepId),
  );
  const [journeyStepTaskKey, journeyStepIdKey] =
    employeeLifecycleKeys.journeys.stepTasks({
      stepId,
      journeyId,
    });
  queryClient.invalidateQueries([journeyStepTaskKey, journeyStepIdKey]);
  queryClient.invalidateQueries(
    employeeLifecycleKeys.journeys.stepTask(task.id),
  );
};

/**
 * Returns an array of JourneyAssignee objects whose IDs match those provided in the collaboratorsQueryIds string.
 *
 * @param collaborators - The list of available JourneyAssignee objects to select from.
 * @param collaboratorsQueryIds - A comma-separated string of collaborator IDs (e.g., "1,2,3") or null.
 * @returns An array of JourneyAssignee objects whose IDs are present in collaboratorsQueryIds, in the order they appear in the string.
 *
 * If collaboratorsQueryIds is null, empty, or collaborators is falsy, returns an empty array.
 */
export const getSelectedCollaborators = (
  collaborators: JourneyAssignee[],
  collaboratorsQueryIds?: string,
): JourneyAssignee[] => {
  if (!collaboratorsQueryIds || !collaborators) return [];

  const selectedCollaborators = collaboratorsQueryIds
    .split(',')
    .filter(Boolean)
    .map(Number);

  const filteredCollaborators: JourneyAssignee[] = [];

  selectedCollaborators.forEach(id => {
    const collaboratorFound = collaborators.find(
      collaborator => collaborator.id === id,
    );

    if (collaboratorFound) filteredCollaborators.push(collaboratorFound);
  });

  return filteredCollaborators;
};
