import React, { Fragment } from 'react';
import { withRouter } from 'react-router-dom';
import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro';

import { OrganizationsAPI, TeamsAPI, UsersAPI } from '@api';
import AddResourceRole from '@components/AddRole/AddResourceRole';
import AlertModal from '@components/AlertModal';
import DataListToolbar from '@components/DataListToolbar';
import ErrorDetail from '@components/ErrorDetail';
import PaginatedDataList, { ToolbarAddButton } from '@components/PaginatedDataList';
import {
  getQSConfig,
  encodeQueryString,
  parseNamespacedQueryString
} from '@util/qs';
import { Organization } from '@types';

import DeleteRoleConfirmationModal from './DeleteRoleConfirmationModal';
import OrganizationAccessItem from './OrganizationAccessItem';

const QS_CONFIG = getQSConfig('access', {
  page: 1,
  page_size: 5,
  order_by: 'first_name',
});

class OrganizationAccess extends React.Component {
  static propTypes = {
    organization: Organization.isRequired,
  };

  constructor (props) {
    super(props);
    this.state = {
      accessRecords: [],
      contentError: null,
      hasContentLoading: true,
      deletionError: null,
      deletionRecord: null,
      deletionRole: null,
      isAddModalOpen: false,
      itemCount: 0,
    };
    this.loadAccessList = this.loadAccessList.bind(this);
    this.handleAddClose = this.handleAddClose.bind(this);
    this.handleAddOpen = this.handleAddOpen.bind(this);
    this.handleAddSuccess = this.handleAddSuccess.bind(this);
    this.handleDeleteCancel = this.handleDeleteCancel.bind(this);
    this.handleDeleteConfirm = this.handleDeleteConfirm.bind(this);
    this.handleDeleteErrorClose = this.handleDeleteErrorClose.bind(this);
    this.handleDeleteOpen = this.handleDeleteOpen.bind(this);
  }

  componentDidMount () {
    this.loadAccessList();
  }

  componentDidUpdate (prevProps) {
    const { location } = this.props;

    const prevParams = parseNamespacedQueryString(QS_CONFIG, prevProps.location.search);
    const currentParams = parseNamespacedQueryString(QS_CONFIG, location.search);

    if (encodeQueryString(currentParams) !== encodeQueryString(prevParams)) {
      this.loadAccessList();
    }
  }

  async loadAccessList () {
    const { organization, location } = this.props;
    const params = parseNamespacedQueryString(QS_CONFIG, location.search);

    this.setState({ contentError: null, hasContentLoading: true });
    try {
      const {
        data: {
          results: accessRecords = [],
          count: itemCount = 0
        }
      } = await OrganizationsAPI.readAccessList(organization.id, params);
      this.setState({ itemCount, accessRecords });
    } catch (err) {
      this.setState({ contentError: err });
    } finally {
      this.setState({ hasContentLoading: false });
    }
  }

  handleDeleteOpen (deletionRole, deletionRecord) {
    this.setState({ deletionRole, deletionRecord });
  }

  handleDeleteCancel () {
    this.setState({ deletionRole: null, deletionRecord: null });
  }

  handleDeleteErrorClose () {
    this.setState({
      deletionError: null,
      deletionRecord: null,
      deletionRole: null
    });
  }

  async handleDeleteConfirm () {
    const { deletionRole, deletionRecord } = this.state;

    if (!deletionRole || !deletionRecord) {
      return;
    }

    let promise;
    if (typeof deletionRole.team_id !== 'undefined') {
      promise = TeamsAPI.disassociateRole(deletionRole.team_id, deletionRole.id);
    } else {
      promise = UsersAPI.disassociateRole(deletionRecord.id, deletionRole.id);
    }

    this.setState({ hasContentLoading: true });
    try {
      await promise.then(this.loadAccessList);
      this.setState({
        deletionRole: null,
        deletionRecord: null
      });
    } catch (err) {
      this.setState({
        hasContentLoading: false,
        deletionError: err
      });
    }
  }

  handleAddClose () {
    this.setState({ isAddModalOpen: false });
  }

  handleAddOpen () {
    this.setState({ isAddModalOpen: true });
  }

  handleAddSuccess () {
    this.setState({ isAddModalOpen: false });
    this.loadAccessList();
  }

  render () {
    const { organization, i18n } = this.props;
    const {
      accessRecords,
      contentError,
      hasContentLoading,
      deletionRole,
      deletionRecord,
      deletionError,
      itemCount,
      isAddModalOpen
    } = this.state;
    const canEdit = organization.summary_fields.user_capabilities.edit;
    const isDeleteModalOpen = !hasContentLoading && !deletionError && deletionRole;

    return (
      <Fragment>
        <PaginatedDataList
          error={contentError}
          hasContentLoading={hasContentLoading}
          items={accessRecords}
          itemCount={itemCount}
          itemName="role"
          qsConfig={QS_CONFIG}
          toolbarColumns={[
            { name: i18n._(t`Name`), key: 'first_name', isSortable: true },
            { name: i18n._(t`Username`), key: 'username', isSortable: true },
            { name: i18n._(t`Last Name`), key: 'last_name', isSortable: true },
          ]}
          renderToolbar={(props) => (
            <DataListToolbar
              {...props}
              additionalControls={canEdit ? [
                <ToolbarAddButton key="add" onClick={this.handleAddOpen} />
              ] : null}
            />
          )}
          renderItem={accessRecord => (
            <OrganizationAccessItem
              key={accessRecord.id}
              accessRecord={accessRecord}
              onRoleDelete={this.handleDeleteOpen}
            />
          )}
        />
        {isAddModalOpen && (
          <AddResourceRole
            onClose={this.handleAddClose}
            onSave={this.handleAddSuccess}
            roles={organization.summary_fields.object_roles}
          />
        )}
        {isDeleteModalOpen && (
          <DeleteRoleConfirmationModal
            role={deletionRole}
            username={deletionRecord.username}
            onCancel={this.handleDeleteCancel}
            onConfirm={this.handleDeleteConfirm}
          />
        )}
        <AlertModal
          isOpen={deletionError}
          variant="danger"
          title={i18n._(t`Error!`)}
          onClose={this.handleDeleteErrorClose}
        >
          {i18n._(t`Failed to delete role`)}
          <ErrorDetail error={deletionError} />
        </AlertModal>
      </Fragment>
    );
  }
}

export { OrganizationAccess as _OrganizationAccess };
export default withI18n()(withRouter(OrganizationAccess));
