import React, { Component } from 'react';
import { addLocaleData } from 'react-intl';

import { fromJS } from 'immutable';
import moment from 'moment';

import createReducer from 'lib/reducer';


const defaultCtx = {
    dateFormat: "MM/DD/YYYY",
    timeFormat: "hh:mm",
    
    thousandDelimiter: ",",
    decimalDelimiter: ".",
    decimalDigits: 2,

    currencySymbolLeft: true
};


const space = String.fromCharCode(160);

function formatNum(n, ctx, decimalDigits) {
  //TODO optimize
  if (!ctx) {
    ctx = global.i18n || defaultCtx;
  }
  
  let  
      c = decimalDigits || isNaN(ctx.decimalDigits = Math.abs(ctx.decimalDigits)) ? 2 : ctx.decimalDigits, 
      d = ctx.decimalDelimiter == undefined ? "." : ctx.decimalDelimiter, 
      t = ctx.thousandDelimiter == undefined ? "," : ctx.thousandDelimiter, 
      s = n < 0 ? "-" : "", 
      i = String(parseInt(n = Math.abs(Number(n) || 0).toFixed(c))), 
      j = (j = i.length) > 3 ? j % 3 : 0;
    return s + (j ? i.substr(0, j) + t : "") + i.substr(j).replace(/(\d{3})(?=\d)/g, "$1" + t) + (c ? d + Math.abs(n - i).toFixed(c).slice(2) : "");
}


export function formatDate(date, ctx) {
  if (!ctx) {
    ctx = global.i18n || defaultCtx;
  }

  if (!date) { return null; }
  let format = (ctx && ctx.dateFormat) || undefined;
  return moment(date).format(format);
}


export function formatNumber(n, ctx, decimalDigits) {
  if (!ctx) {
    ctx = global.i18n || defaultCtx;
  }

  return formatNum(n, ctx, decimalDigits);
}


export function formatMoney(n, currency, ctx, decimalDigits) {
  if (!ctx) {
    ctx = global.i18n || defaultCtx;
  }

  n = formatNum(n, ctx, decimalDigits);
  return ctx.currencySymbolLeft ? currency + space + n : n + space + currency;
}


export function formatPercent(n, ctx, decimalDigits) {
  if (!ctx) {
    ctx = global.i18n || defaultCtx;
  }

  n = formatNum(n, ctx && ctx.number, decimalDigits);
  return n + space + "%";
}


function sp(s) {
  return s == " " ? space : s;
}

export function setI18nContext(ctx) {
  if (ctx) {
    ctx = { ...defaultCtx, ...ctx };
    //normalize 
    ctx.decimalDelimiter = sp(ctx.decimalDelimiter);
    ctx.thousandDelimiter = sp(ctx.thousandDelimiter);
  } else {
    ctx = defaultCtx;
  }
  global.i18n = ctx;
}


export function getI18nContext() {
  return global.i18n || defaultCtx;
}


export { injectIntl } from 'react-intl';



async function loadLocaleData(locale) {
    try {
      let data = await System.import(`react-intl/locale-data/${locale}`);
      await addLocaleData(data);

      return true;
    } catch (e) {
      console.error(`Cannot load locale data for locale "${locale}"`, e);
      return false;
    }
}


export async function initI18n(locale, defaultLocaleName = "en") {
  let data = [];

  //fetch locale data
  if (!await loadLocaleData(locale)) {
    locale = defaultLocaleName;
  }

  await loadLocaleData(defaultLocaleName);  
  
  try {
    data.push(await System.import(`translations/${defaultLocaleName}.js`));
  } catch (e) {
      console.error(`Cannot load default messages for locale "${locale}"`, e);
  }

  if (locale != defaultLocaleName) {
    try {
      let localeData = await System.import(`react-intl/locale-data/${locale}`);
      let localeMessages = await System.import(`translations/${locale}.js`);
      data.push(localeMessages);
    } catch (e) {
      console.error(`Cannot load messages for locale "${locale}"`, e);
    }
  }
 
  let 
    msgs,
    msg,
    d;
  let messages = {};
  for (let i = 0; i < data.length; i++) {
    d = data[i];
    if (Array.isArray(d)) {
      //convert array into object
      msgs = {};
      for (let j = 0; j < d.length; j++) {
        msg = d[j];
        messages[msg.id] = msg.defaultMessage;
      }
    } else {
      messages = d;
    }
  }

  return {
    messages,
    defaultLocale: defaultLocaleName,
    locale
  };
}



export const initIntl = initI18n;


//redux
export function createIntlReducer() {
  let reducer = createReducer({});


    reducer.handleAction("@intl/UPDATE_PENDING", (state, action) => { 
      return state.set("loading", true);
    });

    reducer.handleAction("@intl/UPDATE_FULFILLED", (state, action) => { 
      return fromJS(action.payload).set("loading", false);
    });

    reducer.handleAction("@intl/UPDATE_REJECTED", (state, action) => { 
      return state.set("loading", false);
    });


  return reducer.export();
}


//TODO fetch from resources???
export function updateIntl(locale) {
  return {
    type: "@intl/UPDATE",
    payload: initI18n(locale),
    meta: {
      locale
    }
  }
}


export function intlSelector(state) {
  let intl = state.get('intl');
  return intl ? intl.toJS() : {};
}

