import { createSelector } from 'reselect';

import { getHost } from 'pl-fe/actions/instance';
import { normalizePlFeConfig } from 'pl-fe/normalizers';
import KVStore from 'pl-fe/storage/kv-store';

import { getClient, staticFetch } from '../api';

import type { AppDispatch, RootState } from 'pl-fe/store';
import type { APIEntity } from 'pl-fe/types/entities';

const PLFE_CONFIG_REQUEST_SUCCESS = 'PLFE_CONFIG_REQUEST_SUCCESS' as const;
const PLFE_CONFIG_REQUEST_FAIL = 'PLFE_CONFIG_REQUEST_FAIL' as const;

const PLFE_CONFIG_REMEMBER_SUCCESS = 'PLFE_CONFIG_REMEMBER_SUCCESS' as const;

const getPlFeConfig = createSelector([
  (state: RootState) => state.plfe,
  (state: RootState) => state.auth.client.features,
], (plfe, features) => {
  // Do some additional normalization with the state
  return normalizePlFeConfig(plfe);
});

const rememberPlFeConfig = (host: string | null) =>
  (dispatch: AppDispatch) => {
    return KVStore.getItemOrError(`plfe_config:${host}`).then(plFeConfig => {
      dispatch({ type: PLFE_CONFIG_REMEMBER_SUCCESS, host, plFeConfig });
      return plFeConfig;
    }).catch(() => {});
  };

const fetchFrontendConfigurations = () =>
  (dispatch: AppDispatch, getState: () => RootState) =>
    getClient(getState).instance.getFrontendConfigurations();

/** Conditionally fetches pl-fe config depending on backend features */
const fetchPlFeConfig = (host: string | null) =>
  (dispatch: AppDispatch, getState: () => RootState) => {
    const features = getState().auth.client.features;

    if (features.frontendConfigurations) {
      return dispatch(fetchFrontendConfigurations()).then(data => {
        if (data.pl_fe) {
          dispatch(importPlFeConfig(data.pl_fe, host));
          return data.pl_fe;
        } else {
          return dispatch(fetchPlFeJson(host));
        }
      });
    } else {
      return dispatch(fetchPlFeJson(host));
    }
  };

/** Tries to remember the config from browser storage before fetching it */
const loadPlFeConfig = () =>
  (dispatch: AppDispatch, getState: () => RootState) => {
    const host = getHost(getState());

    return dispatch(rememberPlFeConfig(host)).then(() =>
      dispatch(fetchPlFeConfig(host)),
    );
  };

const fetchPlFeJson = (host: string | null) =>
  (dispatch: AppDispatch) =>
    staticFetch('/instance/pl-fe.json').then(({ json: data }) => {
      if (!isObject(data)) throw 'pl-fe.json failed';
      dispatch(importPlFeConfig(data, host));
      return data;
    }).catch(error => {
      dispatch(plFeConfigFail(error, host));
    });

const importPlFeConfig = (plFeConfig: APIEntity, host: string | null) => {
  if (!plFeConfig.brandColor) {
    plFeConfig.brandColor = '#0482d8';
  }
  return {
    type: PLFE_CONFIG_REQUEST_SUCCESS,
    plFeConfig,
    host,
  };
};

const plFeConfigFail = (error: unknown, host: string | null) => ({
  type: PLFE_CONFIG_REQUEST_FAIL,
  error,
  skipAlert: true,
  host,
});

// https://stackoverflow.com/a/46663081
const isObject = (o: any) => o instanceof Object && o.constructor === Object;

export {
  PLFE_CONFIG_REQUEST_SUCCESS,
  PLFE_CONFIG_REQUEST_FAIL,
  PLFE_CONFIG_REMEMBER_SUCCESS,
  getPlFeConfig,
  rememberPlFeConfig,
  fetchFrontendConfigurations,
  fetchPlFeConfig,
  loadPlFeConfig,
  fetchPlFeJson,
  importPlFeConfig,
  plFeConfigFail,
};
