import React, {useContext, useEffect, useMemo, useState} from "react";
import SearchBar from "../../SearchBar";
import {toast} from "react-toastify";
import {createElementAlert} from "../../Alert";
import PromotionForm from "../../Forms/PromotionForm";
import {Link} from "react-router-dom";
import {useHistory} from "react-router-dom";
import PromotionApi from "../../../Services/API/PromotionApi";
import {confirmAlert} from "react-confirm-alert";
import {checkUserIsConnectedOnError} from "../../../Services/API/errorsManager";
import {useTranslation} from "react-i18next";
import AddButton from "../../AddButton";
import {usePaginatedFetch} from "../../../Hooks/useFetch";
import Modal from "../../Modal";
import {checkRights} from "../../../Services/Functions/Rights/Rights";
import AtoUserRightsContext from "../../../Context/AtoUserRightsContext";
import LoadingModal from "../../LoadingModal";
import {getIri} from "../../../Services/Functions/functions";

const PromotionRow = ({promotion, onDelete, onEdit}) => {
    const {atoUserRights} = useContext(AtoUserRightsContext);

    const {t} = useTranslation("promotionList");

    const getStatus = (promotionFormation) => {
        switch (promotionFormation.status) {
            case "active":
                return <div className="badge badge-warning">{t("En cours")}</div>;
                break;
            case "suspended":
                return <div className="badge badge-secondary">{t("Suspendue")}</div>;
                break;
            case "archived":
                return <div className="badge badge-primary">{t("Archivée")}</div>;
                break;
        }
    }

    function handleDelete(e) {
        e.preventDefault();
        confirmAlert({
            title: t("Suppression de la promotion {{promotion.name}}", {promotion}),
            message: t(
                "Êtes-vous sûr(e) de vouloir supprimer la promotion ? \n Toutes les données seront supprimées. Cette action est irréversible."
            ),
            buttons: [
                {
                    className: "btnDelete",
                    label: t("Supprimer la promotion"),
                    onClick: () => onDelete(promotion),
                },
                {
                    label: t("Annuler"),
                },
            ],
        });
    }

    function handleClickEdit(e) {
        e.preventDefault();
        onEdit(promotion);
    }

    return (
        <tr key={promotion["@id"]}>
            <th>
                {(checkRights(atoUserRights, "students:view") && (
                        <Link to={"promotion/" + promotion.id}>{promotion.name}</Link>
                    )) ||
                    promotion.name}
            </th>
            <td>
                {(promotion?.formation && (
                    <Link
                        key={promotion?.formation.formation["@id"]}
                        to={"formations/" + promotion?.formation.formation.id}
                    >
                        {promotion?.formation.formation.name}
                    </Link>
                )) || <span className="text-danger">{t("Aucune formation")}</span>}
            </td>
            <td className="text-center">
                {new Date(promotion.createdAt).toLocaleString()}
            </td>
            <td className="text-center">{promotion.students.length}</td>
            <td className="text-center">{getStatus(promotion)}</td>
            <td>
                <div className="text-center row justify-content-around">
                    <div className="col">
                        {checkRights(atoUserRights, "students:view") && (
                            <Link to={"promotion/" + promotion.id} className={"text-primary"}>
                                <i className="icon-cursor text-primary"/>
                            </Link>
                        )}
                    </div>
                    <div className="col">
                        {promotion.status !== 'archived' && (
                            <button
                                onClick={handleClickEdit}
                                className="text-secondary link-style"
                            >
                                <i className="icon-pencil"/>
                            </button>
                        )}
                    </div>

                    <div className="col">
                        {" "}
                        {(!promotion.formation || !promotion.formation.formation.hasSession) && promotion.status !== 'archived' ? (
                            <button
                                className="mx-2 text-danger link-style"
                                onClick={handleDelete}
                            >
                                <i className="icon-trash text-danger"/>
                            </button>
                        ) : <></>}
                    </div>
                </div>
            </td>
        </tr>
    );
};

