import React from 'react';
import './App.css';
import Box from './components/UI/Box/Box';
import Configuration from './containers/Configuration/Configuration';
import {connect} from 'react-redux';
import DependencyList from './components/DependencyList/DependencyList';
import DownloadProgress from './components/DownloadProgress/DownloadProgress';
import ErrorDetails from './components/ErrorDetails/ErrorDetails';
import Grid from './components/UI/Grid/Grid';
import InfoDetails from './components/InfoDetails/InfoDetails';
import IPCContainer from './containers/IPCContainer/IPCContainer';
import Loading from './components/UI/Loading/Loading';
import MountItems from './containers/MountItems/MountItems';
import NewReleases from './components/NewReleases/NewReleases';
import {notifyError} from './redux/actions/error_actions';
import Reboot from './components/Reboot/Reboot';
import {
  setDismissNewReleasesAvailable,
  setNewReleasesAvailable
} from './redux/actions/release_version_actions';
import ReleaseVersionDisplay from './components/ReleaseVersionDisplay/ReleaseVersionDisplay';
import {
  displaySelectAppPlatform,
  saveState
} from './redux/actions/common_actions';
import SelectAppPlatform from './containers/SelectAppPlatform/SelectAppPlatform';
import Text from './components/UI/Text/Text';
import UpgradeIcon from './components/UpgradeIcon/UpgradeIcon';
import UpgradeUI from './components/UpgradeUI/UpgradeUI';
import {
  loadReleases,
  setDismissUIUpgrade
} from './redux/actions/release_version_actions';
import YesNo from './components/YesNo/YesNo';
import {createModalConditionally} from './utils';
import SkynetImport from './containers/SkynetImport/SkynetImport';
import ApplicationBusy from './components/ApplicationBusy/ApplicationBusy';
import SkynetExport from './containers/SkynetExport/SkynetExport';

const Constants = require('./constants');
const Scheduler = require('node-schedule');

class App extends IPCContainer {
  componentDidMount() {
    const detectUpgrades = () => {
      if (this.props.AppPlatform === 'unknown') {
        if (this.props.Platform === 'linux') {
          this.props.displaySelectAppPlatform(true);
        } else {
          this.props.notifyError('Operating system is not supported.', true);
        }
      } else {
        this.props.loadReleases();
      }
    };
    detectUpgrades();
    this.scheduledUpdateJob = Scheduler.scheduleJob('23 11 * * *', detectUpgrades);
  }

  componentDidUpdate(prevProps) {
    if ((prevProps.Release !== this.props.Release) ||
      (prevProps.ReleaseVersion !== this.props.ReleaseVersion) ||
      (prevProps.VersionLookup !== this.props.VersionLookup)) {
      this.props.saveState();
    } else if (Object.keys(this.props.ProviderState).filter(k => {
      return this.props.ProviderState[k] !== prevProps.ProviderState[k];
    }).length > 0) {
      this.props.saveState();
    }
  }

  componentWillUnmount() {
    Scheduler.cancelJob(this.scheduledUpdateJob);
    super.componentWillUnmount();
  }

  getSelectedVersion = () => {
    return (this.props.ReleaseVersion === -1) ?
      'unavailable' :
      this.props.VersionLookup[Constants.RELEASE_TYPES[this.props.Release]][this.props.ReleaseVersion];
  };

  handleUpgradeIconClicked = () => {
    if (this.props.UpgradeAvailable) {
      this.props.setDismissUIUpgrade(false)
    } else if (this.props.NewReleasesAvailable2.length > 0) {
      this.props.setNewReleasesAvailable(this.props.NewReleasesAvailable2);
      this.props.setDismissNewReleasesAvailable(false);
    }
  };

