/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @format
 */

import {remote, ipcRenderer, IpcRendererEvent} from 'electron';
import {toggleAction} from '../reducers/application';
import {
  Group,
  GRAPHQL_ANDROID_GROUP,
  GRAPHQL_IOS_GROUP,
  LITHO_GROUP,
} from '../reducers/supportForm';
import {Store} from '../reducers/index';
import {Logger} from '../fb-interfaces/Logger';
import {parseFlipperPorts} from '../utils/environmentVariables';
import {
  importDataToStore,
  importFileToStore,
  IMPORT_FLIPPER_TRACE_EVENT,
} from '../utils/exportData';
import {tryCatchReportPlatformFailures} from '../utils/metrics';
import {selectPlugin} from '../reducers/connections';
import qs from 'query-string';

export const uriComponents = (url: string): Array<string> => {
  if (!url) {
    return [];
  }
  const match: Array<string> | undefined | null = url.match(
    /^flipper:\/\/([^\/]*)\/([^\/]*)\/?(.*)$/,
  );
  if (match) {
    return match.map(decodeURIComponent).slice(1).filter(Boolean);
  }
  return [];
};

export default (store: Store, _logger: Logger) => {
  const currentWindow = remote.getCurrentWindow();
  currentWindow.on('focus', () => {
    store.dispatch({
      type: 'windowIsFocused',
      payload: {isFocused: true, time: Date.now()},
    });
  });
  currentWindow.on('blur', () => {
    store.dispatch({
      type: 'windowIsFocused',
      payload: {isFocused: false, time: Date.now()},
    });
  });

  // windowIsFocussed is initialized in the store before the app is fully ready.
  // So wait until everything is up and running and then check and set the isFocussed state.
  window.addEventListener('flipper-store-ready', () => {
    const isFocused = currentWindow.isFocused();
    store.dispatch({
      type: 'windowIsFocused',
      payload: {isFocused: isFocused, time: Date.now()},
    });
  });

  ipcRenderer.on(
    'flipper-protocol-handler',
    (_event: IpcRendererEvent, query: string) => {
      const uri = new URL(query);
      if (query.startsWith('flipper://import')) {
        const {search} = new URL(query);
        const {url} = qs.parse(search);
        store.dispatch(toggleAction('downloadingImportData', true));
        return (
          typeof url === 'string' &&
          fetch(url)
            .then((res) => res.text())
            .then((data) => importDataToStore(url, data, store))
            .then(() => {
              store.dispatch(toggleAction('downloadingImportData', false));
            })
            .catch((e: Error) => {
              console.error(e);
              store.dispatch(toggleAction('downloadingImportData', false));
            })
        );
      } else if (
        uri.protocol === 'flipper:' &&
        uri.pathname.includes('support-form')
      ) {
        const formParam = uri.searchParams.get('form');
        const grp = deeplinkFormParamToGroups(formParam);
        if (grp) {
          grp.handleSupportFormDeeplinks(store);
        }
        return;
      }
      const match = uriComponents(query);
      if (match.length > 1) {
        // flipper://<client>/<pluginId>/<payload>
        return store.dispatch(
          selectPlugin({
            selectedApp: match[0],
            selectedPlugin: match[1],
            deepLinkPayload: match[2],
          }),
        );
      }
    },
  );

  function deeplinkFormParamToGroups(formParam: string | null): Group | null {
    if (!formParam) {
      return null;
    }
    if (formParam.toLowerCase() === 'litho') {
      return LITHO_GROUP;
    } else if (formParam.toLowerCase() === 'graphql_android') {
      return GRAPHQL_ANDROID_GROUP;
    } else if (formParam.toLowerCase() === 'graphql_ios') {
      return GRAPHQL_IOS_GROUP;
    }
    return null;
  }

  ipcRenderer.on(
    'open-flipper-file',
    (_event: IpcRendererEvent, url: string) => {
      tryCatchReportPlatformFailures(() => {
        return importFileToStore(url, store);
      }, `${IMPORT_FLIPPER_TRACE_EVENT}:Deeplink`);
    },
  );

  if (process.env.FLIPPER_PORTS) {
    const portOverrides = parseFlipperPorts(process.env.FLIPPER_PORTS);
    if (portOverrides) {
      store.dispatch({
        type: 'SET_SERVER_PORTS',
        payload: portOverrides,
      });
    } else {
      console.error(
        `Ignoring malformed FLIPPER_PORTS env variable:
        "${process.env.FLIPPER_PORTS || ''}".
        Example expected format: "1111,2222".`,
      );
    }
  }
};
