import {useLoadingSwitcher} from "../hooks/useLoading.jsx";
import {useFetch} from "../hooks/useFetch.js";
import {AxiosError} from "../components/AxiosError.jsx";
import {ThreeDots} from "react-loader-spinner";
import {useEffect, useState} from "react";
import {useLocation, useNavigate} from "react-router-dom";
import {Checkbox} from "../components/MemberCustomFiels.jsx";
import * as Tools from "../utils/Tools.js";
import {apiAxios, errFormater} from "../utils/Tools.js";
import {toast} from "react-toastify";
import {SearchBar} from "../components/SearchBar.jsx";
import * as XLSX from "xlsx-js-style";
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome";
import {faEuroSign} from "@fortawesome/free-solid-svg-icons";

export function MemberList({source}) {
    const {hash} = useLocation();
    const navigate = useNavigate();
    let page = Number(hash.substring(1));
    page = (page > 0) ? page : 1;

    const [memberData, setMemberData] = useState([]);
    const [licenceData, setLicenceData] = useState([]);
    const [showLicenceState, setShowLicenceState] = useState(false);
    const [clubFilter, setClubFilter] = useState("");
    const [stateFilter, setStateFilter] = useState(4)
    const [lastSearch, setLastSearch] = useState("");
    const [paymentFilter, setPaymentFilter] = useState(2);

    const setLoading = useLoadingSwitcher()
    const {data, error, refresh} = useFetch(`/member/find/${source}?page=${page}&licenceRequest=${stateFilter}&payment=${paymentFilter}`, setLoading, 1)


    useEffect(() => {
        refresh(`/member/find/${source}?page=${page}&search=${lastSearch}&club=${clubFilter}&licenceRequest=${stateFilter}&payment=${paymentFilter}`);
    }, [hash, clubFilter, stateFilter, lastSearch, paymentFilter]);

    useEffect(() => {
        if (!data)
            return;
        const data2 = [];
        for (const e of data.result) {
            data2.push({
                id: e.id,
                fname: e.fname,
                lname: e.lname,
                club: e.club,
                categorie: e.categorie,
                licence_number: e.licence,
                licence: showLicenceState ? licenceData.find(licence => licence.membre === e.id) : null
            })
        }
        setMemberData(data2);
    }, [data, licenceData]);

    useEffect(() => {
        if (!showLicenceState)
            return;

        toast.promise(
            apiAxios.get(`/licence/current/${source}`),
            {
                pending: "Chargement des licences...",
                success: "Licences chargées",
                error: {
                    render({data}) {
                        return errFormater(data, "Impossible de charger les licences")
                    }
                }
            })
            .then(data => {
                setLicenceData(data.data);
            });
    }, [showLicenceState]);

    const search = (search) => {
        if (search === lastSearch)
            return;
        setLastSearch(search);
    }

    return <>
        <div>
            <div className="row">
                <div className="col-lg-9">
                    <SearchBar search={search}/>
                    {data
                        ? <MakeCentralPanel data={data} visibleMember={memberData} navigate={navigate} showLicenceState={showLicenceState}
                                            page={page} source={source}/>
                        : error
                            ? <AxiosError error={error}/>
                            : <Def/>
                    }
                </div>
                <div className="col-lg-3">
                    <div className="mb-4">
                        <button className="btn btn-primary" onClick={() => navigate("new")}>Ajouter un membre</button>
                        {source === "admin" &&
                            <button className="btn btn-primary" onClick={() => navigate("validate")} style={{marginTop: "0.5rem"}}>Valider des
                                licences</button>}
                        {source === "club" && false && // TODO: enable when payment is ready
                            <button className="btn btn-primary" onClick={() => navigate("pay")} style={{marginTop: "0.5rem"}}>Paiement des
                                licences</button>}
                    </div>
                    <div className="card mb-4">
                        <div className="card-header">Filtre</div>
                        <div className="card-body">
                            <FiltreBar showLicenceState={showLicenceState} setShowLicenceState={setShowLicenceState} data={data}
                                       clubFilter={clubFilter} setClubFilter={setClubFilter} source={source}
                                       stateFilter={stateFilter} setStateFilter={setStateFilter} paymentFilter={paymentFilter}
                                       setPaymentFilter={setPaymentFilter}/>
                        </div>
                    </div>

                    {source === "club" &&
                        <div className="card mb-4">
                            <div className="card-header">Gestion groupée</div>
                            <div className="card-body">
                                <FileOutput/>
                                <div style={{marginTop: "1.5em"}}></div>
                                <FileInput/>
                            </div>
                        </div>}
                </div>
            </div>
        </div>
    </>
}

