import { ControlType, Priority, Size, Type } from '../../common';
import { logActionRequired, logActionRequiredIf } from '../../utilities';

const deprecatedTypeMap: Record<Type, ControlType> = {
  [Type.PRIMARY]: ControlType.ACCENT,
  [Type.SECONDARY]: ControlType.ACCENT,
  [Type.LINK]: ControlType.ACCENT,
  [Type.PAY]: ControlType.POSITIVE,
  [Type.DANGER]: ControlType.NEGATIVE,
};

type OldTypeKeys = Type.DANGER | Type.LINK | Type.SECONDARY;
const oldTypePriorityMap: Record<OldTypeKeys, Priority> = {
  [Type.DANGER]: Priority.SECONDARY,
  [Type.LINK]: Priority.TERTIARY,
  [Type.SECONDARY]: Priority.SECONDARY,
};

const deprecatedTypeMapMessage = {
  [Type.DANGER]: 'Type.NEGATIVE',
  [Type.LINK]: 'ControlType.ACCENT with priority Priority.TERTIARY',
  [Type.PAY]: 'ControlType.POSITIVE',
  [Type.PRIMARY]: 'ControlType.ACCENT',
  [Type.SECONDARY]: 'ControlType.ACCENT with priority Priority.SECONDARY',
};

const deprecatedTypes = Object.keys(deprecatedTypeMap);

type EstablishNewTypeType = (
  originalType: Type | (string & Record<never, never>) | null,
) => `${ControlType}` | string | null;

export const establishNewType: EstablishNewTypeType = (originalType) =>
  originalType && originalType in deprecatedTypeMap
    ? deprecatedTypeMap[originalType as Type]
    : originalType;

type EstablishNewPriorityType = (
  originalPriority?: Priority | (string & Record<never, never>) | null,
  originalType?: OldTypeKeys | (string & Record<never, never>) | null,
) => `${ControlType}` | string | null | undefined;

export const establishNewPriority: EstablishNewPriorityType = (originalPriority, originalType) => {
  const type = originalType ? establishNewType(originalType) : '';

  // The old SECONDARY and LINK types now map to priorities. If they're still using one of
  // these old types, ignore whatever priority they've passed and use this instead.
  if (originalType && originalType in oldTypePriorityMap) {
    return oldTypePriorityMap[originalType as OldTypeKeys];
  }
  // Only ControlType.ACCENT supports tertiary styles
  if (originalPriority === Priority.TERTIARY && type !== ControlType.ACCENT) {
    return Priority.SECONDARY;
  }
  return originalPriority;
};

type DeprecatedTypeMapMessageType = keyof typeof deprecatedTypeMapMessage;
type LogDeprecationNoticesType = (params: {
  size?: `${Size}`;
  type?: DeprecatedTypeMapMessageType | (string & Record<never, never>) | null;
}) => void;
export const logDeprecationNotices: LogDeprecationNoticesType = ({ size, type }) => {
  logActionRequiredIf(
    'Button has deprecated the `Size.EXTRA_SMALL` value for the `size` prop. Please use Size.SMALL instead.',
    size === Size.EXTRA_SMALL,
  );

  if (type && deprecatedTypes.includes(type) && type in deprecatedTypeMapMessage) {
    logActionRequired(
      `Button has deprecated the ${type} value for the \`type\` prop. Please update to ${deprecatedTypeMapMessage[type as DeprecatedTypeMapMessageType]}.`,
    );
  }
};
