import * as Constants from '../../constants';
import {createAction} from '@reduxjs/toolkit';
import {
  getIPCRenderer,
  getSelectedVersionFromState
} from '../../utils';
import {notifyError} from './error_actions';
import {downloadItem, setAllowDownload} from './download_actions';
import {
  loadReleases,
  setActiveRelease,
  setInstalledVersion,
  setReleaseUpgradeAvailable,
  setNewReleasesAvailable2,
} from './release_version_actions';
import {
  confirmYesNo,
  displaySelectAppPlatform,
  setAllowMount,
  setApplicationReady,
  setLinuxAppPlatform,
  setRebootRequired,
  showWindow,
  shutdownApplication
} from './common_actions';
import {unmountAll} from './mount_actions';

const ipcRenderer = getIPCRenderer();

export const checkInstalled = (dependencies, version) => {
  return (dispatch, getState) => {
    const checkInstalledComplete = (event, arg) => {
      const result = arg.data;
      const updateState = () => {
        const installedVersion = result.Success && result.Exists ? result.Version : 'none';
        const state = getState();

        const release = state.relver.Release;
        let version = state.relver.Version;

        let upgradeAvailable = false;
        if (installedVersion !== 'none') {
          const latestVersion = state.relver.VersionLookup[Constants.RELEASE_TYPES[release]].length - 1;
          if (version === -1) {
            version = latestVersion;
            dispatch(setActiveRelease(release, version));
          } else {
            upgradeAvailable = version !== latestVersion;
          }
        }
        dispatch(setInstalledVersion(installedVersion));
        dispatch(setReleaseUpgradeAvailable(upgradeAvailable));
        dispatch(setMissingDependencies(result.Dependencies));
        dispatch(setAllowDownload(true));
        dispatch(setAllowMount(true));

        const autoInstallRelease = getState().install.AutoInstallRelease;
        dispatch(setAutoInstallRelease(false));

        if (result.Dependencies && (result.Dependencies.length > 0)) {
          dispatch(showWindow());
        } else if ((installedVersion === 'none') && autoInstallRelease) {
          dispatch(setAllowMount(false));
          const versionString = getState().relver.VersionLookup[Constants.RELEASE_TYPES[release]][version];
          const urls = getState().relver.LocationsLookup[versionString].urls;
          const fileName = versionString + '.zip';
          dispatch(downloadItem(fileName, Constants.INSTALL_TYPES.Release, urls));
        }
      };

      if (result.Success) {
        updateState();
      } else {
        dispatch(notifyError(result.Error, false, updateState));
      }
    };

    ipcRenderer.once(Constants.IPC_Check_Installed_Reply, checkInstalledComplete);
    ipcRenderer.send(Constants.IPC_Check_Installed, {
      Dependencies: dependencies,
      Version: version,
    });
  };
};

export const checkVersionInstalled = () => {
  return (dispatch, getState) => {
    const state = getState();

    dispatch(setAllowDownload(false));
    const selectedVersion = getSelectedVersionFromState(state);
    if (selectedVersion && (selectedVersion !== 'unavailable')) {
      let dependencies = [];
      if (state.relver.LocationsLookup[selectedVersion] && state.relver.LocationsLookup[selectedVersion].dependencies) {
        dependencies = state.relver.LocationsLookup[selectedVersion].dependencies;
      }
      dispatch(checkInstalled(dependencies, selectedVersion));
    } else {
      dispatch(setInstalledVersion('none'));
      dispatch(setAllowDownload(true));
    }
  };
};

export const installDependency = (source, url, isWinFSP) => {
  return (dispatch, getState) => {
    if (ipcRenderer && !getState().install.InstallActive) {
      dispatch(setInstallActive(Constants.INSTALL_TYPES.Dependency));

      const installDependencyComplete = (event, arg) => {
        const result = arg.data;
        const handleCompleted = ()=> {
          if (result.RebootRequired) {
            dispatch(setRebootRequired());
          } else {
            ipcRenderer.send(Constants.IPC_Delete_File, {
              FilePath: source,
            });
            dispatch(setInstallComplete(result));
            dispatch(checkVersionInstalled());
          }
        };

        if (result.Success && source.toLowerCase().endsWith('.dmg')) {
          const dep = getState().install.MissingDependencies.find(d => {
            return d.download === url;
          });
          const i = setInterval(()=> {
            const ret = ipcRenderer.sendSync(Constants.IPC_Check_Dependency_Installed + '_sync', {
              File: dep.file,
            });

            if (ret.data.Exists) {
              clearInterval(i);
              setTimeout(() => {
                handleCompleted();
              }, 5000);
            }
          }, 3000);
        } else {
          handleCompleted();
        }
      };

      ipcRenderer.once(Constants.IPC_Install_Dependency_Reply, installDependencyComplete);
      ipcRenderer.send(Constants.IPC_Install_Dependency, {
        Source: source,
        URL: url,
        IsWinFSP: isWinFSP,
      });
    }
  };
};

