// 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 PropTypes from 'prop-types';
import React from 'react';
import {Form, Table, Tooltip, OverlayTrigger} from "react-bootstrap";
import moment from 'moment';
import {ErrorModal} from './modals';
import {removeCredentialsFromUrl} from '../api';
import Components from "../../components/react-components";
import Helpers from '../../../helpers';
import FauxtonAPI from "../../../core/api";

const { ToolbarButton } = Components;

const getDbNameFromUrl = (urlObj, root) => {
  try {
    const urlWithoutDb = new URL(root);
    const dbName = urlObj.pathname.substring(urlWithoutDb.pathname.length);
    return encodeURIComponent(dbName);
  } catch (e) {
    return '';
  }
};

export const formatUrl = (url) => {
  let urlObj;
  let encoded;
  try {
    urlObj = new URL(removeCredentialsFromUrl(url));
  } catch (e) {
    return '';
  }
  const root = Helpers.getRootUrl();
  encoded = getDbNameFromUrl(urlObj, root);
  if (url.indexOf(window.location.hostname) > -1) {
    return (
      <span>
        {root}
        <a href={`#/database/${encoded}/_all_docs`}>{decodeURIComponent(encoded)}</a>
      </span>
    );
  }

  return `${urlObj.origin}${urlObj.pathname}`;
};

class RowStatus extends React.Component {
  constructor (props) {
    super(props);
    this.state = {
      modalVisible: false,
    };
  }

  showModal () {
    this.setState({modalVisible: true});
  }

  closeModal () {
    this.setState({modalVisible: false});
  }

  getErrorIcon () {
    const {status} = this.props;
    if (status !== 'error' && status !== 'retrying') {
      return null;
    }

    return (
      <span>
        <a
          data-bypass="true"
          className="replication__row-btn replication__row-btn--warning fonticon-attention-circled"
          onClick={this.showModal.bind(this)}
          title="View error message">
        </a>
        <ErrorModal
          onClick={this.closeModal.bind(this)}
          onClose={this.closeModal.bind(this)}
          errorMsg={this.props.errorMsg}
          visible={this.state.modalVisible}
          status={status}
        />
      </span>
    );
  }

  render () {
    const {statusTime, status} = this.props;
    let momentTime = moment(statusTime);
    let statusValue = <span>{status}</span>;

    if (momentTime.isValid()) {
      const formattedStatusTime = momentTime.format("MMM Do, h:mm a");
      const stateTimeTooltip = <Tooltip id="">Last updated: {formattedStatusTime}</Tooltip>;
      statusValue =
        <OverlayTrigger placement="top" overlay={stateTimeTooltip}>
          <span>{status}</span>
        </OverlayTrigger>;
    }

    return (
      <td className={`replication__row-status replication__row-status--${status}`}>
        {statusValue}
        {this.getErrorIcon()}
      </td>
    );
  }
}

RowStatus.propTypes = {
  statusTime: PropTypes.any,
  status: PropTypes.string,
  errorMsg: PropTypes.string.isRequired,
};

RowStatus.defaultProps = {
  status: ''
};

const RowActions = ({onlyDeleteAction, _id, url, deleteDocs}) => {
  const actions = [];
  if (!onlyDeleteAction) {
    actions.push(
      <ToolbarButton icon="fonticon-wrench"
        title={`Edit replication`}
        aria-label={`Edit replication`}
        key={1}
        onClick={() => FauxtonAPI.navigate(`#replication/id/${encodeURIComponent(_id)}`)} />
    );
    actions.push(
      <ToolbarButton icon="fonticon-document"
        title={`Edit replication document`}
        aria-label={`Edit replication document ${_id}`}
        key={2}
        onClick={() => FauxtonAPI.navigate(url)} />
    );
  }

  actions.push(
    <ToolbarButton icon="fonticon-trash"
      title={`Delete ${onlyDeleteAction ? 'job' : 'document'}`}
      aria-label={`Delete ${onlyDeleteAction ? 'job' : 'document'} ${_id}`}
      key={3}
      onClick={() => deleteDocs(_id)} />
  );

  return (
    <div className="replication__actions">
      {actions}
    </div>
  );
};

RowActions.propTypes = {
  _id: PropTypes.string.isRequired,
  url: PropTypes.string,
  error: PropTypes.bool.isRequired,
  errorMsg: PropTypes.string.isRequired,
  deleteDocs: PropTypes.func.isRequired
};

const Row = ({
  _id,
  source,
  target,
  type,
  startTime,
  status,
  statusTime,
  url,
  selected,
  selectDoc,
  errorMsg,
  deleteDocs,
  onlyDeleteAction,
  showStateRow
}) => {
  let momentTime = moment(startTime);
  const formattedStartTime = momentTime.isValid() ? momentTime.format("MMM Do, h:mm a") : '';
  let stateRow = null;

  if (showStateRow) {
    stateRow = <RowStatus
      statusTime={statusTime}
      status={status}
      errorMsg={errorMsg}
    />;
  }

  return (
    <tr className="replication__table-row">
      <td className="replication__table-col">
        <Form.Check type="checkbox"
          checked={selected}
          onChange={() => selectDoc(_id)} />
      </td>
      <td className="replication__table-col">{formatUrl(source)}</td>
      <td className="replication__table-col">{formatUrl(target)}</td>
      <td className="replication__table-col">{formattedStartTime}</td>
      <td className="replication__table-col">{type}</td>
      {stateRow}
      <td className="replication__table-col">
        <RowActions
          onlyDeleteAction={onlyDeleteAction}
          deleteDocs={deleteDocs}
          _id={_id}
          url={url}
          error={status === "error" || status === 'retrying'}
          errorMsg={errorMsg}
        />
      </td>
    </tr>

  );
};

