/*
 *  Copyright ETH 2023 Zürich, Scientific IT Services
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 */

import React from 'react'
import ResizeObserver from 'rc-resize-observer'
import Button from '@material-ui/core/Button'
import CreateNewFolderIcon from '@material-ui/icons/CreateNewFolderOutlined'
import DownloadIcon from '@material-ui/icons/GetApp'
import DeleteIcon from '@material-ui/icons/Delete'
import RenameIcon from '@material-ui/icons/Create'
import CopyIcon from '@material-ui/icons/FileCopy'
import MoveIcon from '@material-ui/icons/ArrowRightAlt'
import MoreIcon from '@material-ui/icons/MoreVert'
import messages from '@src/js/common/messages.js'
import { withStyles } from '@material-ui/core/styles'
import logger from '@src/js/common/logger.js'
import autoBind from 'auto-bind'
import IconButton from '@material-ui/core/IconButton'
import { debounce } from '@material-ui/core'
import Container from '@src/js/components/common/form/Container.jsx'
import Popover from '@material-ui/core/Popover'
import InputDialog from '@src/js/components/common/dialog/InputDialog.jsx'
import ConfirmationDialog from '@src/js/components/common/dialog/ConfirmationDialog.jsx'
import LocationDialog from '@src/js/components/database/data-browser/LocationDialog.jsx'
import LoadingDialog from '@src/js/components/common/loading/LoadingDialog.jsx'

const color = 'default'
const iconButtonSize = 'medium'
const moveLocationMode = 'move'
const copyLocationMode = 'copy'

const styles = theme => ({
  buttons: {
    flex: '1 1 auto',
    display: 'flex',
    alignItems: 'center',
    whiteSpace: 'nowrap',
    overflow: 'hidden',
    '&>button': {
      marginRight: theme.spacing(1)
    },
    '&>button:nth-last-child(1)': {
      marginRight: 0
    }
  },
  toggleButton: {},
  collapsedButtonsContainer: {
    display: 'flex',
    flexDirection: 'column',
    '&>button': {
      marginBottom: theme.spacing(1)
    },
    '&>button:nth-last-child(1)': {
      marginBottom: 0
    }
  },
})

class LeftToolbar extends React.Component {

  constructor(props, context) {
    super(props, context)
    autoBind(this)

    this.state = {
      width: 0,
      hiddenButtonsPopup: null,
      newFolderDialogOpen: false,
      deleteDialogOpen: false,
      renameDialogOpen: false,
      locationDialogMode: null,
      loading: false
    }

    this.controller = this.props.controller
    this.onResize = debounce(this.onResize, 1)
  }

  async handleNewFolderCreate(folderName) {
    this.closeNewFolderDialog()
    await this.controller.createNewFolder(folderName)
  }

  handleNewFolderCancel() {
    this.closeNewFolderDialog()
  }

  openNewFolderDialog() {
    this.setState({ newFolderDialogOpen: true })
  }

  closeNewFolderDialog() {
    this.setState({ newFolderDialogOpen: false })
  }

  openDeleteDialog() {
    this.setState({ deleteDialogOpen: true })
  }

  closeDeleteDialog() {
    this.setState({ deleteDialogOpen: false })
  }

  openRenameDialog() {
    this.setState({ renameDialogOpen: true })
  }

  closeRenameDialog() {
    this.setState({ renameDialogOpen: false })
  }

  async handleRenameConfirm(newName) {
    const { multiselectedFiles } = this.props
    const oldName = multiselectedFiles.values().next().value.name
    this.closeRenameDialog()

    try {
      this.setState({ loading: true })
      await this.controller.rename(oldName, newName)
    } finally {
      this.setState({ loading: false })
    }
  }

  handleRenameCancel() {
    this.closeRenameDialog()
  }

  openMoveLocationDialog() {
    this.setState({ locationDialogMode: moveLocationMode })
  }

  openCopyLocationDialog() {
    this.setState({ locationDialogMode: copyLocationMode })
  }