function FileOutput() {
    function formatColumnDate(worksheet, col) {
        const range = XLSX.utils.decode_range(worksheet['!ref'])
        // note: range.s.r + 1 skips the header row
        for (let row = range.s.r + 1; row <= range.e.r; ++row) {
            const ref = XLSX.utils.encode_cell({r: row, c: col})
            if (worksheet[ref] && worksheet[ref].t === "n") {
                worksheet[ref].v = Math.trunc(worksheet[ref].v)
            } else {
                worksheet[ref].t = "n"
            }
            worksheet[ref].z = "dd/mm/yyyy"
        }
    }

    const handleFileDownload = () => {
        toast.promise(
            apiAxios.get(`/member/club/export`),
            {
                pending: "Exportation des licences...",
                success: "Licences exportées",
                error: {
                    render({data}) {
                        return errFormater(data, "Impossible d'exporté les licences")
                    }
                }
            })
            .then(data => {
                const dataOut = []
                for (const e of data.data) {
                    const tmp = {
                        licence: e.licence,
                        nom: e.nom,
                        prenom: e.prenom,
                        email: e.email,
                        genre: e.genre,
                        birthdate: new Date(e.birthdate),
                        licenceCurrent: e.licenceCurrent ? 'X' : '',
                        certif: e.certif ? e.certif.split("¤")[0] : '',
                        certifDate: e.certif ? new Date(e.certif.split("¤")[1]) : '',
                    }

                    //tmp.birthdate.setMilliseconds(0);
                    //tmp.birthdate.setSeconds(0);
                    //tmp.birthdate.setMinutes(0);
                    //tmp.birthdate.setHours(0);
//
                    //console.log(tmp.birthdate);
                    dataOut.push(tmp)
                }

                const wb = XLSX.utils.book_new();
                const ws = XLSX.utils.json_to_sheet(dataOut);
                XLSX.utils.sheet_add_aoa(ws, [["Licence", "Nom", "Prénom", "Email", "Genre", "Date de naissance", "Licence en cours", "Nom médecin certificat", "Date certificat"]], {origin: 'A1'});
                // XLSX.utils.sheet_add_json(ws, dataOut, {skipHeader: true, origin: 'A2'});

                formatColumnDate(ws, 5)
                formatColumnDate(ws, 8)
                console.log(ws)
                //ws["!data"][0][0].z = "yyyy-mm-dd hh:mm:ss"
                ws["!cols"] = [{wch: 7}, {wch: 16}, {wch: 16}, {wch: 30}, {wch: 9}, {wch: 12}, {wch: 6}, {wch: 13}, {wch: 12}]

                XLSX.utils.book_append_sheet(wb, ws, `Saison ${Tools.getSaison()}-${Tools.getSaison() + 1}`);
                XLSX.writeFile(wb, "output.xlsx");
            });
    };

    return (
        <div>
            <button className="btn btn-primary" onClick={handleFileDownload}>Télécharger l'Excel des membres</button>
            <small>À utiliser comme template pour mettre à jour les informations</small>
        </div>
    );
}