const PromotionList = ({ato, updateAto, userConnected, isAppAdmin}) => {
    const {t} = useTranslation("promotionList");
    const access = userConnected.appRoles[0].name;

    /* Load contexts */
    const {atoUserRights} = useContext(AtoUserRightsContext);

    /* States definition */
    const [filter, setFilter] = useState("");
    const [modalContent, setModalContent] = useState(null);
    const history = useHistory();
    const {
        loading,
        load,
        items: promotionList,
        setItems: setPromotionList,
        errors,
        clearAllErrors,
    } = usePaginatedFetch(PromotionApi.findByAto(ato.id, true));

    // Handlers
    async function handleSubmitPromotion(promotion) {
        // Check if promotion name doesn't already exists
        if (promotionList.find((pl) => pl.name === promotion.name && (getIri(promotion) === null || getIri(promotion) !== getIri(pl)))) {
            toast.error(t("Une promotion avec ce nom existe déjà"));
            return;
        }

        try {
            if (promotion["@id"]) {
                promotion.ato = getIri(promotion.ato);
                if (!promotion.formation) {
                    delete promotion.formation;
                } else {
                    promotion.formation = getIri(promotion.formation);
                }

                promotion.students = promotion.students.map((s) => getIri(s));

                const editedPromotion = await PromotionApi.edit(promotion);
                const updatedPromotionList = [...promotionList];
                updatedPromotionList.splice(
                    updatedPromotionList.findIndex(
                        (searchPromotion) =>
                            searchPromotion["@id"] === editedPromotion["@id"]
                    ),
                    1,
                    editedPromotion
                );
                setPromotionList(updatedPromotionList);
                toast.success(
                    t("La promotion {{promotion.name}} a bien été modifiée.", {
                        ns: "notification",
                        promotion,
                    })
                );
            } else {
                promotion.ato = promotion.ato["@id"];
                const newPromotion = await PromotionApi.create(promotion);
                setPromotionList((prevPromotionList) => [
                    ...prevPromotionList,
                    ...[newPromotion],
                ]);
                toast.success(
                    t("La promotion {{promotion.name}} a bien été créée.", {
                        ns: "notification",
                        promotion,
                    })
                );
            }
            setModalContent(null);
        } catch (e) {
            toast.error(
                t("Erreur lors de la création de la promotion.", {ns: "notification"})
            );
            console.error(e.response);
        }
    }

    function handleClickPromotionCreate(e) {
        e.preventDefault();
        setModalContent(<PromotionForm onsubmit={handleSubmitPromotion}/>);
    }

    function handlePromotionEdit(promotion) {
        setModalContent(
            <PromotionForm
                EditPromotion={promotion}
                onsubmit={handleSubmitPromotion}
            />
        );
    }

    async function handleDeleteClick(promotion) {
        const promotionListBackUp = [...promotionList];
        try {
            setPromotionList(promotionList.filter((p) => p.id !== promotion.id));
            if (await PromotionApi.remove(promotion)) {
                toast.success(
                    t("La promotion {{promotion.name}} a bien été supprimée.", {
                        promotion,
                    })
                );
            }
        } catch (e) {
            checkUserIsConnectedOnError(
                history,
                e,
                t("Erreur lors de la suppression de la promotion.", {
                    ns: "notification",
                })
            );
            setPromotionList(promotionListBackUp);
        }
    }

    // Memoized value
    const promotionsFilteredList = useMemo(() => {
        if (filter) {
            return promotionList.filter((p) =>
                p.name.toLowerCase().includes(filter.toLowerCase())
            );
        }
        return promotionList;
    }, [filter, promotionList]);

    /* Effects */
    useEffect(() => {
        load();
    }, [load]);

    useEffect(() => {
        if (access !== 'admin') {
            if (!checkRights(atoUserRights, 'All users:list')) {
                toast.error(t('Accès interdit', {ns: 'notification'}));
                history.goBack();
            }
        }
    }, [atoUserRights]); /* Check user rights */

    // Render
    return (
        <div>
            <LoadingModal isOpen={loading}>
                {t("Chargement des promotions")}
            </LoadingModal>
            {errors && (
                <Modal open={errors} onClose={clearAllErrors}>
                    <h1 className={"text-danger"}>
                        {t("Erreur lors du chargement des promotions")}
                    </h1>
                    <p>{errors["hydra:description"]}</p>
                </Modal>
            )}
            {modalContent && (
                <Modal
                    open={modalContent}
                    style={{minHeight: "70vh", minWidth: "50%"}}
                    onClose={() => setModalContent(null)}
                >
                    {modalContent}
                </Modal>
            )}
            <section>
                <div className="row justify-content-between align-items-center">
                    {(isAppAdmin || ((checkRights(atoUserRights, 'All users:create') || access === 'admin') && ato.status === 'active')) && (
                        <div className="col-auto mr-5 text-success">
                            <AddButton onclick={handleClickPromotionCreate}/>
                        </div>
                    )}
                    <div
                        style={{display: "flex", alignItems: "center", width: "100%"}}
                        className="col"
                        id="search-section"
                    >
                        <SearchBar value={filter} onChange={setFilter}/>
                    </div>
                </div>
            </section>
            <section>
                <table className="table">
                    <thead>
                    <tr>
                        <th>{t("Promotion")}</th>
                        <th>{t("Formation rattachée")}</th>
                        <th className="text-center">{t("Date de création")}</th>
                        <th className="text-center">{t("Nombre d'élèves")}</th>
                        <th className="text-center">{t("Statut")}</th>
                        <th className="text-center">{t("Options")}</th>
                    </tr>
                    </thead>
                    <tbody>
                    {(promotionsFilteredList.length > 0 &&
                        promotionsFilteredList.sort((a, b) => {
                            // Sort array by Active / Suspended / Archived
                            if (a.status === "active" && b.status !== "active") {
                                return -1
                            }
                            if (a.status === "suspended" && b.status !== "archived") {
                                return 0;
                            }

                            return 1;
                        }).map((p) => (
                            <PromotionRow
                                key={p.id}
                                promotion={p}
                                onDelete={handleDeleteClick}
                                onEdit={handlePromotionEdit}
                            />
                        ))) || (
                        <tr>
                            <td
                                colSpan={6}
                                className="text-danger text-center text-important"
                            >
                                {t("Aucune promotion dans votre base.")}
                            </td>
                        </tr>
                    )}
                    </tbody>
                </table>
            </section>
        </div>
    );
};

export default PromotionList;
