/*
Copyright (C) 2017  Cloudbase Solutions SRL
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

// @flow

import * as React from 'react'
import { observer } from 'mobx-react'
import styled, { css } from 'styled-components'

import EndpointLogos from '../../atoms/EndpointLogos'
import CopyValue from '../../atoms/CopyValue'
import StatusIcon from '../../atoms/StatusIcon'
import StatusImage from '../../atoms/StatusImage'
import Table from '../../molecules/Table'
import CopyButton from '../../atoms/CopyButton'

import type { MainItem } from '../../../types/MainItem'
import type { Endpoint } from '../../../types/Endpoint'
import StyleProps from '../../styleUtils/StyleProps'
import Palette from '../../styleUtils/Palette'
import DateUtils from '../../../utils/DateUtils'
import LabelDictionary from '../../../utils/LabelDictionary'
import DomUtils from '../../../utils/DomUtils'
import NotificationStore from '../../../stores/NotificationStore'

import arrowImage from './images/arrow.svg'

const Wrapper = styled.div`
  display: flex;
  flex-direction: column;
  padding-bottom: 48px;
`
const ColumnsLayout = styled.div`
  display: flex;
`
const Column = styled.div`
  width: ${props => props.width};
`
const Arrow = styled.div`
  width: 34px;
  height: 24px;
  background: url('${arrowImage}') center no-repeat;
  margin-top: 84px;
`
const Row = styled.div`
  margin-bottom: 32px;
  &:last-child {
    margin-bottom: 16px;
  }
`
const Field = styled.div`
  display: flex;
  flex-direction: column;
`
const Label = styled.div`
  font-size: 10px;
  color: ${Palette.grayscale[3]};
  font-weight: ${StyleProps.fontWeights.medium};
  text-transform: uppercase;
`
const Value = styled.div`
  display: ${props => props.flex ? 'flex' : props.block ? 'block' : 'inline-table'};
  margin-top: 3px;
  ${props => props.capitalize ? 'text-transform: capitalize;' : ''}
`
const ValueLink = styled.a`
  display: flex;
  margin-top: 3px;
  color: ${Palette.primary};
  text-decoration: none;
  cursor: pointer;
`
const TableStyled = styled(Table)`
  margin-top: 89px;
  margin-bottom: 48px;
`
const Loading = styled.div`
  display: flex;
  justify-content: center;
  align-items: center;
  height: 200px;
`
const PropertiesTable = styled.div``
const PropertyRow = styled.div`
  display: flex;
  justify-content: space-between;
  margin-bottom: 4px;
`
const PropertyText = css``
const PropertyName = styled.div`
  ${PropertyText}
`
const PropertyValue = styled.div`
  ${PropertyText}
  color: ${Palette.grayscale[4]};
  text-align: right;
  overflow: hidden;
  text-overflow: ellipsis;
`
const MultilineValue = styled.div`
  cursor: pointer;

  &:hover > span {
    opacity: 1;
  }
  > span {
    background-position-y: 4px;
    margin-left: 4px;
  }
`

type Props = {
  item: ?MainItem,
  endpoints: Endpoint[],
  bottomControls: React.Node,
  loading: boolean,
}
@observer
class MainDetails extends React.Component<Props> {
  getSourceEndpoint(): ?Endpoint {
    let endpoint = this.props.endpoints.find(e => this.props.item && e.id === this.props.item.origin_endpoint_id)
    return endpoint
  }

  getDestinationEndpoint(): ?Endpoint {
    let endpoint = this.props.endpoints.find(e => this.props.item && e.id === this.props.item.destination_endpoint_id)
    return endpoint
  }

  getLastExecution() {
    if (this.props.item && this.props.item.executions && this.props.item.executions.length) {
      return this.props.item.executions[this.props.item.executions.length - 1]
    }

    return {}
  }

  getConnectedVms(networkId: string) {
    let vms = []
    if (!this.props.item) {
      return '-'
    }
    Object.keys(this.props.item.info).forEach(key => {
      // $FlowIssue
      let instance = this.props.item.info[key]
      if (instance.export_info && instance.export_info.devices.nics.length) {
        instance.export_info.devices.nics.forEach(nic => {
          if (nic.network_name === networkId) {
            vms.push(key)
          }
        })
      }
    })

    return vms.length === 0 ? '-' : vms
  }

  getNetworks() {
    if (!this.props.item || !this.props.item.destination_environment || !this.props.item.destination_environment.network_map) {
      return null
    }
    let networks = []
    Object.keys(this.props.item.destination_environment.network_map).forEach(key => {
      let newItem
      if (this.props.item && typeof this.props.item.destination_environment.network_map[key] === 'object') {
        newItem = [
          this.props.item.destination_environment.network_map[key].source_network,
          this.getConnectedVms(key),
          // $FlowIssue
          this.props.item.destination_environment.network_map[key].destination_network,
          'Existing network',
        ]
      } else {
        newItem = [
          key,
          this.getConnectedVms(key),
          this.props.item ? this.props.item.destination_environment.network_map[key] : '-',
          'Existing network',
        ]
      }
      networks.push(newItem)
    })

    return networks
  }

  handleCopy(text: string) {
    let succesful = DomUtils.copyTextToClipboard(text)

    if (succesful) {
      NotificationStore.notify('The message has been copied to clipboard.')
    }
  }

  renderLastExecutionTime() {
    let lastExecution = this.getLastExecution()
    if (lastExecution.updated_at || lastExecution.created_at) {
      return this.renderValue(DateUtils.getLocalTime(lastExecution.updated_at || lastExecution.created_at).format('YYYY-MM-DD HH:mm:ss'))
    }

    return <Value>-</Value>
  }

  renderValue(value: string, dateTestId?: string) {
    return <CopyValue value={value} maxWidth="90%" data-test-id={dateTestId} />
  }

  renderNetworksTable() {
    if (this.props.loading) {
      return null
    }

    let items = this.getNetworks()

    if (!items || !items.length) {
      return null
    }

    return (
      <TableStyled
        header={['Source Network', 'Connected VMs', 'Destination Network', 'Destination Type']}
        items={items}
        columnsStyle={[css`color: ${Palette.black};`]}
      />
    )
  }

  renderEndpointLink(type: string): React.Node {
    let endpointIsMissing = (
      <Value flex>
        <StatusIcon style={{ marginRight: '8px' }} status="ERROR" />Endpoint is missing
      </Value>
    )

    let endpoint = type === 'source' ? this.getSourceEndpoint() : this.getDestinationEndpoint()

    if (endpoint) {
      return <ValueLink data-test-id="endpointName" href={`/#/endpoint/${endpoint.id}`}>{endpoint.name}</ValueLink>
    }

    return endpointIsMissing
  }

  renderMultilineValue(value: string, dataTestId?: string) {
    return (
      <MultilineValue onClick={() => { this.handleCopy(value) }} data-test-id={dataTestId}>
        {value}
        <CopyButton />
      </MultilineValue>
    )
  }

  renderDescription() {
    if (!this.props.item || !this.props.item.destination_environment || !this.props.item.destination_environment.description) {
      return <Value>-</Value>
    }
    return this.renderMultilineValue(this.props.item.destination_environment.description, 'description')
  }

  renderInstances(instances: string[]) {
    return this.renderMultilineValue(instances.join(', '))
  }

  renderPropertiesTable(propertyNames: string[]) {
    let renderValue = (value: any) => {
      if (value === true) {
        return 'Yes'
      }
      if (value === false) {
        return 'No'
      }
      return value.toString()
    }

    return (
      <PropertiesTable>
        {propertyNames.map(propName => {
          return (
            <PropertyRow key={propName}>
              <PropertyName>{LabelDictionary.get(propName)}</PropertyName>
              <PropertyValue>{renderValue(this.props.item ? this.props.item.destination_environment[propName] : '')}</PropertyValue>
            </PropertyRow>
          )
        })}
      </PropertiesTable>
    )
  }

  renderTable() {
    if (this.props.loading) {
      return null
    }
    const sourceEndpoint = this.getSourceEndpoint()
    const destinationEndpoint = this.getDestinationEndpoint()

    const propertyNames = this.props.item && this.props.item.destination_environment ? Object.keys(this.props.item.destination_environment).filter(k => k !== 'description' && k !== 'network_map') : []

    return (
      <ColumnsLayout>
        <Column width="34.5%">
          <Row>
            <Field>
              <Label>Source</Label>
              {this.renderEndpointLink('source')}
            </Field>
          </Row>
          <Row>
            <EndpointLogos endpoint={sourceEndpoint ? sourceEndpoint.type : ''} />
          </Row>
          <Row>
            <Field>
              <Label>Id</Label>
              {this.renderValue(this.props.item ? this.props.item.id || '-' : '-', 'id')}
            </Field>
          </Row>
          <Row>
            <Field>
              <Label>Created</Label>
              {this.props.item && this.props.item.created_at ? this.renderValue(DateUtils.getLocalTime(this.props.item.created_at).format('YYYY-MM-DD HH:mm:ss'), 'created') : <Value>-</Value>}
            </Field>
          </Row>
          <Row>
            <Field>
              <Label>Description</Label>
              {this.renderDescription()}
            </Field>
          </Row>
          <Row>
            <Field>
              <Label>Type</Label>
              <Value capitalize data-test-id="type">Coriolis {this.props.item && this.props.item.type}</Value>
            </Field>
          </Row>
          <Row>
            <Field>
              <Label>Last Updated</Label>
              <Value data-test-id="updated">{this.renderLastExecutionTime()}</Value>
            </Field>
          </Row>
        </Column>
        <Column width="17.5%">
          <Arrow />
        </Column>
        <Column width="auto" style={{ flexGrow: 1 }}>
          <Row>
            <Field>
              <Label>Target</Label>
              {this.renderEndpointLink('target')}
            </Field>
          </Row>
          <Row>
            <EndpointLogos endpoint={destinationEndpoint ? destinationEndpoint.type : ''} />
          </Row>
          {propertyNames.length > 0 ? (
            <Row>
              <Field>
                <Label>Properties</Label>
                <Value block>{this.renderPropertiesTable(propertyNames)}</Value>
              </Field>
            </Row>
          ) : null}
          {this.props.item && this.props.item.instances ? (
            <Row>
              <Field>
                <Label>Instances</Label>
                {this.renderInstances(this.props.item.instances)}
              </Field>
            </Row>
          ) : null}
        </Column>
      </ColumnsLayout>
    )
  }

  renderBottomControls() {
    if (this.props.loading) {
      return null
    }

    return this.props.bottomControls
  }

  renderLoading() {
    if (!this.props.loading) {
      return null
    }

    return (
      <Loading>
        <StatusImage loading />
      </Loading>
    )
  }

  render() {
    return (
      <Wrapper>
        {this.renderTable()}
        {this.renderNetworksTable()}
        {this.renderBottomControls()}
        {this.renderLoading()}
      </Wrapper>
    )
  }
}

export default MainDetails
