import isNil from 'lodash-es/isNil';

import { TimeTrackingIncidenceTypeProperty } from 'src/types/amplitude';
import { Incidence } from 'src/types/timeTracking';
import { type MeUser } from 'src/types/user';
import { formatDistanceNotifications } from 'src/utils/date';
import { type LokaliseTFunction } from 'src/utils/i18n';

import {
  AVATAR_COLORS,
  type AvatarColor,
  BASE_URL,
  notificationsModulesSet,
} from '../constants';
import { NotificationIconType, type NotificationItem } from '../types';

const isModuleOverlay = (notification: NotificationItem): boolean =>
  notification.icon?.type === NotificationIconType.URL;

const getOverlaySrc = (notification: NotificationItem): string | undefined => {
  if (isModuleOverlay(notification) && !isNil(notification.icon?.source)) {
    return notification.icon.source;
  }
  return notification.iconUrl ?? undefined;
};

const getOverlayText = (notification: NotificationItem): string | undefined => {
  if (
    notification.icon?.type === NotificationIconType.REACTION &&
    !isNil(notification.icon?.source)
  ) {
    return notification.icon.source;
  }
  return notification.reaction ?? undefined;
};

const getOverlayAvatarColor = (
  notification: NotificationItem,
): AvatarColor | undefined => {
  if (!isModuleOverlay(notification)) return undefined;
  const bg = notification.icon?.bgColor;
  return bg && AVATAR_COLORS.includes(bg as AvatarColor)
    ? (bg as AvatarColor)
    : 'primary';
};

type NotificationOverlayProps = {
  overlaySrc: string | undefined;
  overlayText: string | undefined;
  overlayColor: AvatarColor | undefined;
  isModule: boolean;
  hasOverlay: boolean;
};

export const getNotificationOverlayProps = (
  notification: NotificationItem,
): NotificationOverlayProps => {
  const overlaySrc = getOverlaySrc(notification);
  const overlayText = getOverlayText(notification);
  return {
    overlaySrc,
    overlayText,
    overlayColor: getOverlayAvatarColor(notification),
    isModule: isModuleOverlay(notification),
    hasOverlay: Boolean(overlaySrc || overlayText),
  };
};

export const formatNotificationCopetin = ({
  createdAt,
  module,
  user,
  t,
  coursesCustomName,
}: {
  createdAt: string;
  module: string;
  user: MeUser | null;
  t: LokaliseTFunction;
  coursesCustomName: string;
}) => {
  const timeAgo = formatDistanceNotifications(new Date(createdAt), user);

  const hasCustomModuleName = !notificationsModulesSet.has(module);

  let moduleName: string;

  if (module === 'COURSES') {
    moduleName = coursesCustomName;
  } else {
    const moduleKey = module.toLowerCase();
    moduleName = hasCustomModuleName ? module : t(`modules.${moduleKey}`);
  }

  return `${timeAgo} · ${moduleName}`;
};

const parseUrl = (url: string | null): string => {
  if (isNil(url)) return '';
  if (!url.includes(BASE_URL)) return url;
  return url.split(BASE_URL)[1];
};

const readStringExtra = (
  notification: NotificationItem,
  key: string,
): string | null => {
  const value = notification.extraData?.[key];
  return typeof value === 'string' && value ? value : null;
};

type NotificationDeepLinkTranslator = (
  notification: NotificationItem,
) => string;

const defaultDeepLinkTranslator: NotificationDeepLinkTranslator =
  notification => parseUrl(notification.deepLink);

const BACKEND_INCIDENCE_TYPE_MAP: Record<string, Incidence> = {
  ABSENT: Incidence.ABSENT,
  AUTO_CLOSE: Incidence.AUTO_CLOSE,
  LATE: Incidence.LATE,
  LOCATION: Incidence.LOCATION_INCIDENCE,
  // NOT_CLOCKED_IN is intentionally absent: the deeplink opens the drawer on
  // the date only, with no incidence param, since the type is not represented
  // as an incidence tag in the UI.
};