function FileInput() {
    const re = /^(([^<>()[\].,;:\s@"]+(\.[^<>()[\].,;:\s@"]+)*)|(".+"))@(([^<>()[\].,;:\s@"]+\.)+[^<>()[\].,;:\s@"]{2,})$/i;

    function excelDateToJSDate(serial) {
        const utcDays = Math.floor(serial - 25569);
        const utcValue = utcDays * 86400;
        return new Date(utcValue * 1000);
    }

    const handleFileUpload = (e) => {
        const file = e.target.files[0];
        const reader = new FileReader();

        reader.onload = (event) => {
            const workbook = XLSX.read(event.target.result, {type: 'binary'});
            const sheet = workbook.Sheets[`Saison ${Tools.getSaison()}-${Tools.getSaison() + 1}`];
            const sheetData = XLSX.utils.sheet_to_json(sheet);

            const dataOut = []
            let error = 0;
            let cetifNotFill = 0;
            for (let i = 0; i < sheetData.length; i++) {
                const line = sheetData[i];
                // noinspection NonAsciiCharacters,JSNonASCIINames
                const tmp = {
                    licence: line["Licence"],
                    nom: line["Nom"],
                    prenom: line["Prénom"],
                    email: line["Email"],
                    genre: line["Genre"],
                    birthdate: line["Date de naissance"],
                    licenceCurrent: line["Licence en cours"] === undefined ? false : line["Licence en cours"].toLowerCase() === "x",
                    certif: "",
                }

                if (tmp.nom === undefined || tmp.nom === "") {
                    toast.error("Nom vide à la ligne " + (i + 2))
                    error++;
                }
                if (tmp.prenom === undefined || tmp.prenom === "") {
                    toast.error("Prénom vide à la ligne " + (i + 2))
                    error++;
                }

                if (tmp.licenceCurrent) { // need check full data
                    if (tmp.email === undefined || tmp.email === "") {
                        toast.error("Email vide à la ligne " + (i + 2))
                        error++;
                    }
                    if (!re.test(tmp.email)) {
                        toast.error("Email invalide à la ligne " + (i + 2))
                        error++;
                    }
                    // noinspection NonAsciiCharacters,JSNonASCIINames
                    if (line["Nom médecin certificat"] === undefined || line["Nom médecin certificat"] === "" ||
                        line["Date certificat"] === undefined || line["Date certificat"] === "") {
                        cetifNotFill++;
                    } else {
                        try {
                            const date = excelDateToJSDate(line["Date certificat"]);
                            if (Number.isNaN(date.getFullYear())) {
                                toast.error("Format de la date de certificat invalide à la ligne " + (i + 2))
                                error++;
                            } else {
                                // noinspection JSNonASCIINames
                                tmp.certif = line["Nom médecin certificat"] + "¤" + date.getFullYear() + "-" + ("0" + (date.getMonth() + 1)).slice(-2) + "-" + ("0" + date.getDate()).slice(-2);
                            }
                        } catch (e) {
                            toast.error("Format de la date de certificat invalide à la ligne " + (i + 2))
                            error++;
                        }
                    }

                    if (tmp.birthdate === undefined || tmp.birthdate === "") {
                        toast.error("Date de naissance vide à la ligne " + (i + 2))
                        error++;
                    }
                }

                if (tmp.birthdate !== undefined && tmp.birthdate !== "") {
                    console.log(tmp.birthdate);
                    try {
                        tmp.birthdate = excelDateToJSDate(tmp.birthdate).toISOString();
                    } catch (e) {
                        toast.error("Format de la date de naissance invalide à la ligne " + (i + 2))
                        error++;
                    }
                }

                dataOut.push(tmp)
            }

            if (error > 0) {
                toast.error(`${error} erreur(s) dans le fichier, opération annulée`)
            } else {
                console.log(dataOut);

                toast.promise(
                    apiAxios.put(`/member/club/import`, dataOut),
                    {
                        pending: "Envoie des changement en cours",
                        success: "Changement envoyé avec succès 🎉",
                        error: {
                            render({data}) {
                                return errFormater(data, "Échec de l'envoie des changements")
                            }
                        }
                    }
                ).then(_ => {
                    if (cetifNotFill > 0)
                        toast.warn(`${cetifNotFill} certificat(s) médical(aux) non rempli(s)`)
                })
            }
        };

        reader.readAsBinaryString(file);
    };

    return (
        <div>
            <span>Charger l'Excel</span>
            <div className="input-group">
                <input type="file" className="form-control" id="logo" name="logo" accept=".xls,.xlsx" onChange={handleFileUpload}/>
            </div>
            <small>Merci d'utiliser le fichier ci-dessus comme base, ne pas renommer les colonnes ni modifier les n° de licences.</small>
        </div>
    );
}

function MakeCentralPanel({data, visibleMember, navigate, showLicenceState, page, source}) {
    const pages = []
    for (let i = 1; i <= data.page_count; i++) {
        pages.push(<li key={i} className={"page-item " + ((page === i) ? "active" : "")}>
            <span className="page-link" onClick={() => navigate("#" + i)}>{i}</span>
        </li>);
    }

    return <>
        <div className="mb-4">
            <small>Ligne {((page - 1) * data.page_size) + 1} à {
                (page * data.page_size > data.result_count) ? data.result_count : (page * data.page_size)} (page {page} sur {data.page_count})</small>
            <div className="list-group">
                {visibleMember.map(member => (
                    <MakeRow key={member.id} member={member} navigate={navigate} showLicenceState={showLicenceState} source={source}/>))}
            </div>
        </div>
        <div className="mb-4">
            <nav aria-label="Page navigation">
                <ul className="pagination justify-content-center">
                    <li className={"page-item" + ((page <= 1) ? " disabled" : "")}>
                        <span className="page-link" onClick={() => navigate("#" + (page - 1))}>&laquo;</span></li>
                    {pages}
                    <li className={"page-item" + ((page >= data.page_count) ? " disabled" : "")}>
                        <span className="page-link" onClick={() => navigate("#" + (page + 1))}>&raquo;</span></li>
                </ul>
            </nav>
        </div>
    </>
}

