import React, { useCallback, useState } from "react";
import pick from "lodash/pick";

import {
  acceptProposal,
  announceProposal,
  archive,
  dislike,
  edit,
  hide,
  like,
  loadPosts,
  markSeen,
  rejectProposal,
  rejectProposalByChairman,
} from "actions/posts";
import { ban, unban } from "actions/users";
import ErrorMessage from "components/ErrorMessage";
import ModalConfirm from "components/modals/ModalConfirm";
import PostEditModal from "components/posts/PostEditModal";
import PostList from "components/posts/PostList";
import { useActionState, useItemActionConfirm } from "hooks";
import { AuthStore, PostStore } from "stores";

const PostsContainer = ({ className }) => {
  const [postToEdit, setPostToEdit] = useState(null);
  const [confirmingEdit, setConfirmingEdit] = useState(false);
  const [editError, setEditError] = useState(null);

  const [
    userToBan,
    setUserToBan,
    onBanUserConfirm,
    onBanUserCancel,
  ] = useItemActionConfirm(ban);
  const [
    userToUnban,
    setUserToUnban,
    onUnbanUserConfirm,
    onUnbanUserCancel,
  ] = useItemActionConfirm(unban);
  const [
    postToHide,
    setPostToHide,
    onPostHideConfirm,
    onPostHideCancel,
  ] = useItemActionConfirm(hide);
  const [
    postToArchive,
    setPostToArchive,
    onPostArchiveConfirm,
    onPostArchiveCancel,
  ] = useItemActionConfirm(archive);
  const [
    postToAnnounce,
    setPostToAnnounce,
    onAnnounceConfirm,
    onAnnounceCancel,
  ] = useItemActionConfirm(announceProposal);
  const [
    postToAccept,
    setPostToAccept,
    onAcceptConfirm,
    onAcceptCancel,
  ] = useItemActionConfirm(acceptProposal);
  const [
    postToReject,
    setPostToReject,
    onRejectConfirm,
    onRejectCancel,
  ] = useItemActionConfirm(rejectProposal);
  const [
    postToRejectByChairman,
    setPostToRejectByChairman,
    onRejectByChairmanConfirm,
    onRejectByChairmanCancel,
  ] = useItemActionConfirm(rejectProposalByChairman);

  const { isAuthenticated, user } = AuthStore.useState();
  const { window, items } = PostStore.useState((state) =>
    pick(state, ["window", "items"])
  );
  const showingArchivedOnly = PostStore.useState(
    (state) => state.filters.flags === "archived"
  );

  const [banningUser, banningUserError] = useActionState(ban, userToBan);
  const [unbanningUser, unbanningUserError] = useActionState(
    unban,
    userToUnban
  );
  const [hidingPost, hidingPostError] = useActionState(hide, postToHide);
  const [archivingPost, archivingPostError] = useActionState(
    archive,
    postToArchive
  );
  const [announcingProposal, announcingProposalError] = useActionState(
    announceProposal,
    postToAnnounce
  );
  const [acceptingProposal, acceptingProposalError] = useActionState(
    acceptProposal,
    postToAccept
  );
  const [rejectingProposal, rejectingProposalError] = useActionState(
    rejectProposal,
    postToReject
  );
  const [
    rejectingProposalByChairman,
    rejectingProposalByChairmanError,
  ] = useActionState(rejectProposalByChairman, postToRejectByChairman);

  const { 2: loadResult } = loadPosts.useWatch();

  const confirmEdit = useCallback(
    async (newContent) => {
      if (postToEdit && newContent) {
        setConfirmingEdit(true);

        const result = await edit.run({ post: postToEdit, newContent });

        if (!result.error) {
          setPostToEdit(null);
          setEditError(null);
        } else {
          setEditError(result.message);
        }

        setConfirmingEdit(false);
      }
    },
    [postToEdit, setPostToEdit]
  );

  const cancelEdit = useCallback(() => {
    setPostToEdit(null);
  }, [setPostToEdit]);

  /**
   * Ban a post's author.
   * @param {CF2021.Post} post
   */
  const onBanUser = (post) => {
    setUserToBan(post.author);
  };
  /**
   * Ban a post's author.
   * @param {CF2021.Post} post
   */
  const onUnbanUser = (post) => {
    setUserToUnban(post.author);
  };

  const sliceStart = (window.page - 1) * window.perPage;
  const sliceEnd = window.page * window.perPage;
  const windowItems = window.items.map((postId) => items[postId]);

  return (
    <>
      {loadResult && loadResult.error && (
        <ErrorMessage>
          Příspěvky se nepodařilo načíst: {loadResult.message}
        </ErrorMessage>
      )}
      <PostList
        items={windowItems.slice(sliceStart, sliceEnd)}
        canThumb={isAuthenticated}
        onLike={like.run}
        onDislike={dislike.run}
        onSeen={markSeen}
        className={className}
        dimArchived={!showingArchivedOnly}
        currentUser={user}
        onHide={setPostToHide}
        onBanUser={onBanUser}
        onUnbanUser={onUnbanUser}
        onEdit={setPostToEdit}
        onArchive={setPostToArchive}
        onAnnounceProcedureProposal={setPostToAnnounce}
        onAcceptProcedureProposal={setPostToAccept}
        onRejectProcedureProposal={setPostToReject}
        onRejectProcedureProposalByChairman={setPostToRejectByChairman}
      />
      <ModalConfirm
        isOpen={!!userToBan}
        onConfirm={onBanUserConfirm}
        onCancel={onBanUserCancel}
        confirming={banningUser}
        error={banningUserError}
        title={`Zablokovat uživatele ${userToBan ? userToBan.name : null}?`}
        yesActionLabel="Zablokovat"
      >
        Uživatel <strong>{userToBan ? userToBan.name : null}</strong> bude
        zablokován a nebude dále moci vkládat nové příspěvky. Opravdu to chcete?
      </ModalConfirm>
      <ModalConfirm
        isOpen={!!userToUnban}
        onConfirm={onUnbanUserConfirm}
        onCancel={onUnbanUserCancel}
        confirming={unbanningUser}
        error={unbanningUserError}
        title={`Odblokovat uživatele ${userToUnban ? userToUnban.name : null}?`}
        yesActionLabel="Odblokovat"
      >
        Uživatel <strong>{userToUnban ? userToUnban.name : null}</strong> bude
        odblokován a bude mu opět umožněno přidávat nové příspěvky. Opravdu to
        chcete?
      </ModalConfirm>
      <ModalConfirm
        isOpen={!!postToHide}
        onConfirm={onPostHideConfirm}
        onCancel={onPostHideCancel}
        confirming={hidingPost}
        error={hidingPostError}
        title="Skrýt příspěvek?"
        yesActionLabel="Potvrdit"
      >
        Příspěvek se skryje a uživatelé ho neuvidí. Opravdu to chcete?
      </ModalConfirm>
      <ModalConfirm
        isOpen={!!postToArchive}
        onConfirm={onPostArchiveConfirm}
        onCancel={onPostArchiveCancel}
        confirming={archivingPost}
        error={archivingPostError}
        title="Archivovat příspěvek?"
        yesActionLabel="Potvrdit"
      >
        Příspěvek bude archivován a bude ve výpisu vizuálně odlišen. Opravdu to
        chcete?
      </ModalConfirm>
      <ModalConfirm
        isOpen={!!postToAnnounce}
        onConfirm={onAnnounceConfirm}
        onCancel={onAnnounceCancel}
        confirming={announcingProposal}
        error={announcingProposalError}
        title="Vyhlásit procedurální návrh?"
        yesActionLabel="Vyhlásit návrh"
      >
        Procedurální návrh bude <strong>vyhlášen</strong>. Opravdu to chcete?
      </ModalConfirm>
      <ModalConfirm
        isOpen={!!postToAccept}
        onConfirm={onAcceptConfirm}
        onCancel={onAcceptCancel}
        confirming={acceptingProposal}
        error={acceptingProposalError}
        title="Schválit procedurální návrh?"
        yesActionLabel="Schválit návrh"
      >
        Procedurální návrh bude <strong>schválen</strong>. Opravdu to chcete?
      </ModalConfirm>
      <ModalConfirm
        isOpen={!!postToReject}
        onConfirm={onRejectConfirm}
        onCancel={onRejectCancel}
        confirming={rejectingProposal}
        error={rejectingProposalError}
        title="Zamítnout procedurální návrh?"
        yesActionLabel="Zamítnout návrh"
      >
        Procedurální návrh bude <strong>zamítnut</strong>. Opravdu to chcete?
      </ModalConfirm>
      <ModalConfirm
        isOpen={!!postToRejectByChairman}
        onConfirm={onRejectByChairmanConfirm}
        onCancel={onRejectByChairmanCancel}
        confirming={rejectingProposalByChairman}
        error={rejectingProposalByChairmanError}
        title="Zamítnout procedurální návrh předsedajícícm?"
        yesActionLabel="Zamítnout návrh předsedajícím"
      >
        Procedurální návrh bude <strong>zamítnut předsedajícím</strong>. Opravdu
        to chcete?
      </ModalConfirm>
      {postToEdit && (
        <PostEditModal
          isOpen={true}
          post={postToEdit}
          onConfirm={confirmEdit}
          onCancel={cancelEdit}
          confirming={confirmingEdit}
          error={editError}
        />
      )}
    </>
  );
};

export default PostsContainer;