Row.propTypes = {
  _id: PropTypes.string.isRequired,
  source: PropTypes.string.isRequired,
  target: PropTypes.string.isRequired,
  type: PropTypes.string.isRequired,
  status: PropTypes.string,
  url: PropTypes.string,
  statusTime: PropTypes.object.isRequired,
  startTime: PropTypes.object,
  selected: PropTypes.bool.isRequired,
  selectDoc: PropTypes.func.isRequired,
  errorMsg: PropTypes.string.isRequired,
  deleteDocs: PropTypes.func.isRequired,
  onlyDeleteAction: PropTypes.bool.isRequired,
  showStateRow: PropTypes.bool.isRequired
};

const BulkSelectHeader = ({isSelected, deleteDocs, someDocsSelected, onCheck}) => {
  const trash = someDocsSelected ?
    <ToolbarButton icon="fonticon-trash"
      title="Delete all selected"
      aria-label="Delete all selected"
      onClick={() => deleteDocs()} /> : null;

  return (
    <div className="replication__bulk-select-wrapper">
      <div className="replication__bulk-select-header">
        <Form.Check type="checkbox"
          className="replication__bulk-select-input"
          checked={isSelected}
          onChange={onCheck} />
      </div>
      {trash}
    </div>
  );
};

BulkSelectHeader.propTypes = {
  isSelected: PropTypes.bool.isRequired,
  someDocsSelected: PropTypes.bool.isRequired,
  onCheck: PropTypes.func.isRequired,
  deleteDocs: PropTypes.func.isRequired
};

const EmptyRow = ({msg}) => {
  return (
    <tr>
      <td colSpan="7" className="replication__empty-row">
        {msg}
      </td>
    </tr>
  );
};

EmptyRow.defaultProps = {
  msg: "There is no replicator-db activity or history to display."
};


export class ReplicationTable extends React.Component {
  constructor (props) {
    super(props);
  }

  sort(column, descending, docs) {
    let orderChanged = false;
    const sorted = docs.sort((a, b) => {
      if (a[column] < b[column]) {
        orderChanged = true;
        return -1;
      }

      if (a[column] > b[column]) {
        orderChanged = true;
        return 1;
      }

      return 0;

    });

    if (!descending && orderChanged) {
      sorted.reverse();
    }

    return sorted;
  }

  renderRows () {
    if (this.props.docs.length === 0) {
      return <EmptyRow />;
    }

    return this.sort(this.props.column, this.props.descending, this.props.docs).map((doc, i) => {
      return <Row
        key={i}
        _id={doc._id}
        selected={doc.selected}
        selectDoc={this.props.selectDoc}
        source={doc.source}
        target={doc.target}
        type={doc.continuous === true ? 'Continuous' : 'One time'}
        status={doc.status}
        statusTime={doc.statusTime}
        startTime={doc.startTime}
        url={doc.url}
        deleteDocs={this.props.deleteDocs}
        errorMsg={doc.errorMsg}
        doc={doc}
        onlyDeleteAction={this.props.onlyDeleteAction}
        showStateRow={this.props.showStateRow}
      />;
    });
  }

  iconDirection (column) {
    if (column === this.props.column && !this.props.descending) {
      return 'fonticon-up-dir';
    }

    return 'fonticon-down-dir';
  }

  onSort (column) {
    return () => {
      this.props.changeSort({
        descending: column === this.props.column ? !this.props.descending : true,
        column
      });
    };
  }

  isSelected (header) {
    if (header === this.props.column) {
      return 'replication__table--selected';
    }

    return '';
  }

  stateCol () {
    if (this.props.showStateRow) {
      return (
        <th className="replication__table-header-status" onClick={this.onSort('status')}>
          State
          <span className={`replication__table-header-icon ${this.iconDirection('status')} ${this.isSelected('status')}`} />
        </th>
      );
    }

    return null;
  }

  render () {

    return (
      <Table striped>
        <thead>
          <tr>
            <th className="replication__table-bulk-select">
              <BulkSelectHeader
                isSelected={this.props.allDocsSelected}
                onCheck={this.props.selectAllDocs}
                someDocsSelected={this.props.someDocsSelected}
                deleteDocs={this.props.deleteDocs}
              />
            </th>
            <th className="replication__table-header-source" onClick={this.onSort('source')}>
              Source
              <span className={`replication__table-header-icon ${this.iconDirection('source')} ${this.isSelected('source')}`} />
            </th>
            <th className="replication__table-header-target" onClick={this.onSort('target')}>
              Target
              <span className={`replication__table-header-icon ${this.iconDirection('target')} ${this.isSelected('target')}`} />
            </th>
            <th className="replication__table-header-time" onClick={this.onSort('statusTime')}>
              Start Time
              <span className={`replication__table-header-icon ${this.iconDirection('statusTime')} ${this.isSelected('statusTime')}`} />
            </th>
            <th className="replication__table-header-type" onClick={this.onSort('continuous')}>
              Type
              <span className={`replication__table-header-icon ${this.iconDirection('continuous')} ${this.isSelected('continuous')}`} />
            </th>
            {this.stateCol()}
            <th className="replication__table-header-actions">
              Actions
            </th>
          </tr>
        </thead>
        <tbody>
          {this.renderRows()}
        </tbody>
      </Table>
    );
  }
}

ReplicationTable.defaultProps = {
  onlyDeleteAction: false,
  showStateRow: true
};
