import { isString, map, get, find } from "lodash";
import React from "react";
import PropTypes from "prop-types";

import Button from "antd/lib/button";
import Modal from "antd/lib/modal";
import routeWithUserSession from "@/components/ApplicationArea/routeWithUserSession";
import Paginator from "@/components/Paginator";
import DynamicComponent from "@/components/DynamicComponent";
import { UserPreviewCard } from "@/components/PreviewCard";
import InputWithCopy from "@/components/InputWithCopy";

import { wrap as itemsList, ControllerType } from "@/components/items-list/ItemsList";
import { ResourceItemsSource } from "@/components/items-list/classes/ItemsSource";
import { UrlStateStorage } from "@/components/items-list/classes/StateStorage";

import LoadingState from "@/components/items-list/components/LoadingState";
import EmptyState from "@/components/items-list/components/EmptyState";
import * as Sidebar from "@/components/items-list/components/Sidebar";
import ItemsTable, { Columns } from "@/components/items-list/components/ItemsTable";

import Layout from "@/components/layouts/ContentWithSidebar";
import CreateUserDialog from "@/components/users/CreateUserDialog";
import wrapSettingsTab from "@/components/SettingsWrapper";

import { currentUser } from "@/services/auth";
import { policy } from "@/services/policy";
import User from "@/services/user";
import navigateTo from "@/components/ApplicationArea/navigateTo";
import notification from "@/services/notification";
import { absoluteUrl } from "@/services/utils";

function UsersListActions({ user, enableUser, disableUser, deleteUser }) {
  if (user.id === currentUser.id) {
    return null;
  }
  if (user.is_invitation_pending) {
    return (
      <Button type="danger" className="w-100" onClick={event => deleteUser(event, user)}>
        Delete
      </Button>
    );
  }
  return user.is_disabled ? (
    <Button type="primary" className="w-100" onClick={event => enableUser(event, user)}>
      Enable
    </Button>
  ) : (
    <Button className="w-100" onClick={event => disableUser(event, user)}>
      Disable
    </Button>
  );
}

UsersListActions.propTypes = {
  user: PropTypes.shape({
    id: PropTypes.number,
    is_invitation_pending: PropTypes.bool,
    is_disabled: PropTypes.bool,
  }).isRequired,
  enableUser: PropTypes.func.isRequired,
  disableUser: PropTypes.func.isRequired,
  deleteUser: PropTypes.func.isRequired,
};

class UsersList extends React.Component {
  static propTypes = {
    controller: ControllerType.isRequired,
  };

  sidebarMenu = [
    {
      key: "active",
      href: "users",
      title: "Active Users",
    },
    {
      key: "pending",
      href: "users/pending",
      title: "Pending Invitations",
    },
    {
      key: "disabled",
      href: "users/disabled",
      title: "Disabled Users",
      isAvailable: () => policy.canCreateUser(),
    },
  ];

  listColumns = [
    Columns.custom.sortable((text, user) => <UserPreviewCard user={user} withLink />, {
      title: "Name",
      field: "name",
      width: null,
    }),
    Columns.custom.sortable(
      (text, user) =>
        map(user.groups, group => (
          <a key={"group" + group.id} className="label label-tag" href={"groups/" + group.id}>
            {group.name}
          </a>
        )),
      {
        title: "Groups",
        field: "groups",
      }
    ),
    Columns.timeAgo.sortable({
      title: "Joined",
      field: "created_at",
      className: "text-nowrap",
      width: "1%",
    }),
    Columns.timeAgo.sortable({
      title: "Last Active At",
      field: "active_at",
      className: "text-nowrap",
      width: "1%",
    }),
    Columns.custom(
      (text, user) => (
        <UsersListActions
          user={user}
          enableUser={this.enableUser}
          disableUser={this.disableUser}
          deleteUser={this.deleteUser}
        />
      ),
      {
        width: "1%",
        isAvailable: () => policy.canCreateUser(),
      }
    ),
  ];

  componentDidMount() {
    if (this.props.controller.params.isNewUserPage) {
      this.showCreateUserDialog();
    }
  }

  createUser = values =>
    User.create(values)
      .then(user => {
        notification.success("Saved.");
        if (user.invite_link) {
          Modal.warning({
            title: "Email not sent!",
            content: (
              <React.Fragment>
                <p>
                  The mail server is not configured, please send the following link to <b>{user.name}</b>:
                </p>
                <InputWithCopy value={absoluteUrl(user.invite_link)} readOnly />
              </React.Fragment>
            ),
          });
        }
      })
      .catch(error => {
        const message = find([get(error, "response.data.message"), get(error, "message"), "Failed saving."], isString);
        return Promise.reject(new Error(message));
      });

