import { format, isValid } from 'date-fns';
import i18next, { type TFunction } from 'i18next';
import { grey } from '@material-hu/mui/colors';

import { logEvent } from 'src/config/logging';
import { Languages } from 'src/constants/languages';
import { EventName } from 'src/types/amplitude';
import {
  CLOSED,
  type FormItemResponse,
  FormSkipTypes,
  FormStatus,
  FormStepType,
  FormType,
  InputType,
  NOT_ASSIGNED_TO_APPROVAL_STEP,
  PENDING,
  type Question,
  type Step,
} from 'src/types/forms';
import { type MeUser } from 'src/types/user';
import { sortByPosition } from 'src/utils/position';

import { getCurrentLocale } from './locale';

const { ENGLISH, SPANISH } = Languages;

const removeQueryParamMapper = (values: any) =>
  values.map((e: any) => ({ ...e, url: e.url?.split('?')[0] }));

export const formatValue = (key: any, value: any) => {
  if (key === 'phoneCode') return null;
  if (!value && value !== 0) return null;

  const keyFragments = key.split('-');
  const inputType = keyFragments[2];

  const propertiesAnswer = {
    id: Number(keyFragments[4]),
    inputType,
  };

  if (inputType === InputType.CHECKBOX && keyFragments[3] === 'true') {
    if (!Object.values(value).length) return null;
    return {
      ...propertiesAnswer,
      answer: Object.values(value),
    };
  }
  if (inputType === InputType.FILE) {
    return {
      ...propertiesAnswer,
      attachments: removeQueryParamMapper(value),
    };
  }
  if (inputType === InputType.MEDIA) {
    if (value?.images?.length === 0 && value?.videos?.length === 0) {
      return null;
    }

    return {
      ...propertiesAnswer,
      attachments: [
        ...(Array.isArray(value.images)
          ? removeQueryParamMapper(value.images)
          : []),
        ...(Array.isArray(value.videos)
          ? removeQueryParamMapper(value.videos)
          : []),
      ],
    };
  }
  if (inputType === InputType.DIGITAL_SIGN) {
    return {
      ...propertiesAnswer,
      attachments: removeQueryParamMapper(value.answer),
    };
  }
  if (inputType === InputType.DATE) {
    return {
      ...propertiesAnswer,
      answer: [format(value, 'dd/MM/yyyy')],
    };
  }
  if (inputType === InputType.DATE_MMAAAA) {
    return {
      ...propertiesAnswer,
      answer: [format(value, 'MM/yyyy')],
    };
  }
  if (inputType === InputType.DATE_MMDDYYYY) {
    return {
      ...propertiesAnswer,
      answer: [format(value, 'MM/dd/yyyy')],
    };
  }
  if (inputType === InputType.TIME) {
    return {
      ...propertiesAnswer,
      answer: [format(value, 'HH:mm')],
    };
  }
  if (inputType === InputType.DECIMAL) {
    return {
      ...propertiesAnswer,
      answer: [value.toString()],
    };
  }
  if (inputType === InputType.PHONE) {
    if (value.length <= 4) return null;

    return {
      ...propertiesAnswer,
      answer: [value],
    };
  }
  if (inputType === InputType.CHECKBOX_GRID) {
    const rows: any[] = [];

    const entries = Object.entries(value);

    if (!entries.length) return null;

    entries.forEach(([id, answer]) => {
      rows.push({ id: Number(id), answer });
    });

    return {
      ...propertiesAnswer,
      rows,
    };
  }

  return {
    ...propertiesAnswer,
    answer: [value],
  };
};

export const formatDecimalAnswer = (value: any, lang: any) =>
  lang === SPANISH ? value?.replace('.', ',') : value;

export const formatValues = (values: any) =>
  Object.keys(values)
    .map(key => formatValue(key, values[key]))
    .filter(value => value !== null);

export const buildCheckboxGridAnswer = (answerInput: any) => {
  if (!answerInput) return null;

  const answers = answerInput.answer;
  if (!answers) return null;

  const builtOptions = answers.reduce((answerObj: any, current: any) => {
    const options: string[] = [];

    current?.answer?.forEach((option: any) => {
      if (option.checked) {
        options.push(option.description);
      }
    });

    if (!options.length) return answerObj;

    answerObj[current.rowId] = options;
    return answerObj;
  }, {});

  if (!Object.keys(builtOptions).length) return null;

  return builtOptions;
};

