import { ThemeColorType } from '@nova-hf/ui';
import {
  addMonths,
  differenceInCalendarDays,
  format,
  formatDistanceStrict,
  subMonths,
} from 'date-fns';
import is from 'date-fns/locale/is';
import { get, isEmpty, set } from 'lodash';
import { IAmount, IRateplan, IUser } from 'typings';
import { CartItem, PurchaseInfoInput, Rateplan } from 'typings/graphql';

const locales = {
  'is-IS': is,
};

interface IOpts {
  showZero?: boolean;
  showDecimals?: boolean;
  monthly?: boolean;
  unit?: string;
}

export function formatPrice(
  price: number,
  opts: IOpts = { showZero: true, showDecimals: false, monthly: false },
) {
  if (!price || price === 0) {
    return get(opts, 'showZero')
      ? `0 kr.${
          get(opts, 'monthly') ? ` ${get(opts, 'unit') ? `/ ${get(opts, 'unit')}` : '/ mán'}` : ''
        }`
      : '—';
  }

  const isMinus = price < 0;
  const decimal = opts.showDecimals ? 2 : 0;

  return `${isMinus ? '-' : ''}${price
    .toFixed(decimal)
    .replace('.', ',')
    .replace('-', '')
    .replace(/./g, (c, i, a) => (i && c !== ',' && (a.length - i) % 3 === 0 ? `.${c}` : c))} kr.${
    get(opts, 'monthly') ? ` ${get(opts, 'unit') ? `/ ${get(opts, 'unit')}` : '/ mán'}` : ''
  }`;
}

export function formatCardExpiryDate(date: string) {
  // in temoorary use while we figure out how wee will deliver expiry date
  if (date.length === 4 && /^-?\d+$/.test(date)) {
    return `${date.slice(0, 2)}/${date.slice(2, 4)}`;
  } else return date;
}

export function isCompany(ssn: string) {
  const firstDigit = parseInt(ssn[0], 10);
  return !isNaN(firstDigit) && firstDigit > 3;
}

export function isStringPhoneNumber(testString: string) {
  const phoneRegex = /^(\d{3})?[-.●]?(\d{3})?[-.●]?(\d{4})$/;
  return phoneRegex.test(testString);
}

export function formatNumber(number: number) {
  const isMinus = number < 0;

  return `${isMinus ? '-' : ''}${number
    .toFixed(0)
    .replace('.', ',')
    .replace('-', '')
    .replace(/./g, (c, i, a) => (i && c !== ',' && (a.length - i) % 3 === 0 ? `.${c}` : c))}`;
}

export function formatPhone(phone: string) {
  if (!phone) {
    return '—';
  }
  return phone.replace('-', '').replace(/^(.{3})(.*)$/, '$1 $2');
}

export function formatTel(number: string) {
  if (!number || isNaN(parseInt(number, 10)) || number.length !== 7) {
    return number;
  }

  return `${number.slice(0, 3)} ${number.slice(3)}`;
}
/**
 * Date-fns format localized to is-IS
 * @param date
 * @param formatString
 */
export function formatDate(date: Date, formatString: string) {
  const dateItem = date instanceof Date ? date : new Date(date);

  return format(dateItem, formatString, {
    locale: locales['is-IS'],
  });
}

export function formatAmount(num: number) {
  return num
    .toString()
    .replace('.', ',')
    .replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1.');
}

export function capitalize(str: string) {
  return str.length > 0 ? str.charAt(0).toUpperCase() + str.slice(1) : str;
}