  showCreateUserDialog = () => {
    if (policy.isCreateUserEnabled()) {
      const goToUsersList = () => {
        if (this.props.controller.params.isNewUserPage) {
          navigateTo("users");
        }
      };
      CreateUserDialog.showModal()
        .onClose(values =>
          this.createUser(values).then(() => {
            this.props.controller.update();
            goToUsersList();
          })
        )
        .onDismiss(goToUsersList);
    }
  };

  enableUser = (event, user) => User.enableUser(user).then(() => this.props.controller.update());

  disableUser = (event, user) => User.disableUser(user).then(() => this.props.controller.update());

  deleteUser = (event, user) => User.deleteUser(user).then(() => this.props.controller.update());

  // eslint-disable-next-line class-methods-use-this
  renderPageHeader() {
    if (!policy.canCreateUser()) {
      return null;
    }
    return (
      <div className="m-b-15">
        <Button type="primary" disabled={!policy.isCreateUserEnabled()} onClick={this.showCreateUserDialog}>
          <i className="fa fa-plus m-r-5" />
          New User
        </Button>
        <DynamicComponent name="UsersListExtra" />
      </div>
    );
  }

  render() {
    const { controller } = this.props;
    return (
      <React.Fragment>
        {this.renderPageHeader()}
        <Layout>
          <Layout.Sidebar className="m-b-0">
            <Sidebar.SearchInput value={controller.searchTerm} onChange={controller.updateSearch} />
            <Sidebar.Menu items={this.sidebarMenu} selected={controller.params.currentPage} />
            <Sidebar.PageSizeSelect
              className="m-b-10"
              options={controller.pageSizeOptions}
              value={controller.itemsPerPage}
              onChange={itemsPerPage => controller.updatePagination({ itemsPerPage })}
            />
          </Layout.Sidebar>
          <Layout.Content>
            {!controller.isLoaded && <LoadingState className="" />}
            {controller.isLoaded && controller.isEmpty && <EmptyState className="" />}
            {controller.isLoaded && !controller.isEmpty && (
              <div className="table-responsive" data-test="UserList">
                <ItemsTable
                  items={controller.pageItems}
                  columns={this.listColumns}
                  context={this.actions}
                  orderByField={controller.orderByField}
                  orderByReverse={controller.orderByReverse}
                  toggleSorting={controller.toggleSorting}
                />
                <Paginator
                  totalCount={controller.totalItemsCount}
                  itemsPerPage={controller.itemsPerPage}
                  page={controller.page}
                  onChange={page => controller.updatePagination({ page })}
                />
              </div>
            )}
          </Layout.Content>
        </Layout>
      </React.Fragment>
    );
  }
}

const UsersListPage = wrapSettingsTab(
  {
    permission: "list_users",
    title: "Users",
    path: "users",
    isActive: path => path.startsWith("/users") && path !== "/users/me",
    order: 2,
  },
  itemsList(
    UsersList,
    () =>
      new ResourceItemsSource({
        getRequest(request, { params: { currentPage } }) {
          switch (currentPage) {
            case "active":
              request.pending = false;
              break;
            case "pending":
              request.pending = true;
              break;
            case "disabled":
              request.disabled = true;
              break;
            // no default
          }
          return request;
        },
        getResource() {
          return User.query.bind(User);
        },
      }),
    () => new UrlStateStorage({ orderByField: "created_at", orderByReverse: true })
  )
);

export default [
  routeWithUserSession({
    path: "/users/new",
    title: "Users",
    render: pageProps => <UsersListPage {...pageProps} currentPage="active" isNewUserPage />,
  }),
  routeWithUserSession({
    path: "/users",
    title: "Users",
    render: pageProps => <UsersListPage {...pageProps} currentPage="active" />,
  }),
  routeWithUserSession({
    path: "/users/pending",
    title: "Pending Invitations",
    render: pageProps => <UsersListPage {...pageProps} currentPage="pending" />,
  }),
  routeWithUserSession({
    path: "/users/disabled",
    title: "Disabled Users",
    render: pageProps => <UsersListPage {...pageProps} currentPage="disabled" />,
  }),
];
