import { type DeepPartial } from 'react-hook-form';

import { format } from 'date-fns';
import { type Palette } from '@material-hu/mui/styles';

import { type CreateKudosFormValues } from 'src/pages/dashboard/acknowledgements/components/KudosCreateDrawer/types';
import {
  type Acknowledgement,
  type AcknowledgementRankingParams,
  type CreateAcknowledgementParams,
  type KudosRankingFiltersState,
  type KudosRankingFilterValues,
} from 'src/pages/dashboard/acknowledgements/types';
import { type Attachment, FileTypes } from 'src/types/attachments';
import { type MeInstance } from 'src/types/instance';
import { type LokaliseTFunction } from 'src/utils/i18n';
import {
  hasAnyPermissions,
  InstanceCapabilityNames,
  UserPermissions,
} from 'src/utils/permissions';
import { getFullName } from 'src/utils/userUtils';

import { DEFAULT_KUDOS_VALUES } from '../constants';

const VALID_FILE_TYPES = new Set<string>(Object.values(FileTypes));

const toFileType = (type: string): FileTypes =>
  VALID_FILE_TYPES.has(type) ? (type as FileTypes) : FileTypes.FILE;

export const formatAcknowledgementValues = (
  acknowledgement: CreateKudosFormValues,
): CreateAcknowledgementParams => {
  const { acknowledgeds, categoryId, attachments, body } = acknowledgement;

  if (!categoryId) {
    throw new Error('[formatAcknowledgementValues] Category ID is required');
  }

  const formattedAttachments: Attachment[] = attachments
    .filter(({ status, attachment }) => status === 'success' && !!attachment)
    .map(({ attachment }) => {
      const { url, type, name, size } = attachment as NonNullable<
        typeof attachment
      >;
      return { url, type: toFileType(type), name, size };
    });

  return {
    body,
    acknowledgementCategoryId: Number(categoryId.value),
    acknowledgedIds: acknowledgeds.map(option => Number(option.value)),
    attachments: formattedAttachments,
  };
};

export const buildAcknowledgementValues = (
  acknowledgement?: Acknowledgement,
): CreateKudosFormValues => {
  if (!acknowledgement) return DEFAULT_KUDOS_VALUES;

  const formattedAcknowledgeds =
    acknowledgement.acknowledgeds?.map(acknowledged => ({
      value: acknowledged.id,
      label: getFullName(acknowledged),
    })) ?? [];

  return {
    acknowledgeds: formattedAcknowledgeds,
    categoryId: acknowledgement.category
      ? {
          value: acknowledgement.category.id,
          label: acknowledgement.category.name,
        }
      : null,
    body: acknowledgement.body ?? '',
    attachments: [],
  };
};

export const findIndexOnPaginatedPages = (
  id: string | number,
  pages: any[],
): [pageIndex: number, itemIndex: number] => {
  for (let i = 0; i < pages.length; i++) {
    const itemIndex = pages[i]?.data?.findIndex(
      (ack: Acknowledgement) => ack.id === id,
    );

    if (itemIndex !== undefined && itemIndex !== -1) {
      return [i, itemIndex];
    }
  }

  return [-1, -1];
};

export const canCreateAcknowledgements = (permissions: string[]): boolean =>
  hasAnyPermissions(permissions, [UserPermissions.CREATE_ACKNOWLEDGEMENTS]);

export const isExchangeAvailable = (
  instance: MeInstance | null,
  permissions: string[],
): boolean =>
  Boolean(instance?.showAcknowledgmentsPoints) &&
  permissions.includes(InstanceCapabilityNames.CAN_EXCHANGE);

export const idsToRecord = (ids: number[] | null) =>
  Object.fromEntries((ids ?? []).map(id => [id, true]));

export const recordToIds = (record: Record<string, boolean>) =>
  Object.entries(record)
    .filter(([, selected]) => selected)
    .map(([id]) => Number(id));

export const getFirstDayOfMonth = () => {
  const firstDay = new Date(new Date().getFullYear(), new Date().getMonth(), 1);
  return format(firstDay, 'yyyy-MM-dd');
};

export const formatKudosFilters = (
  filters: KudosRankingFiltersState,
  limit: number,
): AcknowledgementRankingParams => ({
  limit,
  page: 1,
  startDate: filters.startDate
    ? format(filters.startDate, 'yyyy-MM-dd')
    : getFirstDayOfMonth(),
  endDate: filters.endDate ? format(filters.endDate, 'yyyy-MM-dd') : undefined,
  categoryIds: filters.categoryIds?.length
    ? filters.categoryIds.join(',')
    : undefined,
  segmentationItemIds: filters.segmentationItemIds?.length
    ? filters.segmentationItemIds.join(',')
    : undefined,
});

export const getThinScrollbarStyles = (palette: Palette) => ({
  overflow: 'auto',
  scrollbarGutter: 'stable',
  '&::-webkit-scrollbar': { width: 6 },
  '&::-webkit-scrollbar-thumb': {
    background: palette.new.border.neutral.default,
    borderRadius: 3,
  },
});

export const hasSelectedFilters = (
  values: DeepPartial<KudosRankingFilterValues>,
) =>
  !!(
    values.startDate ||
    values.endDate ||
    Object.values(values.categories ?? {}).some(Boolean) ||
    Object.values(values.segmentationItemIds ?? {}).some(Boolean)
  );

export const createKudosFilterResolver = (t: LokaliseTFunction) => {
  return (values: KudosRankingFilterValues) => {
    if (
      values.startDate &&
      values.endDate &&
      values.endDate < values.startDate
    ) {
      return {
        values,
        errors: {
          endDate: {
            type: 'validate',
            message: t('validations:end_date_before_start_date'),
          },
        },
      };
    }
    return { values, errors: {} };
  };
};