export function mockGenerator(id: string) {
  if (id == '23cf25c9-119a-4000-9062-3d8f334035b0') {
    return {
      name: 'Björgvin',
      service: 'AlltSaman',
      pack: 'Meira',
      color: 'orange',
      price: '19.900 kr.',
      icon: 'alltSaman',
    };
  }
  if (id == '967af583-924a-4291-ab53-8241857d734c') {
    return {
      name: 'Unnur',
      service: 'Ljósleiðari',
      pack: '500 GB',
      color: 'purple',
      price: '11.790 kr.',
      icon: 'internet',
    };
  }
  if (id == 'bd36c2a5-8c47-4580-9bea-8c4bdc89e93a') {
    return {
      name: 'Andrea',
      service: 'Frelsi',
      pack: '10 GB',
      color: 'pink',
      price: '2.490 kr.',
      icon: 'mobileStar',
    };
  }
  if (id == 'dc1343ce-0e25-4c1f-9178-c354f332893f') {
    return {
      name: 'Ástþór',
      service: 'Áskrift',
      pack: '100 GB',
      color: 'ocean',
      price: '3.990 kr.',
      icon: 'mobilePlus',
    };
  }
  if (id == '9c39ba3b-2d49-471a-c2d0-08dab34e9570') {
    return {
      name: 'Sigurjón',
      service: 'Áskrift',
      pack: '150 GB',
      color: 'ocean',
      price: '6.990 kr.',
      icon: 'mobilePlus',
    };
  }
  if (id == 'cd6fc737-daa3-44ca-c2d1-08dab34e9570') {
    return {
      name: 'Hilma',
      service: 'MínusÁtján',
      pack: '2 GB',
      color: 'pink',
      price: '0 kr.',
      icon: 'bestDeal',
    };
  }
  if (id == 'b29d78bf-37fd-4ce4-c2d2-08dab34e9570') {
    return {
      name: 'Hrafnhildur',
      service: 'Sjálfsvörn',
      pack: 'Íbúð',
      color: 'green',
      price: '3.990 kr.',
      icon: 'lock',
    };
  } else {
    return {
      name: 'Gunnþór',
      service: 'Áskrift',
      pack: '100 GB',
      color: 'ocean',
      price: '3.990 kr.',
      icon: 'mobilePlus',
    };
  }
}

export function pages(totalCount: number, perPage: number) {
  return Math.ceil(totalCount / perPage);
}

export const getMonth = (date: number | Date) => {
  return format(date, 'MMMM', {
    locale: locales['is-IS'],
  });
};

export function getMonths(date: number | Date, count: number) {
  const dateInPast = subMonths(date, count);

  return Array(count + 1)
    .fill(0)
    .map((_, i) => {
      const newdate = addMonths(dateInPast, i);

      return {
        month: format(newdate, 'MMMM', {
          locale: locales['is-IS'],
        }),
        date: newdate,
      };
    });
}

export function formatMillisRemaining(t: number) {
  const cd = 24 * 60 * 60 * 1000;
  const ch = 60 * 60 * 1000;
  const cmon = cd * 30;
  const mon = Math.floor(t / cmon);
  let d = Math.floor(t / cd);
  let h = Math.floor((t - d * cd) / ch);
  let m = Math.round((t - d * cd - h * ch) / 60000);

  if (m === 60) {
    h += 1;
    m = 0;
  }

  if (h === 24) {
    d += 1;
    h = 0;
  }

  if (d > 31) {
    if (mon === 1) {
      return `${mon} mánuður`;
    }
    return `${mon} mánuðir`;
  }

  if (d > 0) {
    if (d === 1) {
      return `${d} dagur`;
    }
    return `${d} dagar`;
  }
  return `${d}d ${h}k ${m}m`;
}

export function objectToQuery(obj: { [key: string]: string }) {
  return Object.keys(obj)
    .map((key) => {
      return `${encodeURIComponent(key)}=${encodeURIComponent(obj[key])}`;
    })
    .join('&');
}

export function formElementsToObject(elements: HTMLCollectionOf<HTMLInputElement>) {
  const obj = {};

  Object.entries(elements).forEach(([_, field]) => {
    const attr: string = get(field, ['dataset', 'key']);

    if (attr !== undefined) {
      if (field.type === 'checkbox') {
        set(obj, attr.split('.'), field.checked);
      } else if (field.type !== 'submit') {
        set(obj, attr.split('.'), field.value);
      }
    }
  });

  return obj;
}

export function queryToObject(query: string) {
  if (query.length < 1) {
    return {};
  }
  const search = query.substring(1);

  return JSON.parse(
    `{"${decodeURI(search).replace(/"/g, '\\"').replace(/&/g, '","').replace(/=/g, '":"')}"}`,
  );
}

export function hasLocalStorage() {
  const test = 'test';

  try {
    localStorage.setItem(test, test);
    localStorage.removeItem(test);
    return true;
  } catch (e) {
    return false;
  }
}

export function diffInDays(dateFrom: Date, dateTo: Date) {
  return differenceInCalendarDays(dateFrom, dateTo);
}