  render() {
    const selectedVersion = this.getSelectedVersion();

    const downloadEnabled = this.props.AllowDownload &&
      !this.props.MountsBusy &&
      !this.props.DownloadActive &&
      (selectedVersion !== 'unavailable') &&
      (selectedVersion !== this.props.InstalledVersion);

    const missingDependencies = (this.props.MissingDependencies.length > 0) &&
      this.props.AllowMount;

    const allowMount = this.props.AllowMount &&
      this.props.InstalledVersion !== 'none' &&
      !missingDependencies &&
      !this.props.InstallActive;

    const remoteSupported = this.props.LocationsLookup[selectedVersion] &&
      this.props.LocationsLookup[selectedVersion].supports_remote;

    let s3Supported = this.props.LocationsLookup[selectedVersion] &&
      this.props.LocationsLookup[selectedVersion].s3_support;
    s3Supported = true;

    const skynetSupported = this.props.LocationsLookup[selectedVersion] &&
      this.props.LocationsLookup[selectedVersion].skynet_support;

    const scPrimeSupported = this.props.LocationsLookup[selectedVersion] &&
      this.props.LocationsLookup[selectedVersion].siaprime_support;

    const siaSupported = Constants.RELEASES_URL.endsWith('releases_1.1.json') || (this.props.LocationsLookup[selectedVersion] &&
      this.props.LocationsLookup[selectedVersion].sia_support);

    const showConfig = !missingDependencies &&
      this.props.DisplayConfiguration &&
      !this.props.RebootRequired;

    const showUpgrade = this.props.UpgradeAvailable &&
      !this.props.DisplayError &&
      !showConfig &&
      !this.props.DownloadActive &&
      !this.props.UpgradeDismissed &&
      !this.props.InstallActive &&
      !this.props.RebootRequired;

    const showDependencies = !showUpgrade &&
      missingDependencies &&
      !this.props.DownloadActive &&
      !this.props.RebootRequired &&
      !this.props.DismissDependencies &&
      this.props.AllowMount;

    const showNewReleases = !showConfig &&
      !this.props.DisplayConfirmYesNo &&
      !showDependencies &&
      !this.props.DownloadActive &&
      !this.props.DisplayError &&
      !this.props.DisplayInfo &&
      !this.props.InstallActive &&
      !this.props.RebootRequired &&
      !this.props.DisplaySelectAppPlatform &&
      !showUpgrade &&
      !this.props.DismissNewReleasesAvailable &&
      (this.props.NewReleasesAvailable.length > 0);

    const showSkynetImport = !showConfig &&
      !showDependencies &&
      !this.props.DownloadActive &&
      !showNewReleases &&
      !this.props.RebootRequired &&
      !this.props.DisplaySelectAppPlatform &&
      !showUpgrade &&
      this.props.DisplayImport;

    const showSkynetExport = !showConfig &&
      !showDependencies &&
      !this.props.DownloadActive &&
      !showNewReleases &&
      !this.props.RebootRequired &&
      !this.props.DisplaySelectAppPlatform &&
      !showUpgrade &&
      this.props.DisplayExport;

    const configDisplay = createModalConditionally(showConfig, <Configuration
      version={selectedVersion}
      s3Supported={s3Supported}
      remoteSupported={remoteSupported}/>);
    const confirmDisplay = createModalConditionally(this.props.DisplayConfirmYesNo, <YesNo/>);
    const dependencyDisplay = createModalConditionally(showDependencies,
      <DependencyList/>, false, this.props.InstallActive);
    const downloadDisplay = createModalConditionally(this.props.DownloadActive,
      <DownloadProgress/>, false, true);
    const errorDisplay = createModalConditionally(this.props.DisplayError, <ErrorDetails/>, true);
    const infoDisplay = createModalConditionally(this.props.DisplayInfo, <InfoDetails/>, true);
    const newReleasesDisplay = createModalConditionally(showNewReleases, <NewReleases/>);
    const rebootDisplay = createModalConditionally(this.props.RebootRequired, <Reboot/>);
    const selectAppPlatformDisplay = createModalConditionally(this.props.DisplaySelectAppPlatform,
      <SelectAppPlatform/>);
    const upgradeDisplay = createModalConditionally(showUpgrade, <UpgradeUI/>);
    const importDisplay = createModalConditionally(showSkynetImport, <SkynetImport
      version={selectedVersion}/>);
    const exportDisplay = createModalConditionally(showSkynetExport, <SkynetExport
      version={selectedVersion}/>)
    const appBusyDisplay = createModalConditionally(this.props.AppBusy,
      <ApplicationBusy/>, false, true, this.props.AppBusyTransparent);

    let mainContent = [];
    if (this.props.DisplaySelectAppPlatform || !this.props.AppReady) {
      mainContent = (
        <Box dxStyle={{height: '100%'}}>
          <Loading/>
        </Box>);
    } else {
      let key = 0;
      mainContent.push((
        <Box key={'md_' + key++}
             dxStyle={{padding: 'var(--default_spacing)', height: 'auto'}}>
          <ReleaseVersionDisplay downloadDisabled={!downloadEnabled}
                                 version={selectedVersion}/>
        </Box>
      ));
      mainContent.push(<div key={'md_' + key++}
                            style={{paddingTop: 'var(--default_spacing)'}}/>);
      if (allowMount) {
        mainContent.push((
          <Box dxStyle={{padding: 'var(--default_spacing)', height: 'auto'}}
               key={'md_' + key++}>
            <MountItems s3Supported={s3Supported}
                        remoteSupported={remoteSupported}
                        scPrimeSupported={scPrimeSupported}
                        siaSupported={siaSupported}
                        skynetSupported={skynetSupported}/>
          </Box>
        ));
      } else if (selectedVersion !== 'unavailable') {
        mainContent.push((
          <Box dxStyle={{padding: 'var(--default_spacing)', height: '170px'}}
               key={'md_' + key++}>
            <Loading/>
          </Box>
        ));
      }
    }

    return (
      <div className={'App'}>
        <div className={'AppContainer'}>
          <div className={'AppHeader'}>
            <Box>
              <Grid>
                <Text col={0}
                      colSpan={'remain'}
                      row={0}
                      rowSpan={'remain'}
                      text={'Repertory UI v' + this.props.Version}
                      textAlign={'center'}
                      type={'Heading1'}/>
                <UpgradeIcon
                  available={this.props.UpgradeAvailable || (this.props.NewReleasesAvailable2.length > 0)}
                  newReleases={!this.props.UpgradeAvailable && (this.props.NewReleasesAvailable2.length > 0)}
                  clicked={this.handleUpgradeIconClicked}
                  col={dimensions => dimensions.columns - 6}
                  colSpan={5}
                  row={1}
                  rowSpan={remain => remain - 1}/>
              </Grid>
            </Box>
          </div>
          <div className={'AppContent'}>
            {mainContent}
          </div>
        </div>
        {importDisplay}
        {exportDisplay}
        {newReleasesDisplay}
        {selectAppPlatformDisplay}
        {dependencyDisplay}
        {upgradeDisplay}
        {configDisplay}
        {infoDisplay}
        {confirmDisplay}
        {downloadDisplay}
        {rebootDisplay}
        {appBusyDisplay}
        {errorDisplay}
      </div>
    );
  }
}

