import React from 'react';
import './App.css';
import AddEditHost from './containers/AddEditHost/AddEditHost';
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.jsx';
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.jsx';
import SkynetImport from './containers/SkynetImport/SkynetImport';
import ApplicationBusy from './components/ApplicationBusy/ApplicationBusy';
import SkynetExport from './containers/SkynetExport/SkynetExport';
import PinnedManager from './containers/PinnedManager/PinnedManager';

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

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.schedule('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() {
    this.scheduledUpdateJob.stop();
    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;

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

    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 =
      this.props.LocationsLookup[selectedVersion] &&
      this.props.LocationsLookup[selectedVersion].sia_support;

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

    const showPinnedManager =
      !missingDependencies &&
      !this.props.RebootRequired &&
      this.props.DisplayPinnedManager;

    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 showAddEditHost =
      !showDependencies &&
      !this.props.DownloadActive &&
      !showNewReleases &&
      !this.props.RebootRequired &&
      !this.props.DisplaySelectAppPlatform &&
      !showUpgrade &&
      this.props.DisplayAddEditHost;

    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 addEditHostDisplay = createModalConditionally(
      showAddEditHost,
      <AddEditHost />
    );
    const pinnedManagerDisplay = createModalConditionally(
      showPinnedManager,
      <PinnedManager version={selectedVersion} />
    );
    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 col={0} colSpan={'remain'} row={0} rowSpan={'remain'}>
          <Loading />
        </Box>
      );
    } else {
      let key = 0;
      mainContent.push(
        <Box
          col={0}
          colSpan={'remain'}
          row={10}
          rowSpan={'17'}
          key={'md_' + key++}
          dxStyle={{ padding: 'var(--default_spacing)' }}>
          <ReleaseVersionDisplay
            downloadDisabled={!downloadEnabled}
            version={selectedVersion}
          />
        </Box>
      );
      if (allowMount) {
        mainContent.push(
          <Box
            row={29}
            rowSpan={'remain'}
            colSpan={'remain'}
            dxStyle={{ padding: 'var(--default_spacing)' }}
            key={'md_' + key++}>
            <MountItems
              s3Supported={s3Supported}
              remoteSupported={remoteSupported}
              scPrimeSupported={scPrimeSupported}
              siaSupported={siaSupported}
              skynetSupported={skynetSupported}
            />
          </Box>
        );
      } else if (!downloadEnabled && selectedVersion !== 'unavailable') {
        mainContent.push(
          <Box
            col={0}
            colSpan={'remain'}
            row={0}
            rowSpan={'remain'}
            dxStyle={{ padding: 'var(--default_spacing)' }}
            key={'md_' + key++}>
            <Loading />
          </Box>
        );
      }
    }

    return (
      <div className={'App'}>
        <Grid>
          <Box col={0} colSpan={'remain'} row={0} rowSpan={8}>
            <Grid noScroll>
              <Text
                col={0}
                colSpan={'remain'}
                row={0}
                rowSpan={8}
                text={'Repertory UI v' + this.props.Version}
                textAlign={'center'}
                type={'Heading1'}
              />
              <UpgradeIcon
                available={
                  !missingDependencies &&
                  (this.props.UpgradeAvailable ||
                    this.props.NewReleasesAvailable2.length > 0)
                }
                newReleases={
                  !missingDependencies &&
                  !this.props.UpgradeAvailable &&
                  this.props.NewReleasesAvailable2.length > 0
                }
                clicked={this.handleUpgradeIconClicked}
                col={(dimensions) => dimensions.columns - 6}
                colSpan={1}
                row={1}
                rowSpan={(remain) => remain - 1}
              />
            </Grid>
          </Box>
          {mainContent}
        </Grid>
        {importDisplay}
        {exportDisplay}
        {newReleasesDisplay}
        {selectAppPlatformDisplay}
        {dependencyDisplay}
        {upgradeDisplay}
        {pinnedManagerDisplay}
        {configDisplay}
        {addEditHostDisplay}
        {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,
    DisplayAddEditHost: state.host.DisplayAddEditHost,
    DisplayConfiguration: state.mounts.DisplayConfiguration,
    DisplayConfirmYesNo: state.common.DisplayConfirmYesNo,
    DisplayError: state.error.DisplayError,
    DisplayExport: state.skynet.DisplayExport,
    DisplayImport: state.skynet.DisplayImport,
    DisplayInfo: state.error.DisplayInfo,
    DisplayPinnedManager: state.pinned.DisplayPinnedManager,
    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);