  closeLocationDialog() {
    this.setState({ locationDialogMode: null })
  }

  async handleLocationConfirm(newPath) {
    const { multiselectedFiles } = this.props
    const { locationDialogMode} = this.state
    this.closeLocationDialog()

    try {
      this.setState({ loading: true })
      if (locationDialogMode === moveLocationMode) {
        await this.controller.move(multiselectedFiles, newPath)
      } else {
        await this.controller.copy(multiselectedFiles, newPath)
      }
    } finally {
      this.setState({ loading: false })
    }
  }

  handleLocationCancel() {
    this.closeLocationDialog()
  }

  async handleDeleteConfirm() {
    const { multiselectedFiles } = this.props

    this.closeDeleteDialog()
    await this.controller.delete(multiselectedFiles)
  }

  handleDeleteCancel() {
    this.closeDeleteDialog()
  }

  async handleDownload() {
    const { multiselectedFiles } = this.props
    const file = multiselectedFiles.values().next().value;

    try {
      this.setState({ loading: true })

      const dataArray = await this.controller.download(file)
      const blob = new Blob(dataArray, { type: "application/octet-stream" })
      const link = document.createElement('a')
      link.href = window.URL.createObjectURL(blob)
      link.download = file.name
      link.click()
    }  finally {
      this.setState({ loading: false })
    }
  }

  renderNoSelectionContextToolbar() {
    const { classes, buttonSize } = this.props
    return ([
      <Button
        key='new-folder'
        classes={{ root: classes.button }}
        color={color}
        size={buttonSize}
        variant='outlined'
        startIcon={<CreateNewFolderIcon />}
        onClick={this.openNewFolderDialog}
      >
        {messages.get(messages.NEW_FOLDER)}
      </Button>,
      <InputDialog
        key='new-folder-dialog'
        open={this.state.newFolderDialogOpen}
        title={messages.get(messages.NEW_FOLDER)}
        inputLabel={messages.get(messages.FOLDER_NAME)}
        onCancel={this.handleNewFolderCancel}
        onConfirm={this.handleNewFolderCreate}
        />
    ])
  }