function MakeRow({member, showLicenceState, navigate, source}) {
    const rowContent = <>
        <div className="row">
            <span className="col-auto">{(member.licence_number ? String(member.licence_number).padStart(5, '0') : "-------") + "   "}
                {(showLicenceState && member.licence != null && member.licence.pay)? <FontAwesomeIcon icon={faEuroSign}/> : <>&nbsp;&nbsp;</>}</span>
            <div className="ms-2 col-auto">
                <div className="fw-bold">{member.fname} {member.lname}</div>
            </div>
        </div>
        {source === "club" ?
            <small>{member.categorie}</small>
            : <small>{member.club?.name || "Sans club"}</small>}
    </>

    if (showLicenceState && member.licence != null) {
        return <div
            className={"list-group-item d-flex justify-content-between align-items-start list-group-item-action list-group-item-"
                + (member.licence.validate ? "success" : (member.licence.certificate.length > 1 ? "warning" : "danger"))}
            onClick={() => navigate("" + member.id)}>{rowContent}</div>
    } else {
        return <div className="list-group-item d-flex justify-content-between align-items-start list-group-item-action"
                    onClick={() => navigate("" + member.id)}>
            {rowContent}
        </div>
    }
}

let allClub = []

function FiltreBar({showLicenceState, setShowLicenceState, data, clubFilter, setClubFilter, source, stateFilter, setStateFilter, paymentFilter, setPaymentFilter}) {
    useEffect(() => {
        if (!data)
            return;
        allClub.push(...data.result.map((e) => e.club?.name))
        allClub = allClub.filter((value, index, self) => self.indexOf(value) === index).filter(value => value != null).sort()
    }, [data]);

    return <div>
        <div className="mb-3">
            <Checkbox value={showLicenceState} onChange={setShowLicenceState} label="Afficher l'état des licences"/>
        </div>
        {source !== "club" && <ClubSelectFilter clubFilter={clubFilter} setClubFilter={setClubFilter}/>}
        <div className="mb-3">
            <select className="form-select" value={stateFilter} onChange={event => setStateFilter(Number(event.target.value))}>
                <option value={4}>Tout les états de licences</option>
                <option value={0}>Sans demande ni licence validée</option>
                <option value={1}>Avec demande ou licence validée</option>
                <option value={2}>Demande en cours</option>
                <option value={5}>Demande complet</option>
                <option value={6}>Demande incomplet</option>
                <option value={3}>Licence validée</option>
            </select>
        </div>
        <div className="mb-3">
            <select className="form-select" value={paymentFilter} onChange={event => setPaymentFilter(Number(event.target.value))}
                    hidden={stateFilter === 0 || stateFilter === 4}>
                <option value={2}>Tout les états de paiement</option>
                <option value={0}>Sans paiement</option>
                <option value={1}>Avec paiement</option>
            </select>
        </div>
    </div>
}

function ClubSelectFilter({clubFilter, setClubFilter}) {
    const setLoading = useLoadingSwitcher()
    const {data, error} = useFetch(`/club/no_detail`, setLoading, 1)

    return <>
        {data
            ? <div className="mb-3">
                <select className="form-select" value={clubFilter} onChange={event => setClubFilter(event.target.value)}>
                    <option value="">--- tout les clubs ---</option>
                    <option value="null">--- sans club ---</option>
                    {data.map(club => (<option key={club.id} value={club.name}>{club.name}</option>))}
                </select>
            </div>
            : error
                ? <AxiosError error={error}/>
                : <Def/>
        }
    </>
}

function Def() {
    return <div className="list-group">
        <li className="list-group-item"><ThreeDots/></li>
        <li className="list-group-item"><ThreeDots/></li>
        <li className="list-group-item"><ThreeDots/></li>
        <li className="list-group-item"><ThreeDots/></li>
        <li className="list-group-item"><ThreeDots/></li>
    </div>
}
