/**
 * IMPORTANT !
 * Décommenter temporairement la ligne suivante (import { } from "./mock_jasmine")
 * Pour exécuter ce code dans le débugger.
 */
// import { describe, expect, it, xdescribe } from "../mock_jasmine";

import { MessageCode } from "../../src";
import { ParamCalculability } from "../../src/param/param-definition";
import { ParallelStructure } from "../../src/structure/parallel_structure";
import { Structure, StructureFlowMode, StructureFlowRegime } from "../../src/structure/structure";
import { LoiDebit, StructureType } from "../../src/structure/structure_props";
import { Result } from "../../src/util/result";
import { precDigits } from "../test_config";
import { checkResult } from "../test_func";

export function itCalcQ(
    struct: Structure, Z1: number, W: number, Q: number,
    mode?: StructureFlowMode, regime?: StructureFlowRegime, precDigits2?: number) {

    struct.debug("itCalQ " + struct.constructor.name + " Z1=" + Z1 + " W=" + W + " Q=" + Q);

    struct.prms.Z1.v = Z1;
    struct.prms.W.v = W;
    const res: Result = struct.Calc("Q");
    struct.debug("struct.Calc(Q)=" + res.vCalc);

    it("Q(Z1=" + Z1 + ",W=" + W + ") should be " + Q, () => {
        if (precDigits2 === undefined) { precDigits2 = precDigits; }
        struct.debug("struct.Calc(Q)=" + res.vCalc);
        expect(res.vCalc).toBeCloseTo(Q, precDigits2);
    });
    if (mode !== undefined) {
        it("Q(Z1=" + Z1 + ",W=" + W + ") Mode should be " + mode, () => {
            expect(res.extraResults.ENUM_StructureFlowMode).toBe(mode);
        });
    }
    if (regime !== undefined) {
        it("Q(Z1=" + Z1 + ",W=" + W + ") Regime should be " + regime, () => {
            expect(res.extraResults.ENUM_StructureFlowRegime).toBe(regime);
        });
    }
}

/**
 * Test de calcul de tous les paramètres d'une loi de débit
 * @param st Structure à tester
 * @param mode Mode d'écoulement
 * @param regime Régime d'écoulement
 * @param bNotZDV Loi de débit ne permettant pas de calculer ZDV
 */
export function testStructure(
    st: Structure,
    mode: StructureFlowMode,
    regime: StructureFlowRegime,
    bNotZDV: boolean = false
) {
    for (const prm of st.prms) {
        if ([ParamCalculability.DICHO, ParamCalculability.EQUATION].includes(prm.calculability)) {
            if (prm.symbol === "W" && prm.v === Infinity) {
                // Le calcul de l'ouverture sur les seuils doit renvoyer une exception (cas impossible)
                it(`Calc(${prm.symbol}) should return exception`, () => {
                    expect(
                        () => { st.Calc(prm.symbol); }
                    ).toThrow(new Error("Structure:Calc : Calcul de W impossible sur un seuil"));
                });
            } else {
                const ref: number = prm.v;
                const res: Result = st.Calc(prm.symbol);
                if (bNotZDV) {
                    // Les lois CEM88D et CUNGE80 ne font pas intervenir ZDV dans le calcul d'un orifice noyé
                    it(`Calc(${prm.symbol}) should return an error`, () => {
                        expect(
                            st.Calc(prm.symbol).code
                        ).toBe(MessageCode.ERROR_STRUCTURE_ZDV_PAS_CALCULABLE);
                    });
                } else {
                    // On ne teste pas le calcul de l'ouverture sur les seuils
                    it(`Calc(${prm.symbol}) should return ${ref}`, () => {
                        checkResult(res, ref);
                    });
                }
                prm.v = ref; // Go back to initial value for following tests
            }
        }
    }
}

/**
 * Test d'ouvrages en parallèle : calcul des débits individuels et test de tous les paramètres
 * @param oPS objet ParallelStructure à tester
 * @param iStTypes Liste ordonnée des types des ouvrages à tester
 * @param iLoiDebits Liste ordonnée des lois de débit à tester
 */
export function testParallelStructures(oPS: ParallelStructure, iStTypes: number[], iLoiDebits: number[]) {
    oPS.prms.Q.v = oPS.Calc("Q").vCalc;

    for (let i = 0; i < oPS.structures.length; i++) {
        const st: Structure = oPS.structures[i];
        describe(`this.structures[${i}]: ${StructureType[iStTypes[i]]} Structure${LoiDebit[iLoiDebits[i]]}: `, () => {
            // Tests sur les résultats complémentaires
            it(`Calc(Q).extraResults[${i}.Q] should return ${oPS.structures[i].Calc("Q").vCalc}`, () => {
                expect(
                    oPS.Calc("Q").extraResults[`ouvrage[${i}].Q`]
                ).toBe(
                    oPS.structures[i].Calc("Q").vCalc
                );
            });

            // Tests de calcul des paramètres des ouvrages
            for (const prm of st.prms) {
                if (
                    prm.calculability === ParamCalculability.DICHO &&
                    prm.symbol !== "Z1" && prm.symbol !== "Z2"
                ) {
                    const ref: number = prm.v;
                    if (prm.symbol === "W" && prm.v === Infinity) {
                        // Le calcul de l'ouverture sur les seuils doit renvoyer une exception (cas impossible)
                        it(`Calc(${prm.symbol}) should return exception`, () => {
                            expect(
                                () => { oPS.Calc({
                                    uid: oPS.structures[i].uid,
                                    symbol: prm.symbol
                                }); }
                            ).toThrow(new Error("Structure:Calc : Calcul de W impossible sur un seuil"));
                        });
                    } else if (
                        iStTypes[i] === StructureType.VanneRectangulaire &&
                        !oPS.structures[i].isZDVcalculable &&
                        prm.symbol === "ZDV"
                    ) {
                        // Les lois CEM88D et CUNGE80 ne font pas intervenir ZDV dans le calcul d'un orifice noyé
                        it(`Calc(${prm.symbol}) should return an error`, () => {
                            expect(
                                oPS.Calc({
                                    uid: oPS.structures[i].uid,
                                    symbol: prm.symbol
                                }).code
                            ).toBe(MessageCode.ERROR_STRUCTURE_ZDV_PAS_CALCULABLE);
                        });
                    } else if (
                        iLoiDebits[i] === LoiDebit.TriangularWeirFree &&
                        prm.symbol === "alpha2"
                    ) {
                        // Le calcul de l'angle de l'équation triangulaire n'est pas assez précis
                        it(`Calc(${prm.symbol}) should return ${ref}`, () => {
                            checkResult(oPS.Calc({
                                uid: oPS.structures[i].uid,
                                symbol: prm.symbol
                            }), ref, 1);
                        });
                    } else {
                        // Cas normal : On teste la valeur calculée
                        it(`Calc(${prm.symbol}) should return ${ref}`, () => {
                            checkResult(oPS.Calc({
                                uid: oPS.structures[i].uid,
                                symbol: prm.symbol
                            }), ref);
                        });
                    }
                    prm.v = ref; // Go back to initial value for following tests
                }
            }
        });
    }
}