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, getCatName, getToastMessage} 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";
import {useTranslation} from "react-i18next";


let lastRefresh = "";

export function MemberList({source}) {
    const {hash} = useLocation();
    const navigate = useNavigate();
    const {t} = useTranslation();

    const [memberData, setMemberData] = useState([]);
    const [licenceData, setLicenceData] = useState([]);
    const [showLicenceState, setShowLicenceState] = useState((sessionStorage.getItem("showLicenceState") || "false") === "true");

    const setFilter = (filter) => {
        navigate("#" + encodeURI(JSON.stringify(filter)))
    }
    const filter = {
        page: 1,
        search: "",
        club: "",
        licenceRequest: 4,
        payment: 2,
        order: "",
        categorie: "",
        archived: false,
        ...JSON.parse(decodeURI(hash.substring(1)) || "{}"),
    }

    const setLoading = useLoadingSwitcher()
    const {
        data,
        error,
        refresh
    } = useFetch(`/member/find/${source}?page=${filter.page}&search=${filter.search}&club=${filter.club}&licenceRequest=${filter.licenceRequest}&payment=${filter.payment}&order=${filter.order}&categorie=${filter.categorie}&archive=${filter.archived}`, setLoading, 1)

    useEffect(() => {
        const tmp = `/member/find/${source}?page=${filter.page}&search=${filter.search}&club=${filter.club}&licenceRequest=${filter.licenceRequest}&payment=${filter.payment}&order=${filter.order}&categorie=${filter.categorie}&archive=${filter.archived}`;
        if (tmp === lastRefresh)
            return;
        lastRefresh = tmp
        refresh(lastRefresh);
    }, [hash]);

    useEffect(() => {
        if (!data)
            return;
        if (data.page_count < filter.page) {
            setFilter({...filter, page: 1});
        }

        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(() => {
        sessionStorage.setItem("showLicenceState", showLicenceState);
        if (!showLicenceState)
            return;

        toast.promise(
            apiAxios.get(`/licence/current/${source}`), getToastMessage("membre.toast.licences.load"))
            .then(data => {
                setLicenceData(data.data);
            });
    }, [showLicenceState]);

    const search = (search) => {
        if (search === filter.search)
            return;
        setFilter({...filter, search: search});
    }

    return <>
        <div>
            <div className="row">
                <div className="col-lg-9">
                    <SearchBar search={search} defaultValue={filter.search}/>
                    {data
                        ? <MakeCentralPanel data={data} visibleMember={memberData} navigate={navigate} showLicenceState={showLicenceState}
                                            page={filter.page} setPage={e => setFilter({...filter, page: e})} 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")}>{t('ajouterUnMembre')}</button>
                        {source === "admin" &&
                            <button className="btn btn-primary" onClick={() => navigate("validate")}
                                    style={{marginTop: "0.5rem"}}>{t('validerDesLicences')}</button>}
                        {source === "club" && false && // TODO: enable when payment is ready
                            <button className="btn btn-primary" onClick={() => navigate("pay")}
                                    style={{marginTop: "0.5rem"}}>{t('paiementDesLicences')}</button>}
                    </div>

                    <div className="card mb-4">
                        <div className="card-header">{t('trie')}</div>
                        <div className="card-body">
                            <OrderBar onOrderChange={e => setFilter({...filter, order: e.join(",")})} defaultValues={filter.order} source={source}/>
                        </div>
                    </div>

                    <div className="card mb-4">
                        <div className="card-header">{t('filtre')}</div>
                        <div className="card-body">
                            <FiltreBar showLicenceState={showLicenceState}
                                       setShowLicenceState={setShowLicenceState}
                                       showArchived={filter.archived}
                                       setShowArchived={e => setFilter({...filter, archived: e})}
                                       clubFilter={filter.club}
                                       setClubFilter={e => setFilter({...filter, club: e})}
                                       source={source}
                                       stateFilter={filter.licenceRequest}
                                       setStateFilter={e => setFilter({...filter, licenceRequest: e})}
                                       paymentFilter={filter.payment}
                                       setPaymentFilter={e => setFilter({...filter, payment: e})}
                                       catFilter={filter.categorie}
                                       setCatFilter={e => setFilter({...filter, categorie: e})}/>
                        </div>
                    </div>

                    {source === "club" &&
                        <div className="card mb-4">
                            <div className="card-header">{t('gestionGroupée')}</div>
                            <div className="card-body">
                                <FileOutput/>
                                <div style={{marginTop: "1.5em"}}></div>
                                <FileInput/>
                            </div>
                        </div>}
                </div>
            </div>
        </div>
    </>
}

function FileOutput() {
    const {t} = useTranslation();
    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`), getToastMessage("membre.toast.licences.export"))
            .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]) : '',
                    }

                    if (isNaN(tmp.certifDate) || tmp.certifDate === 'NaN') {
                        tmp.certifDate = ''
                    }

                    //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('téléchargerLexcelDesMembres')}</button>
            <small>{t('téléchargerLexcelDesMembres.info')}</small>
        </div>
    );
}


function FileInput() {
    const {t} = useTranslation();
    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(t('membre.nomVideàLaLigne', {no: i + 2}))
                    error++;
                }
                if (tmp.prenom === undefined || tmp.prenom === "") {
                    toast.error(t('membre.prénomVideàLaLigne', {no: i + 2}))
                    error++;
                }

                if (tmp.licenceCurrent) { // need check full data
                    if (tmp.email === undefined || tmp.email === "") {
                        toast.error(t('membre.emailVideàLaLigne', {no: i + 2}))
                        error++;
                    }
                    if (!re.test(tmp.email)) {
                        toast.error(t('membre.import.err5', {no: 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(t('membre.import.err1', {no: 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(t('membre.import.err2', {no: i + 2}))
                            error++;
                        }
                    }

                    if (tmp.birthdate === undefined || tmp.birthdate === "") {
                        toast.error(t('membre.import.err3', {no: i + 2}))
                        error++;
                    }
                }

                if (tmp.birthdate !== undefined && tmp.birthdate !== "") {
                    console.log(tmp.birthdate);
                    try {
                        tmp.birthdate = excelDateToJSDate(tmp.birthdate).toISOString();
                    } catch (e) {
                        toast.error(t('membre.import.err4', {no: i + 2}))
                        error++;
                    }
                }

                dataOut.push(tmp)
            }

            if (error > 0) {
                toast.error(t('membre.import.errTT', {count: error}))
            } else {
                console.log(dataOut);

                toast.promise(
                    apiAxios.put(`/member/club/import`, dataOut), getToastMessage("membre.toast.licences.import")
                ).then(_ => {
                    if (cetifNotFill > 0)
                        toast.warn(t('membre.import.warn', {count: cetifNotFill}))
                })
            }
        };

        reader.readAsBinaryString(file);
    };

    return (
        <div>
            <span>{t('chargerLexcel')}</span>
            <div className="input-group">
                <input type="file" className="form-control" id="logo" name="logo" accept=".xls,.xlsx" onChange={handleFileUpload}/>
            </div>
            <small>{t('chargerLexcel.msg')}</small>
        </div>
    );
}

function MakeCentralPanel({data, visibleMember, navigate, showLicenceState, page, setPage, source}) {
    const {t} = useTranslation();

    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={() => setPage(i)}>{i}</span>
        </li>);
    }

    return <>
        <div className="mb-4">
            <small>{t("page_info_full", {
                line: ((page - 1) * data.page_size) + 1,
                tt_line: (page * data.page_size > data.result_count) ? data.result_count : (page * data.page_size),
                page: page,
                tt_page: 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={() => setPage(page - 1)}>&laquo;</span></li>
                    {pages}
                    <li className={"page-item" + ((page >= data.page_count) ? " disabled" : "")}>
                        <span className="page-link" onClick={() => setPage(page + 1)}>&raquo;</span></li>
                </ul>
            </nav>
        </div>
    </>
}

function MakeRow({member, showLicenceState, navigate, source}) {
    const rowContent = <>
        <div className="row" style={{padding: "0.6em 0"}}>
            <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>
        <div style={{verticalAlign: "center", margin: "auto 0"}}>
            {source === "club" ?
                <small>{getCatName(member.categorie)}</small>
                : <div style={{
                    textAlign: "right",
                    fontSize: "small"
                }}>{member.club?.name || "Sans club"}<br/><small>{getCatName(member.categorie)}</small></div>}
        </div>

    </>

    if (showLicenceState && member.licence != null) {
        return <a 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"))}
                  style={{padding: "0 1em"}}
                  onClick={e => {
                      e.preventDefault();
                      navigate("" + member.id)
                  }}
                  href={"member/" + member.id}>
            {rowContent}
        </a>
    } else {
        return <a className="list-group-item d-flex justify-content-between align-items-start list-group-item-action"
                  style={{padding: "0 1em"}}
                  onClick={e => {
                      e.preventDefault();
                      navigate("" + member.id)
                  }}
                  href={"member/" + member.id}>
            {rowContent}
        </a>
    }
}

function OrderBar({onOrderChange, defaultValues = "", source}) {
    const {t} = useTranslation();
    const [orderCriteria, setOrderCriteria] = useState([...defaultValues.split(",").filter(c => c !== ''), '']);

    const handleChange = (index, value) => {
        const newCriteria = [...orderCriteria];
        newCriteria[index] = value;

        // Si le dernier critère est rempli, on en ajoute un nouveau
        if (index === orderCriteria.length - 1 && value !== '') {
            newCriteria.push('');
        }
        // Si un critère (sauf le premier) est réinitialisé, on le supprime
        else if (value === '' && (index !== 0 || orderCriteria.length > 1)) {
            newCriteria.splice(index, 1);
        }

        setOrderCriteria(newCriteria);
        onOrderChange(newCriteria.filter(c => c !== ''));
    };

    // Liste de toutes les options possibles
    const allOptions = [
        {value: 'lname n', label: t('nom') + ' ↓', base: 'lname'},
        {value: 'lname i', label: t('nom') + ' ↑', base: 'lname'},
        {value: 'fname n', label: t('prenom') + ' ↓', base: 'fname'},
        {value: 'fname i', label: t('prenom') + ' ↑', base: 'fname'},
        {value: 'categorie n', label: t('catégorie') + ' ↓', base: 'categorie'},
        {value: 'categorie i', label: t('catégorie') + ' ↑', base: 'categorie'},
        {value: 'licence n', label: t('licence') + ' ↓', base: 'licence'},
        {value: 'licence i', label: t('licence') + ' ↑', base: 'licence'},
    ];

    if (source === "admin") {
        allOptions.push(
            {value: 'club.name n', label: t('club', {count: 1}) + ' ↓', base: 'club.name'},
            {value: 'club.name i', label: t('club', {count: 1}) + ' ↑', base: 'club.name'},
        );
    }

    return (
        <div className="mb-3">
            {orderCriteria.map((criteria, index) => {
                // Récupère les bases des critères déjà sélectionnés (sauf le courant)
                const usedBases = orderCriteria
                    .filter((c, i) => c !== '' && i !== index)
                    .map(c => allOptions.find(o => o.value === c)?.base);

                // Filtre les options disponibles
                const availableOptions = allOptions.filter(option =>
                    !usedBases.includes(option.base) || option.value === criteria
                );

                return (
                    <select
                        key={index}
                        className="form-select mb-2"
                        value={criteria}
                        onChange={(e) => handleChange(index, e.target.value)}
                    >
                        <option value="">----</option>
                        {availableOptions.map((option) => (
                            <option key={option.value} value={option.value}>
                                {option.label}
                            </option>
                        ))}
                    </select>
                );
            })}
        </div>
    );
}

function FiltreBar({
                       showLicenceState,
                       setShowLicenceState,
                       showArchived,
                       setShowArchived,
                       clubFilter,
                       setClubFilter,
                       source,
                       stateFilter,
                       setStateFilter,
                       paymentFilter,
                       setPaymentFilter,
                       catFilter,
                       setCatFilter,
                   }) {
    const {t} = useTranslation();

    return <div>
        <div className="mb-3">
            <Checkbox value={showLicenceState} onChange={setShowLicenceState} label={t('membre.filtre.licence')}/>
        </div>
        <div className="mb-3">
            <Checkbox value={showArchived} onChange={setShowArchived} name="checkbox2" label={t('membre.filtre.inactif')}/>
        </div>
        <div className="mb-3">
            <select className="form-select" value={catFilter} onChange={event => setCatFilter(event.target.value)}>
                <option value="">{t('---TouteLesCatégories---')}</option>
                {Tools.CatList.map(cat => (
                    <option key={cat} value={cat}>{getCatName(cat)}</option>
                ))}
            </select>
        </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}>{t('membre.filtre.licences.4')}</option>
                <option value={0}>{t('membre.filtre.licences.0')}</option>
                <option value={1}>{t('membre.filtre.licences.1')}</option>
                <option value={2}>{t('membre.filtre.licences.2')}</option>
                <option value={5}>{t('membre.filtre.licences.5')}</option>
                <option value={6}>{t('membre.filtre.licences.6')}</option>
                <option value={3}>{t('membre.filtre.licences.3')}</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}>{t('membre.filtre.payement.2')}</option>
                <option value={0}>{t('membre.filtre.payement.0')}</option>
                <option value={1}>{t('membre.filtre.payement.1')}</option>
            </select>
        </div>
    </div>
}

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

    return <>
        {data
            ? <div className="mb-3">
                <select className="form-select" value={clubFilter} onChange={event => setClubFilter(event.target.value)}>
                    <option value="">{t('---ToutLesClubs---')}</option>
                    <option value="null">{t('---SansClub---')}</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>
}