export const buildOptionsToDropDown = (options: any) =>
  options.map((opt: any) => ({
    value: opt.description,
    label: opt.description,
  }));

export const buildOptionsToDropDownCatalog = (options: any) =>
  options.map((opt: any, index: number) => ({ value: index, label: opt }));

export const buildOptionsToRadioButton = (options: any) =>
  options.map((opt: any) => ({
    value: opt.description,
    label: opt.description,
  }));

export const getDayMonthYear = (answerDate: any) => {
  const dateParts = answerDate.split('/');
  return new Date(+dateParts[2], dateParts[1] - 1, +dateParts[0]);
};

export const getMonthYear = (answerDate: any) => {
  const dateParts = answerDate.split('/');
  return new Date(dateParts[1], dateParts[0] - 1);
};

export const getMonthDayYear = (answerDate: string) => {
  const dateParts = answerDate?.split('/');
  if (!dateParts || dateParts.length < 3) return null;
  const date = new Date(+dateParts[2], +dateParts[0] - 1, +dateParts[1]);
  return isNaN(date.getTime()) ? null : date;
};

export const formatAnswerCheckbox = (answerCheckbox: any) => {
  const splitAnswerCheckbox = answerCheckbox.split('-');
  let result = '';
  for (let i = 0; i < splitAnswerCheckbox.length - 1; i++) {
    if (i !== 0) {
      result += '-';
    }
    result += splitAnswerCheckbox[i];
  }
  return result;
};

export const formatRouteForms = (path: any) => `${path.toLowerCase()}s`;

// TODO: esto debera cambiar cuando el back implemente correctamente la solucion
export const getCorrectStatus = (
  isAgent: any,
  approvalStatus: any,
  lastStepOfResponsible: any,
) => {
  if (!isAgent) return approvalStatus;
  if (approvalStatus === CLOSED) {
    return lastStepOfResponsible?.approvalStatus ?? PENDING;
  }
  return approvalStatus;
};

export const getLabel = (
  needApproval: any,
  approvalStatus: any,
  t: TFunction,
) => {
  if (!needApproval) {
    return t('NO_NEED_APPROVAL');
  }

  if (
    approvalStatus === FormStatus.APPROVED ||
    approvalStatus === FormStatus.REJECTED
  ) {
    return t(`FORM_STATUS_${approvalStatus}`);
  }

  if (approvalStatus === FormStatus.CANCELLED) {
    return t(`FORM_STATUS_${approvalStatus}`);
  }

  return t('NEED_APPROVAL');
};

export const createBulkBody = (items: any) =>
  items.reduce(
    (acc: any, elem: any) => ({
      chatIds: elem.chatId ? [...acc.chatIds, elem.chatId] : acc.chatIds,
      approvalWorkflows: [
        ...acc.approvalWorkflows,
        { formId: elem.formId, stepId: elem.stepId },
      ],
    }),
    { chatIds: [], approvalWorkflows: [] },
  );

export const getBackgroundColor = (needApproval: any, isAgent: any) => {
  if (!isAgent) return grey[500];
  return !needApproval ? grey[500] : grey[700];
};

export const getInfoText = (text: any) => {
  const [status, ...nameArray] = text.split(',');

  const STATUS = {
    ASSIGNED_QUERY: 'forms:assigned_query',
    CLOSED: 'forms:finalized_query',
  };

  return i18next.t(STATUS[status as keyof typeof STATUS], {
    responsible: nameArray.join(','),
  });
};

export const getKey = (name = '') => ['forms', `${name.toLowerCase()}Forms`];

export const getStatusFormForRequest = (approveForm: any, rejectForm: any) => {
  if (approveForm) return FormStatus.APPROVED;
  if (rejectForm) return FormStatus.REJECTED;
  return null;
};

export const getPlaceholderString = (
  viewsArray: any,
  inputType?: InputType,
) => {
  if (inputType === InputType.DATE_MMDDYYYY) {
    return 'FORMS:FORM_DATEPICKER_PLACEHOLDER_MONTH_DAY_YEAR';
  }
  if (viewsArray !== undefined && viewsArray[2] === undefined) {
    return 'FORMS:FORM_DATEPICKER_PLACEHOLDER_MONTH_YEAR';
  }
  return 'FORMS:FORM_DATEPICKER_PLACEHOLDER_DATE';
};