const buildIncidenceDeepLink: NotificationDeepLinkTranslator = notification => {
  const basePath = '/time-tracking/collaborators';
  const userId = readStringExtra(notification, 'userId');
  const dateString = readStringExtra(notification, 'dateString');
  const incidenceType = readStringExtra(notification, 'incidenceType');
  if (!userId || !dateString) return basePath;
  const params = new URLSearchParams({ date: dateString });
  const incidence = incidenceType
    ? (BACKEND_INCIDENCE_TYPE_MAP[incidenceType] ?? null)
    : null;
  if (incidence) params.set('incidenceType', incidence);
  return `${basePath}/${userId}?${params.toString()}`;
};

/**
 * Dispatch table for backend → web deeplink translations, keyed by the
 * backend `notification.type`. Each translator reads structured fields from
 * `notification.extraData` so the URL shape on the wire is decoupled from the
 * canonical web route. Falls back to `parseUrl(notification.deepLink)` for
 * unknown types or when extraData is missing/malformed.
 */
const NOTIFICATION_DEEPLINK_TRANSLATORS: Record<
  string,
  NotificationDeepLinkTranslator
> = {
  CATEGORIZED_HOUR_STEP_PENDING: notification => {
    const basePath = '/time-tracking/overtime-requests';
    const categorizedHourId = readStringExtra(
      notification,
      'categorizedHourId',
    );
    if (!categorizedHourId) return basePath;
    const params = new URLSearchParams({ categorizedHourId });
    return `${basePath}?${params.toString()}`;
  },
  TIME_TRACKING_INCIDENCE_ABSENT: buildIncidenceDeepLink,
  TIME_TRACKING_INCIDENCE_AUTO_CLOSE: buildIncidenceDeepLink,
  TIME_TRACKING_INCIDENCE_LATE: buildIncidenceDeepLink,
  TIME_TRACKING_INCIDENCE_LOCATION: buildIncidenceDeepLink,
  TIME_TRACKING_INCIDENCE_NOT_CLOCKED_IN: buildIncidenceDeepLink,
};

export const translateNotificationDeepLink = (
  notification: NotificationItem,
): string => {
  const type = typeof notification.type === 'string' ? notification.type : null;
  const translator = type ? NOTIFICATION_DEEPLINK_TRANSLATORS[type] : null;
  return (translator ?? defaultDeepLinkTranslator)(notification);
};

/**
 * Maps the backend `extraData.incidenceType` value sent by the time-tracking
 * incidence notifications adapter to the canonical Amplitude property.
 * Returns `null` when the value is missing or not a recognized incidence type.
 */
const BACKEND_TO_AMPLITUDE_INCIDENCE_TYPE: Record<
  string,
  TimeTrackingIncidenceTypeProperty
> = {
  ABSENT: TimeTrackingIncidenceTypeProperty.ABSENCE,
  AUTO_CLOSE: TimeTrackingIncidenceTypeProperty.AUTOCLOSE,
  LATE: TimeTrackingIncidenceTypeProperty.LATE,
  LOCATION: TimeTrackingIncidenceTypeProperty.OUT_OF_LOCATION,
  NOT_CLOCKED_IN: TimeTrackingIncidenceTypeProperty.NOT_CLOCKED_IN,
};

const TIME_TRACKING_INCIDENCE_TYPE_PREFIX = 'TIME_TRACKING_INCIDENCE_';

/**
 * Returns the Amplitude `incidenceType` property for a time-tracking incidence
 * notification, or `null` when the notification is not a TT incidence one.
 */
export const getTimeTrackingIncidenceAmplitudeType = (
  notification: NotificationItem,
): TimeTrackingIncidenceTypeProperty | null => {
  const type = typeof notification.type === 'string' ? notification.type : null;
  if (!type?.startsWith(TIME_TRACKING_INCIDENCE_TYPE_PREFIX)) return null;
  const rawIncidenceType = readStringExtra(notification, 'incidenceType');
  if (!rawIncidenceType) return null;
  return BACKEND_TO_AMPLITUDE_INCIDENCE_TYPE[rawIncidenceType] ?? null;
};
