package com.capgemini.reports.builder;

import com.capgemini.framework.common.StringHelper;
import com.capgemini.reports.database.javabean.enumeration.ReportCriteriaEnum;
import com.capgemini.reports.definition.r20report.Classe;
import com.capgemini.reports.definition.r20report.ConjointUnique;
import com.capgemini.reports.definition.r20report.ExecutionR20;
import com.capgemini.reports.definition.r20report.MajorMinor;
import com.capgemini.reports.exceptions.InsufficientParametersException;
import com.capgemini.reports.reports.parameters.ProductUnit;
import com.google.common.base.Joiner;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;

/** Builds a R20 Report from product/unit before & after, a String LMR list, plus various printing data. */
public class R20Builder implements ReportBuilder {

    private static final String NO_LMR = "-";

    @Override
    public ExecutionR20 build(Map<ReportCriteriaEnum, String> data) throws InsufficientParametersException {
        // Get the request raw data
        String productBefore = data.get(ReportCriteriaEnum.PRODUCT_BEFORE);
        String productAfter = data.get(ReportCriteriaEnum.PRODUCT_AFTER);
        String unitBeforeStr = data.get(ReportCriteriaEnum.UNIT_BEFORE);
        String unitAfterStr = data.get(ReportCriteriaEnum.UNIT_AFTER);
        String matricule = data.get(ReportCriteriaEnum.MATRICULE);
        String lmrStr = data.get(ReportCriteriaEnum.LMR);
        String classeStr = data.get(ReportCriteriaEnum.CLASSE);
        String majorMinorStr = data.get(ReportCriteriaEnum.MAJOR_MINOR);
        String conjointUniqueStr = data.get(ReportCriteriaEnum.CONJOINT_UNIQUE);

        // Check presence of all required args
        if (productBefore == null || productAfter == null || unitBeforeStr == null || unitAfterStr == null || lmrStr == null || classeStr == null
                || majorMinorStr == null || conjointUniqueStr == null) {
            String dataStr = Joiner.on('|').withKeyValueSeparator("=").useForNull("null").join(data);
            throw new InsufficientParametersException("Missing parameter for R20 launch. Obtained: " + dataStr);
        }

        // Replacing null optional values by empty
        if (matricule == null) {
            matricule = StringHelper.EMPTY;
        }

        // Present args in correct format
        int unitBefore;
        try {
            unitBefore = Integer.parseInt(unitBeforeStr);
        } catch (NumberFormatException e) {
            throw new InsufficientParametersException("Unit Before is not an int: " + unitBeforeStr, e);
        }
        int unitAfter;
        try {
            unitAfter = Integer.parseInt(unitAfterStr);
        } catch (NumberFormatException e) {
            throw new InsufficientParametersException("Unit After is not an int: " + unitAfterStr, e);
        }
        MajorMinor majorMinor = MajorMinor.parse(majorMinorStr);
        ProductUnit aProductUnitBefore = new ProductUnit(productBefore, unitBefore);
        ProductUnit aProductUnitAfter = new ProductUnit(productAfter, unitAfter);
        ConjointUnique conjointUnique = ConjointUnique.parse(conjointUniqueStr);
        Classe classe = Classe.parse(classeStr);
        List<String> lmr = unpackLMR(lmrStr);

        // Build the report
        return new ExecutionR20(aProductUnitBefore, aProductUnitAfter, matricule, lmr, classe, majorMinor, conjointUnique);
    }

    private static final String LMR_SEPARATOR = ";"; // A semicolon (;) character


    /**
     * Unpacks a {@link #packLMR(List) packed} LMR list from the DB back to a {@link List} of strings.
     * @param allLmrs a single String of all LMRs separated by a semicolon (or a simple dash if no LMR are found)
     * @return a {@link List} of {@link String} MOD names
     */
    private static List<String> unpackLMR(final String allLmrs) {
        List<String> lmrList = new ArrayList<>();
        if (allLmrs == null || allLmrs.isEmpty() || NO_LMR.equals(allLmrs)) {
            return lmrList;
        }
        String[] list = allLmrs.split(LMR_SEPARATOR);
        Collections.addAll(lmrList, list);
        return lmrList;
    }

    /**
     * Takes a List of String MOD names, packs it all in a single String to be saved to DB.<br>
     * Use {@link #unpackLMR(String)} to recover the original List.
     * @param lmr the {@link List} of MOD names, as {@link String}s
     * @return a single String with every LMR semicolon-separated (';'). If no LMRs, then outputs a dash '-'.
     */
    public static String packLMR(final List<String> lmr) {
        String strLmr = "";
        for (String aMod : lmr) {
            strLmr = aMod + LMR_SEPARATOR;
        }
        return strLmr.isEmpty() ? NO_LMR : strLmr;
    }

}