export const getQuestions = (questions: Record<number, Question>): Question[] =>
  sortByPosition(Object.values(questions));

export const getQuestionName = (question: Question): string =>
  `${question.inputType}-${question.multipleAnswer}-${question.id}`;

export const hasMandatory = (questions: Question[]): boolean =>
  questions?.filter(q => q.required).length > 0;

export const getUnreadCompletedFormsWithPages = (
  completedForms: any[] = [],
): number => {
  let counter = 0;

  completedForms.forEach(formPage => {
    formPage?.data.forEach((formItem: any) => {
      if (formItem.unreadMessages > 0) {
        counter++;
      }
    });
  });

  return counter;
};

export const findFormIndex = (chatItemId: number, formDataArray: any[]) =>
  formDataArray.findIndex(element => element.chatId === chatItemId);

export const findFormIndexOnPages = (
  id: number,
  pages: any[],
): [pageIndex: number, formIndex: number] => {
  for (let i = 0; i < pages.length; i++) {
    const formIndex = pages[i].data.findIndex(
      (form: any) => form.chatId === id,
    );
    if (formIndex !== -1) return [i, formIndex];
  }
  return [-1, -1];
};

export const isFormReadyToSubmit = (
  currentStep: any,
  stepsCount: any,
  stepsList: any,
) => {
  const isPreSubmitStep = currentStep + 1 === stepsCount;
  const isLastStep = currentStep + 2 === stepsCount;
  const currentStepData = stepsList[currentStep];

  const allQuestionsHaveNullOrEndSkipType = !currentStepData?.questions.some(
    (question: any) =>
      question.options?.some(
        (option: any) =>
          option.skip && option.skip.skipType !== FormSkipTypes.END,
      ),
  );
  const stepSkipTypeIsEnd =
    currentStepData?.skip?.skipType === FormSkipTypes.END;

  const noQuestionHasSkip = !currentStepData?.questions?.some((question: any) =>
    question.options?.some((option: any) => option.skip),
  );

  return (
    ((isLastStep || isPreSubmitStep) && allQuestionsHaveNullOrEndSkipType) ||
    (stepSkipTypeIsEnd && noQuestionHasSkip)
  );
};

export const buildStepItem = (
  steps: any,
  stepToGo = 0,
  optionId = undefined,
) => ({
  stepIndex: stepToGo,
  skip: steps[stepToGo]?.skip,
  stepId: steps[stepToGo]?.id,
  optionId,
});

export const findStepToGo = (steps: any, destinationStepId: any) =>
  steps?.findIndex((elem: any) => elem.id === destinationStepId);

export const getOptionSelected = (options: any, value: any) =>
  options.find((opt: any) => opt.description === value);

export const getStepById = (steps: any, stepId: any) =>
  steps.find((step: any) => step.id === stepId);

export const getPositionQuestionByOptionId = (questions: any, optionId: any) =>
  questions.find((q: any) => q.options?.find((opt: any) => opt.id === optionId))
    ?.position;

export const makePreSubmitStep = () => ({
  id: `${Math.random()}-pre-submit`,
  questions: [],
});

export const modifyStackStepForms = (
  options: any,
  value: any,
  stackStepForms: any,
  stepsList: any,
) => {
  const optionSelected = getOptionSelected(options, value);
  const currentStepInStack = stackStepForms[stackStepForms?.length - 1];

  if (!currentStepInStack.optionId && optionSelected.skip) {
    currentStepInStack.skip = optionSelected.skip;
    currentStepInStack.optionId = optionSelected.id;
  } else if (optionSelected.skip) {
    const step = getStepById(stepsList, currentStepInStack.stepId);
    const positionCurrentStepInStack = getPositionQuestionByOptionId(
      step.questions,
      currentStepInStack.optionId,
    );

    const positionOptionSelected = getPositionQuestionByOptionId(
      step.questions,
      optionSelected.id,
    );

    if (
      (positionOptionSelected >= positionCurrentStepInStack &&
        (optionSelected.skip || !currentStepInStack.skip)) ||
      (positionOptionSelected < positionCurrentStepInStack &&
        !currentStepInStack.skip)
    ) {
      currentStepInStack.skip = optionSelected.skip;
      currentStepInStack.optionId = optionSelected.id;
    }
  }
};