  renderSelectionContextToolbar() {
    const {
      classes,
      buttonSize,
      multiselectedFiles,
      datastoreServer,
      sessionToken,
      owner,
      path
    } = this.props
    const {
      width,
      hiddenButtonsPopup,
      deleteDialogOpen,
      renameDialogOpen,
      locationDialogMode
    } = this.state

    const ellipsisButtonSize = 24
    const buttonsCount = 5
    const minSize = 500
    const roughButtonSize = Math.floor(minSize / buttonsCount)
    const hideButtons = width < minSize
    const visibleButtonsCount = Math.max(hideButtons ? Math.floor((width - 3 * ellipsisButtonSize) / roughButtonSize) : buttonsCount, 0)

    const buttons = [
      <Button
        key='download'
        classes={{ root: classes.button }}
        color={color}
        size={buttonSize}
        variant='outlined'
        disabled={multiselectedFiles.size !== 1 || multiselectedFiles.values().next().value.directory}
        startIcon={<DownloadIcon />}
        onClick={this.handleDownload}
      >
        {messages.get(messages.DOWNLOAD)}
      </Button>,
      <Button
        key='delete'
        classes={{ root: classes.button }}
        color={color}
        size={buttonSize}
        variant='text'
        startIcon={<DeleteIcon />}
        onClick={this.openDeleteDialog}
      >
        {messages.get(messages.DELETE)}
      </Button>,
      <Button
        key='rename'
        classes={{ root: classes.button }}
        color={color}
        size={buttonSize}
        variant='text'
        disabled={multiselectedFiles.size !== 1}
        startIcon={<RenameIcon />}
        onClick={this.openRenameDialog}
      >
        {messages.get(messages.RENAME)}
      </Button>,
      <Button
        key='copy'
        classes={{ root: classes.button }}
        color={color}
        size={buttonSize}
        variant='text'
        startIcon={<CopyIcon />}
        onClick={this.openCopyLocationDialog}
      >
        {messages.get(messages.COPY)}
      </Button>,
      <Button
        key='move'
        classes={{ root: classes.button }}
        color={color}
        size={buttonSize}
        variant='text'
        startIcon={<MoveIcon />}
        onClick={this.openMoveLocationDialog}
      >
        {messages.get(messages.MOVE)}
      </Button>
    ]
    const ellipsisButton = (
      <IconButton
        key='ellipsis'
        classes={{ root: classes.button }}
        color={color}
        size={iconButtonSize}
        variant='outlined'
        onClick={this.handleOpen}
      >
        <MoreIcon />
      </IconButton>
    )

    const popover = (
      <Popover
        key='more'
        open={Boolean(hiddenButtonsPopup)}
        anchorEl={hiddenButtonsPopup}
        onClose={this.handleClose}
        anchorOrigin={{
          vertical: 'bottom',
          horizontal: 'left'
        }}
        transformOrigin={{
          vertical: 'top',
          horizontal: 'left'
        }}
      >
        <Container square={true}>{this.renderCollapsedButtons(buttons.slice(visibleButtonsCount))}</Container>
      </Popover>
    )

    const selectedValue = multiselectedFiles.values().next().value;
    return (
      <div className={classes.buttons}>
        {hideButtons
          ? [...buttons.slice(0, visibleButtonsCount), ellipsisButton, popover]
          : buttons}
        <ConfirmationDialog
          key='delete-dialog'
          open={deleteDialogOpen}
          onConfirm={this.handleDeleteConfirm}
          onCancel={this.handleDeleteCancel}
          title={messages.get(messages.DELETE)}
          content={messages.get(messages.CONFIRMATION_DELETE_SELECTED)}
        />
        <InputDialog
          key='rename-dialog'
          open={renameDialogOpen}
          title={selectedValue.directory ? messages.get(messages.RENAME_FOLDER) : messages.get(messages.RENAME_FILE)}
          inputLabel={selectedValue.directory ? messages.get(messages.FOLDER_NAME) : messages.get(messages.FILE_NAME)}
          inputValue={selectedValue.name}
          onCancel={this.handleRenameCancel}
          onConfirm={this.handleRenameConfirm}
        />
        <LocationDialog
          key='location-dialog'
          open={!!locationDialogMode}
          title={locationDialogMode === moveLocationMode ? messages.get(messages.MOVE) : messages.get(messages.COPY)}
          content={messages.get(messages.FILE_OR_FILES, multiselectedFiles.size)}
          datastoreServer={datastoreServer}
          sessionToken={sessionToken}
          owner={owner}
          path={path}
          multiselectedFiles={multiselectedFiles}
          onCancel={this.handleLocationCancel}
          onConfirm={this.handleLocationConfirm}
          />
      </div>
    );
  }

  renderCollapsedButtons(buttons) {
    const { classes } = this.props
    return (
      <div className={classes.collapsedButtonsContainer}>
        {buttons}
      </div>
    )
  }

  onResize({ width }) {
    if (width !== this.state.width) {
      this.setState({ width, hiddenButtonsPopup: null })
    }
  }

  handleOpen(event) {
    this.setState({
      hiddenButtonsPopup: event.currentTarget
    })
  }

  handleClose() {
    this.setState({
      hiddenButtonsPopup: null
    })
  }

  render() {
    logger.log(logger.DEBUG, 'LeftToolbar.render')

    const { multiselectedFiles, classes, owner } = this.props
    const { loading } = this.state

    return ([
      <ResizeObserver key='resize-observer' onResize={this.onResize}>
        <div className={classes.buttons}>
          {multiselectedFiles && multiselectedFiles.size > 0
            ? this.renderSelectionContextToolbar()
            : this.renderNoSelectionContextToolbar()}
        </div>
      </ResizeObserver>,
      <LoadingDialog key='loaging-dialog' loading={loading} />
    ])
  }
}

export default withStyles(styles)(LeftToolbar)