export const installAndTestRelease = (source, version, appPlatform) => {
  return (dispatch, getState) => {
    if (ipcRenderer && getState().install.InstallTestActive) {
      const extractReleaseComplete = () => {
        ipcRenderer.send(Constants.IPC_Delete_File, {
          FilePath: source,
        });

        ipcRenderer.once(Constants.IPC_Test_Release_Reply, (event, arg) => {
          if (arg.data.Success) {
            ipcRenderer.sendSync(Constants.IPC_Set_Linux_AppPlatform, {
              AppPlatform: appPlatform,
            });
            dispatch(setLinuxAppPlatform(appPlatform));
            dispatch(setInstallTestActive(false));
            dispatch(displaySelectAppPlatform(false));
            dispatch(setAllowDownload(false));
            dispatch(loadReleases());
          } else {
            dispatch(notifyError(arg.data.Error));
            dispatch(setInstallTestActive(false));
          }
        });
        ipcRenderer.send(Constants.IPC_Test_Release, {
          Version: version,
        })
      };

      ipcRenderer.once(Constants.IPC_Extract_Release_Complete, extractReleaseComplete);
      ipcRenderer.send(Constants.IPC_Extract_Release, {
        Source: source,
        Version: version,
      });
    }
  };
};

export const installReleaseByVersion = (release, version) => {
  return (dispatch, getState) => {
    const install = () => {
      if (getState().download.AllowDownload && !getState().download.DownloadActive) {
        dispatch(setAutoInstallRelease(true));
        dispatch(setActiveRelease(release, version));
      } else {
        notifyError('Download is active. Unable to install release.');
      }
    };

    if (getState().mounts.MountsBusy) {
      dispatch(confirmYesNo('Unmount all drives?'))
        .then(confirmed => {
          if (confirmed) {
            dispatch(unmountAll(install));
          }
        })
        .catch(error => notifyError(error));
    } else {
      install();
    }
  };
};

export const installRelease = source => {
  return (dispatch, getState) => {
    if (ipcRenderer && !getState().install.InstallActive) {
      dispatch(setInstallActive(Constants.INSTALL_TYPES.Release));

      const version = getSelectedVersionFromState(getState());
      const extractReleaseComplete = (event, arg) => {
        ipcRenderer.send(Constants.IPC_Delete_File, {
          FilePath: source,
        });

        if (arg.data.Success) {
          localStorage.setItem('previous_releases', localStorage.getItem('releases'));
          dispatch(setNewReleasesAvailable2([]));
        }

        dispatch(setInstallComplete(arg.data));
        dispatch(checkVersionInstalled());
      };

      ipcRenderer.once(Constants.IPC_Extract_Release_Complete, extractReleaseComplete);
      ipcRenderer.send(Constants.IPC_Extract_Release, {
        Source: source,
        Version: version,
      });
    }
  };
};

export const installUpgrade = (source, sha256, signature, skipVerification) => {
  return (dispatch, getState) => {
    if (ipcRenderer && !getState().install.InstallActive) {
      dispatch(setInstallActive(Constants.INSTALL_TYPES.Upgrade));
      dispatch(setApplicationReady(false));

      const installUpgradeComplete = (event, arg) => {
        const result = arg.data;
        if (result.Success) {
          dispatch(shutdownApplication());
        } else {
          dispatch(setApplicationReady(true));
          dispatch(setInstallComplete(result));
          dispatch(notifyError(result.Error, false, () => {
            // TODO Prompt to verify
            if (result.AllowSkipVerification) {
              dispatch(installUpgrade(source, sha256, signature, true));
            }
          }, false));
        }
      };

      ipcRenderer.once(Constants.IPC_Install_Upgrade_Reply, installUpgradeComplete);
      ipcRenderer.send(Constants.IPC_Install_Upgrade, {
        Sha256: sha256,
        Signature: signature,
        SkipVerification: skipVerification,
        Source: source,
      });
    }
  };
};

export const setAutoInstallRelease = createAction('install/setAutoInstallRelease');
export const setDismissDependencies = createAction('install/setDismissDependencies');
export const setInstallActive = createAction('install/setInstallActive');
export const setInstallTestActive = createAction('install/setInstallTestActive');
export const setInstallComplete = createAction('install/setInstallComplete');
export const setMissingDependencies = createAction('install/setMissingDependencies');