export const resetValuesGoBack = (
  formValues: any,
  destinationStepIds: any,
  resetField: any,
) => {
  Object.keys(formValues).forEach(formValueItem => {
    const formValueItemSplit = formValueItem.split('-');
    if (destinationStepIds.includes(parseInt(formValueItemSplit[5]))) {
      resetField(formValueItem);
    }
  });
};

export const childDestinations = (
  formDetailData: any,
  currentId: any,
  stopId: any,
  destinationStepIds: any,
) => {
  const stopIds: any[] = [];
  stopIds.push(stopId);
  formDetailData.steps.forEach((item: any) => {
    if (item.id === stopId) {
      if (item.skip) {
        stopIds.push(item.skip.destinationStepId);
      }
    }
  });
  formDetailData.steps.forEach((item: any) => {
    if (item.id === currentId) {
      if (item.skip) {
        destinationStepIds.push(item.skip.destinationStepId);
      } else if (!stopIds.includes(currentId + 1)) {
        destinationStepIds.push(currentId + 1);
      }
    }
  });
  return destinationStepIds;
};

export const getDestinationStepIds = (step: Step) => {
  const destinationStepIds: any[] = [];
  step.questions.forEach(item => {
    if (item.options) {
      item.options.forEach(elem => {
        destinationStepIds.push(elem.skip?.destinationStepId);
      });
    }
  });
  return destinationStepIds;
};

export const handleErrorToAddComment = (error: any) => {
  if (error.response?.data?.code === NOT_ASSIGNED_TO_APPROVAL_STEP) {
    return i18next.t('FORMS:NOT_ASSIGNED_TO_APPROVAL_STEP');
  }
  return i18next.t('FORMS:ERROR_ADD_COMMENT');
};

export const userFields = {
  COMPLETE_NAME: 'name',
  BIRTHDATE: 'birthdate',
  EMAIL: 'email',
  COMPLETION_DATE: 'COMPLETION_DATE',
  EMPLOYEE_INTERNAL_ID: 'employeeInternalId',
  HIRING_DATE: 'hiringDate',
  DIRECT_BOSS: 'DIRECT_BOSS',
  DEPARTMENT: 'DEPARTMENT',
};

export const getAnswerAutocompleteField = (
  userField: any,
  autoCompleteBoss: any,
  user: any,
  t: any,
) => {
  let answer: any;

  const profileField = userFields[userField as keyof typeof userFields];

  const customFieldValue = user.profileData[userField];

  if (profileField) {
    if (userField === userFields.DEPARTMENT) {
      answer = user.department?.name;
    } else {
      answer =
        profileField === userFields.COMPLETE_NAME
          ? `${user.firstName} ${user.lastName}`
          : user[profileField];
    }
  } else if (customFieldValue || customFieldValue === 0) {
    answer = Array.isArray(customFieldValue)
      ? customFieldValue.join(', ')
      : customFieldValue;
  }

  if (userField === userFields.DIRECT_BOSS) {
    answer = autoCompleteBoss;
  }

  const KNOWN_DATE_FIELDS = ['BIRTHDATE', 'HIRING_DATE', 'COMPLETION_DATE'];

  if (KNOWN_DATE_FIELDS.includes(userField)) {
    const dateToValidate =
      userField === 'COMPLETION_DATE' ? new Date() : answer;

    if (isValid(dateToValidate)) {
      const locale = getCurrentLocale(user);
      answer = format(dateToValidate, 'P', { locale });
    }
  }

  return answer || answer === 0 ? answer : t('EMPTY');
};

export const getFilteredValues = (objValues: any) => {
  const filteredPairs = Object.entries(objValues).filter(
    ([key]) => !key.includes('AUTOCOMPLETE'),
  );
  return Object.fromEntries(filteredPairs);
};

export const checkEmptyForm = (objValues: any) =>
  !objValues.some(
    (value: any) =>
      value !== undefined &&
      value !== '' &&
      value !== null &&
      (typeof value !== 'object' || Object.keys(value).length !== 0),
  );

export const checkEmptyObject = (obj: any) => {
  for (const key in obj) {
    if (Object.hasOwn(obj, key)) {
      const value = obj[key];
      const isEmptyObject =
        Object.prototype.toString.call(value) === '[object Object]' &&
        Object.keys(value).length === 0;
      const isEmptyArray = Array.isArray(value) && value.length === 0;
      if (
        value !== undefined &&
        value !== null &&
        value !== '' &&
        !isEmptyObject &&
        !isEmptyArray
      ) {
        return false;
      }
    }
  }
  return true;
};