export function profileColor(rateplan: IRateplan | Rateplan) {
  if (rateplan.isVip) {
    return 'viola';
  }
  switch (rateplan.typeId) {
    case 'fiber':
      return 'yellow';
    case 'internet':
      return 'green';
    case 'mobile':
      return rateplan.isPrepaid ? 'pink' : 'ocean';
    case 'service_bundle':
      return 'orange';
    case 'vip_service_bundle':
      return 'dark';
    case 'forwarding':
      return 'purple';
    case 'unregistered':
      return 'pink';
    case 'tv_content_channel':
      return 'pink';
    default:
      return 'ocean';
  }
}

export function connectionColor(type: string) {
  switch (type) {
    case 'Mobile':
      return 'pink';
    case 'Internet':
      return 'yellow';
    case 'CallForwarding':
      return 'purple';
    case 'BackupConnection':
      return 'ocean';
    default:
      return 'ocean';
  }
}

/**
 * @param name String
 * @returns String
 */
export function formatFirstName(name: string) {
  if (name) {
    if (name.includes('TANKAR\\')) {
      return name.split('\\')[1];
    }
    return name.split(' ')[0];
  }
  return '';
}

export function formatName(user: IUser) {
  return formatFirstName(user.name);
}

export function distanceToDate(futureDate: Date, nowDate: Date) {
  return formatDistanceStrict(futureDate, nowDate, {
    locale: locales['is-IS'],
  });
}

export function convertData(remaining: IAmount, included: IAmount) {
  const base = {
    B: 0,
    KB: 1,
    MB: 2,
    GB: 3,
  };
  const r = base[remaining.unit];
  const incl = base[included.unit];
  const diff = Math.abs(incl - r);

  if (diff === 0) {
    return [remaining, included];
  }

  if (r < incl) {
    const remainingResult = remaining.amount / (1024 * diff);

    return [{ amount: remainingResult, unit: included.unit }, included];
  }

  const includedResult = included.amount / (1024 * diff);

  return [remaining, { amount: includedResult, unit: remaining.unit }];
}

export function remainingPercentage(remaining: IAmount, included: IAmount) {
  const base = {
    B: 0,
    KB: 1,
    MB: 2,
    GB: 3,
  };

  if (isEmpty(remaining) || isEmpty(included)) return 0;

  const r = base[remaining.unit];
  const incl = base[included.unit];
  const diff = Math.abs(incl - r);

  if (diff === 0) {
    return (remaining.amount / included.amount) * 100;
  }

  if (r < incl) {
    return (remaining.amount / (included.amount * (1024 * diff))) * 100;
  }

  return ((remaining.amount * (1024 * diff)) / included.amount) * 100;
}

export function scrollToElement(element: string, shouldScrollFromTop?: boolean) {
  const scrollTop = window.pageYOffset || window.scrollY;
  const domElement = typeof element === 'string' ? document.querySelector(element) : element;

  if (!domElement || (!shouldScrollFromTop && domElement.getBoundingClientRect().top > 0)) {
    return;
  }

  const num = domElement.getBoundingClientRect().top + scrollTop;

  return window.scrollTo({
    top: num,
    left: 0,
    behavior: 'smooth',
  });
}

export function signupScroll(element: string, instant?: boolean) {
  const domElement = typeof element === 'string' ? document.querySelector(element) : element;
  if (!domElement) {
    return;
  }

  const rect = domElement.getBoundingClientRect();
  const scrollTop = window.scrollY || document.documentElement.scrollTop;

  // Adjust scroll position relative to current scroll position
  const num = rect.top + scrollTop - (window.innerHeight / 2 - rect.height / 2);

  return window.scrollTo({
    top: num,
    left: 0,
    behavior: instant ? 'instant' : 'smooth',
  });
}
export function getOpportunityColor(category: string) {
  switch (category) {
    case 'vip':
      return 'purple';
    case 'service_bundle':
      return 'orange';
    case 'vip_service_bundle':
      return 'dark';
    case 'watch':
      return 'ocean';
    case 'fiber':
      return 'yellow';
    case 'internet':
      return 'green';
    case 'mobile_prepaid':
      return 'pink';
    case 'mobile_postpaid':
      return 'ocean';
    case 'unregistered':
      return 'pink';
    default:
      return 'ocean';
  }
}

export function stripTypenames(properties: any) {
  if (Array.isArray(properties)) {
    return properties.map(stripTypenames);
  } else if (!isEmpty(properties) && typeof properties === 'object') {
    const newProperties = {};
    for (const property in properties) {
      if (property !== '__typename') {
        newProperties[property] = stripTypenames(properties[property]);
      }
    }
    return newProperties;
  }

  return properties;
}

