import { useFraction } from "~/composables/recipes";

const matchMixedFraction = /(?:\d*\s\d*\d*|0)\/\d*\d*/;
const matchFraction = /(?:\d*\d*|0)\/\d*\d*/;
const matchDecimal = /(\d+.\d+)|(.\d+)/;
const matchInt = /\d+/;



function extractServingsFromMixedFraction(fractionString: string): number | undefined {
    const mixedSplit = fractionString.split(/\s/);
    const wholeNumber = parseInt(mixedSplit[0]);
    const fraction = mixedSplit[1];

    const fractionSplit = fraction.split("/");
    const numerator = parseInt(fractionSplit[0]);
    const denominator = parseInt(fractionSplit[1]);

    if (denominator === 0) {
        return undefined;  // if the denominator is zero, just give up
    }
    else {
        return wholeNumber + (numerator / denominator);
    }
}

function extractServingsFromFraction(fractionString: string): number | undefined {
    const fractionSplit = fractionString.split("/");
    const numerator = parseInt(fractionSplit[0]);
    const denominator = parseInt(fractionSplit[1]);

    if (denominator === 0) {
        return undefined;  // if the denominator is zero, just give up
    }
    else {
        return numerator / denominator;
    }
}



function findMatch(yieldString: string): [matchString: string, servings: number, isFraction: boolean] | null {
    if (!yieldString) {
        return null;
    }

    const mixedFractionMatch = yieldString.match(matchMixedFraction);
    if (mixedFractionMatch?.length) {
        const match = mixedFractionMatch[0];
        const servings = extractServingsFromMixedFraction(match);

        // if the denominator is zero, return no match
        if (servings === undefined) {
            return null;
        } else {
            return [match, servings, true];
        }
    }

    const fractionMatch = yieldString.match(matchFraction);
    if (fractionMatch?.length) {
        const match = fractionMatch[0]
        const servings = extractServingsFromFraction(match);

        // if the denominator is zero, return no match
        if (servings === undefined) {
            return null;
        } else {
            return [match, servings, true];
        }
    }

    const decimalMatch = yieldString.match(matchDecimal);
    if (decimalMatch?.length) {
        const match = decimalMatch[0];
        return [match, parseFloat(match), false];
    }

    const intMatch = yieldString.match(matchInt);
    if (intMatch?.length) {
        const match = intMatch[0];
        return [match, parseInt(match), false];
    }

    return null;
}

function formatServings(servings: number, scale: number, isFraction: boolean): string {
    const val = servings * scale;
    if (Number.isInteger(val)) {
        return val.toString();
    } else if (!isFraction) {
        return (Math.round(val * 1000) / 1000).toString();
    }

    // convert val into a fraction string
    const { frac } = useFraction();

    let valString = "";
    const fraction = frac(val, 10, true);

    if (fraction[0] !== undefined && fraction[0] > 0) {
        valString += fraction[0];
    }

    if (fraction[1] > 0) {
        valString += ` ${fraction[1]}/${fraction[2]}`;
    }

    return valString.trim();
}


export function useExtractRecipeYield(yieldString: string | null, scale: number): string {
    if (!yieldString) {
        return "";
    }

    const match = findMatch(yieldString);
    if (!match) {
        return yieldString;
    }

    const [matchString, servings, isFraction] = match;

    const formattedServings = formatServings(servings, scale, isFraction);
    if (!formattedServings) {
        return yieldString  // this only happens with very weird or small fractions
    } else {
        return yieldString.replace(matchString, formatServings(servings, scale, isFraction));
    }
}