export const getThousandSeparator = (lang: any) => (lang === 'en' ? ',' : '.');

export const getDecimalSeparator = (lang: any) => (lang === 'en' ? '.' : ',');

export const getCurrentProgress = (totalSteps: any, currentStep: any) => {
  const remainder = 100 / totalSteps;
  const multiple = 100 - remainder;
  return (currentStep * multiple) / totalSteps;
};

export const logAmplitudeEvents = (formDetailData: any, response: any) => {
  if (formDetailData?.type === FormType.SURVEY) {
    logEvent(EventName.SURVEY_ANSWER, {
      surveyFilledId: response.data?.form.id,
      surveyId: response.data?.form.templateId,
      surveyName: response.data?.form.title,
    });
  }

  if (formDetailData?.type === FormType.FORM) {
    if (formDetailData?.needApproval) {
      logEvent(EventName.FORM_APPROVAL_FILL, {
        formFilledId: response.data?.id,
        formName: response.data?.title,
        formId: response.data?.templateId,
        formPDF: formDetailData.stepsType === FormStepType.FILE,
      });
    } else {
      logEvent(EventName.FORM_REGULAR_FILL, {
        formFilledId: response.data?.form.id,
        formName: response.data?.form.title,
        formId: response.data?.form.templateId,
        formPDF: formDetailData.stepsType === FormStepType.FILE,
      });
    }
  }
};

export const logAmplitudeEditEvent = (
  formFilledId: any,
  needApproval: any,
  formId: any,
) =>
  logEvent(
    needApproval ? EventName.FORM_APPROVAL_EDIT : EventName.FORM_REGULAR_EDIT,
    { formFilledId, formId },
  );

export const getDateFormat = (user: MeUser | null, inputType?: InputType) => {
  if (inputType === InputType.DATE_MMDDYYYY) return 'MM/DD/YYYY';
  if (!user) return 'DD/MM/YYYY';
  const locale = getCurrentLocale(user);
  return locale?.code === ENGLISH ? 'MM/DD/YYYY' : 'DD/MM/YYYY';
};

export const getDueDate = (
  isUnassigned: any,
  isAssigned: any,
  lastFilledStep: FormItemResponse['lastFilledStep'],
) => {
  if (isUnassigned) {
    return lastFilledStep?.assignedDatetimeLimit;
  }
  return isAssigned
    ? lastFilledStep?.reviewDatetimeLimit
    : lastFilledStep?.reviewDatetime;
};

export const getInputTooltipTitle = (
  value: any,
  description: any,
  required: any,
  inputLimit: any,
) => {
  let showDescription = description;
  if (required) {
    showDescription = `* ${showDescription}`;
  }
  if (inputLimit) {
    showDescription = `${showDescription} • (${value.length}/${inputLimit})`;
  }

  return showDescription;
};

export const getSLATime = (
  sla: any,
  elapsedTime: any,
  trackedTime: any,
  isClosed: any,
) => {
  let remainingTime: any;
  if (isClosed) {
    remainingTime = trackedTime / 1000;
  } else {
    remainingTime = (sla - elapsedTime) / 1000;
  }

  const days = Math.floor(remainingTime / (24 * 3600));
  let aux = remainingTime % (24 * 3600);
  const hours = Math.floor(aux / 3600);
  aux = aux % 3600;
  const minutes = Math.floor(aux / 60);

  if (days >= 1) {
    return `${days}d ${hours}h`;
  } else if (hours >= 1) {
    return `${hours}h ${minutes}m`;
  } else {
    return `${minutes}m`;
  }
};

type ColorType =
  | 'error'
  | 'success'
  | 'warning'
  | 'inherit'
  | 'disabled'
  | 'action'
  | 'secondary'
  | 'primary'
  | 'info';

export const getSLAColor = (sla: any, elapsedTime: any): ColorType => {
  const remainingTime = sla - elapsedTime;
  if (remainingTime < 0) {
    return 'error';
  } else if (elapsedTime <= 0.15 * sla) {
    return 'success';
  } else {
    return 'warning';
  }
};