export const formatNationalId = (nationalId: string): string =>
  `${nationalId.slice(0, 6)} ${nationalId.slice(6)}`;

export const isNationalIdValid = (nationalId: string): boolean => {
  const pattern = /^\d{10}$/;
  return pattern.test(nationalId);
};

export function emailValidate(email: string) {
  return /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/.test(
    email,
  ); //eslint-disable-line
}

export function serializeObject(obj: { [key: string]: string }) {
  const str: Array<string> = [];

  Object.keys(obj).forEach((key) => {
    if (typeof obj[key] !== 'undefined') {
      str.push(`${encodeURIComponent(key)}=${encodeURIComponent(obj[key])}`);
    }
  });
  return str.length > 0 ? `?${str.join('&')}` : '';
}

export function maritalStatusMap(status?: string) {
  switch (status) {
    case 'Unmarried':
      return 'Ógift(ur)';
    case 'IcelanderAbroadMarriedToAForeigner':
      return 'Íslendingur með lögheimili erlendis í hjúskap með útlendingi sem ekki er á skrá';
    case 'LegallySeparated':
      return 'Skilin(n) að borði og sæng';
    case 'IcelanderMarriedToAForeigner':
      return 'Íslendingur í hjúskap með útlendingi';
    case 'MarriedOrRegisteredCohabitation':
      return 'Gift(ur) eða staðfest sambúð';
    case 'Undisclosed':
      return 'Hjón ekki í samvistum';
    case 'MarriedNotCohabitating':
      return 'Hjúskaðarstaða óupplýst';
    case 'DivorcedByLaw':
      return 'Skilin(n) að lögum';
    case 'Widow':
      return 'Ekkja eða ekkill';
    default:
      return 'Óþekkt';
  }
}

export const textColorByBackgroundColor = (backgroundColor: ThemeColorType): ThemeColorType => {
  switch (backgroundColor) {
    case 'grey400':
    case 'grey300':
    case 'grey200':
    case 'grey100':
    case 'ocean':
    case 'white':
    case 'yellow':
      return 'black100';
    default:
      return 'white';
  }
};
export const isSignupMobileReference = (
  referenceItem: CartItem | undefined,
): referenceItem is CartItem & {
  purchaseInfo: {
    contract: { __typename: 'SignupContract' };
    service: { __typename: 'MobileServiceRequest' };
  };
} => {
  return (
    referenceItem?.purchaseInfo?.contract?.__typename === 'SignupContract' &&
    referenceItem?.purchaseInfo?.service?.__typename === 'MobileServiceRequest'
  );
};

export const hasValidPurchaseInfo = (
  serviceItem: { purchaseInfo?: unknown } | undefined,
): serviceItem is { purchaseInfo: PurchaseInfoInput } => {
  return serviceItem?.purchaseInfo !== undefined;
};

export const hasMobileServiceRequest = (
  serviceItem: CartItem | undefined,
): serviceItem is CartItem & {
  purchaseInfo: {
    service: {
      __typename: 'MobileServiceRequest';
      user: unknown;
    };
  };
} => {
  return (
    serviceItem !== undefined &&
    serviceItem.purchaseInfo !== undefined &&
    serviceItem.purchaseInfo !== null &&
    serviceItem.purchaseInfo.service !== undefined &&
    serviceItem.purchaseInfo.service !== null &&
    serviceItem.purchaseInfo.service.__typename === 'MobileServiceRequest' &&
    serviceItem.purchaseInfo.service.user !== undefined
  );
};

export const isEighteenOrOlder = (nationalId: string): boolean => {
  if (!/^\d{10}$/.test(nationalId)) return false;

  const day = parseInt(nationalId.slice(0, 2), 10);
  const month = parseInt(nationalId.slice(2, 4), 10);
  const year = parseInt(nationalId.slice(4, 6), 10);
  const century = parseInt(nationalId[9], 10) === 9 ? 1900 : 2000;
  const birthYear = century + year;

  const birthDate = new Date(birthYear, month - 1, day);
  const today = new Date();
  const age = today.getFullYear() - birthDate.getFullYear();
  const m = today.getMonth() - birthDate.getMonth();
  const d = today.getDate() - birthDate.getDate();

  return age > 18 || (age === 18 && (m > 0 || (m === 0 && d >= 0)));
};
