import { DateTime } from 'luxon';
import ITFSettings from '../ITFSettings';

export function parseHours (str, { hoursInDay } = { hoursInDay: 8 }) {
  let source = (str || '').toString();
  const isNegative = str[0] === '-' ? -1 : 1;
  source = source.replace('-', '');

  const SECONDS_IN_MINUTE = 60;
  const MINUTES_IN_HOUR = 60;
  // try parse decimal
  const matchDecimal = source.match(/^(\d+([.,]\d+)?)$/);
  if (matchDecimal) {
    return isNegative * Math.round(parseFloat(source.replace(',', '.')) * MINUTES_IN_HOUR * SECONDS_IN_MINUTE);
  }

  const match = source.match(/^((\d+)d)?\s*((\d+)h)?\s*((\d+)m)?\s*((\d+)s)?$/);
  if (!match) {
    return false;
  }
  const [,, days,, hours,, minutes,,secs] = match;

  let seconds = 0;
  if (days) {
    seconds += hoursInDay * Number(days) * MINUTES_IN_HOUR * SECONDS_IN_MINUTE;
  }
  if (hours) {
    seconds += Number(hours) * MINUTES_IN_HOUR * SECONDS_IN_MINUTE;
  }
  if (minutes) {
    seconds += Number(minutes) * SECONDS_IN_MINUTE;
  }
  if (secs) {
    seconds += Number(secs);
  }
  return isNegative * seconds;
}

export function formatFinanceMoney (val, symbol = '', digits = 2, showNegative = true) {
  if (isNaN(val) || val === null || val === undefined) {
    return '—';
  }
  if (typeof symbol !== 'string' && symbol !== null && typeof symbol !== 'undefined') {
    if (symbol.IsCryptoCurrency && digits === 2 && Math.abs(val) < 0.01) {
      digits = 6;
    }
    symbol = symbol.Symbol; // in case of passing object of currency
  }
  const isNegative = showNegative && (val < 0);
  return (isNegative ? '(' : '') + formatMoney(Math.abs(val), symbol, digits) + (isNegative ? ')' : '');
}

// https://stptrans.com/wp-content/uploads/2020/02/Working-with-currency-number-and-date-formats.pdf
export function formatMoney (val, symbol = '', digits = null) {
  const format = ITFSettings.moneyDisplayFormat || '{symbol}{value}';
  const thousandSeparator = ITFSettings.moneyThousandSeparator || ',';
  const decimalSeparator = ITFSettings.moneyDecimalSeparator || '.';

  if (Number.isNaN(val) || val === null || val === undefined) {
    return '—';
  }
  let symbolStr = symbol?.currencySymbol ?? symbol?.symbol ?? symbol?.Symbol ?? '';
  if (typeof symbol === 'string') {
    symbolStr = symbol;
  }
  if (digits === null) {
    digits = symbol?.precision ?? symbol?.currencyPrecision ?? symbol?.Precision ?? 2;
  }
  const value = parseFloat(val.toString()).toFixed(digits)
    .replace(/\d(?=(\d{3})+\.)/g, '$&' + thousandSeparator)
    .replace(/\.(\d+)$/, decimalSeparator + '$1')
  ;
  return format
    .replace('{value}', value)
    .replace('{symbol}', symbolStr)
    .trim();
}

export function formatDate (date, inputFormat = 'yyyy-MM-dd', toFormat) {
  if (!date) {
    return date;
  }
  return DateTime.fromFormat(date, inputFormat).toFormat(toFormat || ITFSettings.defaultDisplayDateFormat);
}

export function formatRangeDates(begin, end = null) {
  const DATE_FULL_FORMAT = 'dd MMM yyyy';
  const DATE_SHORT_FORMAT = 'dd MMM';
  const DAY_FORMAT = 'dd';

  const weekStart = DateTime.fromJSDate(begin);
  if (!begin) {
    return null;
  }
  if (!end) {
    return `${weekStart.toFormat(DATE_FULL_FORMAT)} - &infin;`;
  }
  const weekEnd = DateTime.fromJSDate(end);
  if (!weekStart.hasSame(weekEnd, 'year')) {
    return `${weekStart.toFormat(DATE_FULL_FORMAT)} - ${weekEnd.toFormat(DATE_FULL_FORMAT)}`;
  }
  if (!weekStart.hasSame(weekEnd, 'month')) {
    return `${weekStart.toFormat(DATE_SHORT_FORMAT)} - ${weekEnd.toFormat(DATE_FULL_FORMAT)}`;
  }
  if (!weekStart.hasSame(weekEnd, 'day')) {
    return `${weekStart.toFormat(DAY_FORMAT)} - ${weekEnd.toFormat(DATE_FULL_FORMAT)}`;
  }
  return `${weekStart.toFormat(DATE_FULL_FORMAT)}`;
}

export function firstLetters(name) {
  let [first, second] = (name || '').trim()
    .replace(/[\u0250-\u0400\u04FF-\ue007]/g, '')
    .replace(/[ \.,_!@#$%^&*()«»]+/g, ' ')
    .split(' ');

  if (first === 'undefined') {
    first = '';
  }
  if (second === 'undefined') {
    second = '';
  }
  if (!second) {
    return (first[0] || '').toUpperCase();
  }
  return ((first[0] || '') + (second[0] || '')).toUpperCase();
}

export function formatHours (val, removeEmptyMinutes = false) {
  let hours = Math.floor(Math.abs(val) / 60);
  let minutes = Math.abs(val) - hours * 60;
  if (Number.isNaN(minutes)) {
    return '—';
  }
  minutes = Math.floor(minutes);
  if (!removeEmptyMinutes) {
    if (minutes < 10) {
      minutes = '0' + minutes;
    }
    minutes = ` ${minutes}m`;
  } else {
    minutes = '';
  }
  const sign = val < 0 ? '-' : '';
  if (!hours) {
    return `${sign}0h${minutes}`;
  }
  if (hours < 10) {
    hours = '0' + hours;
  }
  return `${sign}${hours}h${minutes}`;
}


/**
 * Округлює число до заданої точності
 *
 * @param number Вхідне число
 * @param digits Кількість знаків після коми
 * @param ceil99 якщо число закінчується на .99, то додає .01 щоб воно було кругле
 * @returns {number}
 */
export function round (number, digits = 2, ceil99 = false) {
  const pow = 10 ** digits;
  let res = Math.round((number + Number.EPSILON) * pow) / pow;
  if (ceil99) {
    const str = res.toFixed(2);
    if (str.substring(str.length - 3) === '.99') {
      res += 0.01;
    }
  }
  return res;
}


export function stringToNumber(str) {
  const formated = (str || '').toString().replace(/[,.](\d+)$/g, '^$1').replace(/[,.\s]/g, '').replace('^', '.');
  return parseFloat(formated);
}