const mapStateToProps = state => {
  return {
    AllowDownload: state.download.AllowDownload,
    AllowMount: state.common.AllowMount,
    AppPlatform: state.common.AppPlatform,
    AppBusy: state.common.AppBusy,
    AppBusyTransparent: state.common.AppBusyTransparent,
    AppReady: state.common.AppReady,
    DismissDependencies: state.install.DismissDependencies,
    DisplayConfiguration: state.mounts.DisplayConfiguration,
    DisplayConfirmYesNo: state.common.DisplayConfirmYesNo,
    DisplayError: state.error.DisplayError,
    DisplayExport: state.skynet.DisplayExport,
    DisplayImport: state.skynet.DisplayImport,
    DisplayInfo: state.error.DisplayInfo,
    DisplaySelectAppPlatform: state.common.DisplaySelectAppPlatform,
    DismissNewReleasesAvailable: state.relver.DismissNewReleasesAvailable,
    DownloadActive: state.download.DownloadActive,
    InstallActive: state.install.InstallActive,
    InstalledVersion: state.relver.InstalledVersion,
    LocationsLookup: state.relver.LocationsLookup,
    MissingDependencies: state.install.MissingDependencies,
    MountsBusy: state.mounts.MountsBusy,
    NewReleasesAvailable: state.relver.NewReleasesAvailable,
    NewReleasesAvailable2: state.relver.NewReleasesAvailable2,
    Platform: state.common.Platform,
    ProviderState: state.mounts.ProviderState,
    RebootRequired: state.common.RebootRequired,
    Release: state.relver.Release,
    ReleaseVersion: state.relver.Version,
    UpgradeAvailable: state.relver.UpgradeAvailable,
    UpgradeDismissed: state.relver.UpgradeDismissed,
    Version: state.common.Version,
    VersionLookup: state.relver.VersionLookup,
  };
};

const mapDispatchToProps = dispatch => {
  return {
    displaySelectAppPlatform: display => dispatch(displaySelectAppPlatform(display)),
    loadReleases: () => dispatch(loadReleases()),
    notifyError: (msg, critical, callback) => dispatch(notifyError(msg, critical, callback)),
    saveState: () => dispatch(saveState()),
    setDismissNewReleasesAvailable: dismiss => dispatch(setDismissNewReleasesAvailable(dismiss)),
    setNewReleasesAvailable: items => dispatch(setNewReleasesAvailable(items)),
    setDismissUIUpgrade: dismiss => dispatch(setDismissUIUpgrade(dismiss)),
  };
};

export default connect(mapStateToProps, mapDispatchToProps)(App);
