import { parse, parseISO, subMilliseconds } from 'date-fns';
import { fromZonedTime, getTimezoneOffset } from 'date-fns-tz';

export const parseDateTime = (format: string) => (value: string) =>
  !!value ? parse(value, format, new Date()) : value;
export const parseIsoDateTime = (value: string) => parseISO(value);

export const parseZonedDateTime =
  (tz: string) => (format: string) => (value: string) =>
    fromZonedTime(parse(value, format, new Date()), tz);

export const parseCETDateTime = parseZonedDateTime('Europe/Berlin');

export const subTimeZone = (value: string) =>
  subMilliseconds(
    new Date(value),
    getTimezoneOffset('Europe/Berlin', new Date(value)),
  );

export const parseInteger = (value = '') => parseInt(value);

export const parseFloat = (value = '') =>
  Number((value ?? '').replace(',', '.'));

export const parseBoolean = (value = '') => value === '1' || value === 'true';

export const pick =
  <T extends Record<string, T[keyof T]>>(keys: (keyof T)[]) =>
  (value: Record<keyof T, T[keyof T]>) =>
    keys.reduce(
      (obj, key) => {
        if (value && Object.prototype.hasOwnProperty.call(value, key)) {
          obj[key] = value[key];
        }
        return obj;
      },
      {} as Record<keyof T, T[keyof T]>,
    );

export const pick2 = <T extends Record<string, unknown>>(
  keys: (keyof T)[],
  value: T,
) =>
  keys.reduce((obj, key) => {
    if (value && Object.prototype.hasOwnProperty.call(value, key)) {
      obj[key] = value[key];
    }
    return obj;
  }, {} as T);

export const transformProperties =
  <T extends string, U>(transformer: (value: T) => U) =>
  (value: Record<string, T>) =>
    Object.entries(value).reduce(
      (obj, [key, value]) => ({
        ...obj,
        [key]: transformer(value),
      }),
      {} as Record<string, U>,
    );
