<cfsetting showdebugoutput="false">
<cfsetting enablecfoutputonly="true">
<cfcontent type="application/json; charset=utf-8" reset="true">

<cfscript>
/**
 * Analyze Menu for Modifier Patterns
 *
 * Parses item descriptions to detect modifier groups and suggests
 * which templates should be created and applied.
 *
 * Detection patterns:
 * - Size variants: "Small available", "1/2 order available", "Small/Large"
 * - Protein choices: "With Chicken / With Steak or Shrimp"
 * - Required choices: "Boneless or bone in"
 * - Category-wide add-ons: "Add to any salad: ..."
 * - Price modifiers: "Add cheese +$0.50"
 *
 * POST JSON:
 * {
 *   "categories": [
 *     {
 *       "name": "Burgers",
 *       "categoryNote": "All burgers served with lettuce, tomato...",
 *       "items": [
 *         { "name": "Burger", "description": "Served with fries" }
 *       ]
 *     }
 *   ]
 * }
 *
 * Returns analyzed menu with detected modifiers and suggestions
 */

response = { "OK": false };

// Pattern definitions for modifier detection
patterns = {
    // Size patterns
    "size_small_available": {
        "regex": "(?i)\bsmall\s+(available|option)\b",
        "templateName": "Size",
        "options": [
            { "name": "Regular", "price": 0, "isDefault": true },
            { "name": "Small", "price": 0, "isDefault": false }
        ],
        "required": true,
        "maxSelections": 1
    },
    "size_half_available": {
        "regex": "(?i)\b(1/2|half)\s+(order\s+)?(available|option)\b",
        "templateName": "Size",
        "options": [
            { "name": "Full", "price": 0, "isDefault": true },
            { "name": "Half", "price": 0, "isDefault": false }
        ],
        "required": true,
        "maxSelections": 1
    },
    // Choice patterns (X or Y)
    "choice_or": {
        "regex": "(?i)\b(\w+)\s+or\s+(\w+)\b(?!\s+shrimp)",
        "templateName": "auto", // Will be generated from matched words
        "required": true,
        "maxSelections": 1
    },
    // Protein add-ons
    "protein_chicken_steak_shrimp": {
        "regex": "(?i)with\s+chicken\s*/?\s*(?:with\s+)?(?:steak\s+or\s+shrimp|steak\/shrimp)",
        "templateName": "Add Protein",
        "options": [
            { "name": "Plain", "price": 0, "isDefault": true },
            { "name": "With Chicken", "price": 0, "isDefault": false },
            { "name": "With Steak or Shrimp", "price": 0, "isDefault": false }
        ],
        "required": false,
        "maxSelections": 1
    },
    // Add-on with price
    "addon_with_price": {
        "regex": "(?i)add\s+(\w+(?:\s+\w+)?)\s*[\+\$]?\s*\.?(\d+(?:\.\d{2})?)",
        "templateName": "Add-ons",
        "required": false,
        "maxSelections": 0
    },
    // Category note patterns
    "salad_addons": {
        "regex": "(?i)add\s+(?:the\s+following\s+)?to\s+any\s+salad[:\s]+(.+)",
        "templateName": "Add Protein",
        "appliesTo": "category",
        "required": false,
        "maxSelections": 1
    }
};

try {
    requestBody = toString(getHttpRequestData().content);
    if (!len(requestBody)) {
        throw(message="No request body provided");
    }

    data = deserializeJSON(requestBody);
    categories = structKeyExists(data, "categories") ? data.categories : [];

    // Track detected templates and their usage
    detectedTemplates = {};
    itemModifiers = {}; // Maps item name to array of template IDs

    // Analyze each category
    analyzedCategories = [];

    for (cat in categories) {
        catName = cat.name;
        catNote = structKeyExists(cat, "categoryNote") ? cat.categoryNote : "";
        items = structKeyExists(cat, "items") ? cat.items : [];

        // Check for category-wide patterns in the note
        categoryTemplates = [];

        // Check for "Add to any salad" pattern
        if (reFindNoCase("add\s+(?:the\s+following\s+)?to\s+any\s+(salad|item)", catNote)) {
            // Extract the add-on items
            addOnMatch = reMatchNoCase("add[^:]+:\s*(.+)", catNote);
            if (arrayLen(addOnMatch)) {
                addOnText = addOnMatch[1];
                // Split by comma
                addOnItems = listToArray(addOnText, ",");
                templateID = "cat_" & lCase(reReplace(catName, "\W+", "_", "all")) & "_addons";

                if (!structKeyExists(detectedTemplates, templateID)) {
                    options = [{ "name": "None", "price": 0, "isDefault": true }];
                    for (addon in addOnItems) {
                        addon = trim(addon);
                        if (len(addon)) {
                            arrayAppend(options, { "name": addon, "price": 0, "isDefault": false });
                        }
                    }
                    detectedTemplates[templateID] = {
                        "id": templateID,
                        "name": "Add Protein",
                        "options": options,
                        "required": false,
                        "maxSelections": 1,
                        "detectedFrom": "Category note: " & catName,
                        "appliesTo": []
                    };
                }
                arrayAppend(categoryTemplates, templateID);
            }
        }

        // Analyze each item
        analyzedItems = [];
        for (item in items) {
            itemName = item.name;
            itemDesc = structKeyExists(item, "description") ? item.description : "";
            itemMods = [];

            // Apply category-wide templates
            for (catTmpl in categoryTemplates) {
                arrayAppend(itemMods, catTmpl);
                arrayAppend(detectedTemplates[catTmpl].appliesTo, itemName);
            }

            // Check for size patterns
            if (reFindNoCase("\bsmall\s*(available|option)?\b", itemDesc) ||
                reFindNoCase("\bsmall\b", itemName)) {
                templateID = "size_regular_small";
                if (!structKeyExists(detectedTemplates, templateID)) {
                    detectedTemplates[templateID] = {
                        "id": templateID,
                        "name": "Size",
                        "options": [
                            { "name": "Regular", "price": 0, "isDefault": true },
                            { "name": "Small", "price": 0, "isDefault": false }
                        ],
                        "required": true,
                        "maxSelections": 1,
                        "detectedFrom": "Pattern: 'Small available'",
                        "appliesTo": []
                    };
                }
                arrayAppend(itemMods, templateID);
                arrayAppend(detectedTemplates[templateID].appliesTo, itemName);
            }

            // Check for half order pattern
            if (reFindNoCase("\b(1/2|half)\s*(order)?\s*(available)?\b", itemDesc)) {
                templateID = "size_full_half";
                if (!structKeyExists(detectedTemplates, templateID)) {
                    detectedTemplates[templateID] = {
                        "id": templateID,
                        "name": "Size",
                        "options": [
                            { "name": "Full Order", "price": 0, "isDefault": true },
                            { "name": "Half Order", "price": 0, "isDefault": false }
                        ],
                        "required": true,
                        "maxSelections": 1,
                        "detectedFrom": "Pattern: '1/2 order available'",
                        "appliesTo": []
                    };
                }
                arrayAppend(itemMods, templateID);
                arrayAppend(detectedTemplates[templateID].appliesTo, itemName);
            }

            // Check for "boneless or bone in" pattern
            if (reFindNoCase("\bboneless\s+(or|/)\s*bone\s*-?\s*in\b", itemDesc)) {
                templateID = "wing_style";
                if (!structKeyExists(detectedTemplates, templateID)) {
                    detectedTemplates[templateID] = {
                        "id": templateID,
                        "name": "Style",
                        "options": [
                            { "name": "Bone-In", "price": 0, "isDefault": true },
                            { "name": "Boneless", "price": 0, "isDefault": false }
                        ],
                        "required": true,
                        "maxSelections": 1,
                        "detectedFrom": "Pattern: 'Boneless or bone in'",
                        "appliesTo": []
                    };
                }
                arrayAppend(itemMods, templateID);
                arrayAppend(detectedTemplates[templateID].appliesTo, itemName);
            }

            // Check for protein add-on pattern (With Chicken / With Steak or Shrimp)
            if (reFindNoCase("with\s+chicken.*(?:steak|shrimp)", itemDesc)) {
                templateID = "protein_addon";
                if (!structKeyExists(detectedTemplates, templateID)) {
                    detectedTemplates[templateID] = {
                        "id": templateID,
                        "name": "Add Protein",
                        "options": [
                            { "name": "Plain", "price": 0, "isDefault": true },
                            { "name": "With Chicken", "price": 0, "isDefault": false },
                            { "name": "With Steak or Shrimp", "price": 0, "isDefault": false }
                        ],
                        "required": false,
                        "maxSelections": 1,
                        "detectedFrom": "Pattern: 'With Chicken / With Steak or Shrimp'",
                        "appliesTo": []
                    };
                }
                arrayAppend(itemMods, templateID);
                arrayAppend(detectedTemplates[templateID].appliesTo, itemName);
            }

            // Check for "add X +$Y" pattern
            priceMatch = reMatchNoCase("add\s+(\w+(?:\s+(?:and\s+)?\w+)?)\s*[\.\+]?\s*(\d+(?:\.\d{2})?)", itemDesc);
            if (arrayLen(priceMatch)) {
                for (match in priceMatch) {
                    // Parse the match to get item name and price
                    parts = reMatchNoCase("add\s+(.+?)\s*[\.\+]?\s*(\d+(?:\.\d{2})?)\s*$", match);
                    if (arrayLen(parts)) {
                        templateID = "addon_" & lCase(reReplace(itemName, "\W+", "_", "all"));
                        if (!structKeyExists(detectedTemplates, templateID)) {
                            detectedTemplates[templateID] = {
                                "id": templateID,
                                "name": "Add-ons",
                                "options": [],
                                "required": false,
                                "maxSelections": 0,
                                "detectedFrom": "Pattern: 'Add X +$Y' in " & itemName,
                                "appliesTo": [],
                                "needsPricing": true
                            };
                        }
                        arrayAppend(itemMods, templateID);
                        arrayAppend(detectedTemplates[templateID].appliesTo, itemName);
                    }
                }
            }

            // Check for "with guacamole" type optional add-ons
            if (reFindNoCase("\bwith\s+guacamole\b", itemDesc)) {
                templateID = "addon_guacamole";
                if (!structKeyExists(detectedTemplates, templateID)) {
                    detectedTemplates[templateID] = {
                        "id": templateID,
                        "name": "Add Guacamole",
                        "options": [
                            { "name": "No Guacamole", "price": 0, "isDefault": true },
                            { "name": "Add Guacamole", "price": 0, "isDefault": false }
                        ],
                        "required": false,
                        "maxSelections": 1,
                        "detectedFrom": "Pattern: 'With guacamole'",
                        "appliesTo": [],
                        "needsPricing": true
                    };
                }
                arrayAppend(itemMods, templateID);
                arrayAppend(detectedTemplates[templateID].appliesTo, itemName);
            }

            // Store item with detected modifiers
            arrayAppend(analyzedItems, {
                "name": itemName,
                "description": itemDesc,
                "price": structKeyExists(item, "price") ? item.price : 0,
                "detectedModifiers": itemMods,
                "originalDescription": itemDesc
            });
        }

        arrayAppend(analyzedCategories, {
            "name": catName,
            "categoryNote": catNote,
            "items": analyzedItems,
            "categoryWideTemplates": categoryTemplates
        });
    }

    // Build template array sorted by usage count
    templateArray = [];
    for (key in detectedTemplates) {
        tmpl = detectedTemplates[key];
        tmpl["usageCount"] = arrayLen(tmpl.appliesTo);
        arrayAppend(templateArray, tmpl);
    }

    // Sort by usage count descending
    arraySort(templateArray, function(a, b) {
        return b.usageCount - a.usageCount;
    });

    // Generate questions for owner confirmation
    questions = [];

    // Question about detected templates
    if (arrayLen(templateArray)) {
        arrayAppend(questions, {
            "type": "confirm_templates",
            "question": "I detected these modifier groups. Are they correct?",
            "templates": templateArray
        });
    }

    // Question about items needing pricing
    itemsNeedingPrices = [];
    for (cat in analyzedCategories) {
        for (item in cat.items) {
            if (item.price == 0) {
                arrayAppend(itemsNeedingPrices, {
                    "category": cat.name,
                    "item": item.name
                });
            }
        }
    }

    if (arrayLen(itemsNeedingPrices)) {
        arrayAppend(questions, {
            "type": "pricing_needed",
            "question": "These items need prices:",
            "items": itemsNeedingPrices
        });
    }

    // Question about template options needing pricing
    templatesNeedingPrices = [];
    for (tmpl in templateArray) {
        if (structKeyExists(tmpl, "needsPricing") && tmpl.needsPricing) {
            arrayAppend(templatesNeedingPrices, {
                "templateId": tmpl.id,
                "templateName": tmpl.name,
                "appliesTo": tmpl.appliesTo
            });
        }
    }

    if (arrayLen(templatesNeedingPrices)) {
        arrayAppend(questions, {
            "type": "modifier_pricing_needed",
            "question": "These add-on options need prices:",
            "templates": templatesNeedingPrices
        });
    }

    response.OK = true;
    response.analyzedMenu = {
        "categories": analyzedCategories,
        "detectedTemplates": templateArray,
        "totalItems": 0,
        "totalTemplates": arrayLen(templateArray),
        "totalModifierLinks": 0
    };

    // Count totals
    totalItems = 0;
    totalLinks = 0;
    for (cat in analyzedCategories) {
        totalItems += arrayLen(cat.items);
        for (item in cat.items) {
            totalLinks += arrayLen(item.detectedModifiers);
        }
    }
    response.analyzedMenu.totalItems = totalItems;
    response.analyzedMenu.totalModifierLinks = totalLinks;

    response.questions = questions;
    response.summary = "Analyzed " & totalItems & " items, detected " & arrayLen(templateArray) & " modifier templates with " & totalLinks & " links";

} catch (any e) {
    response.error = e.message;
    if (len(e.detail)) {
        response.errorDetail = e.detail;
    }
}

writeOutput(serializeJSON(response));
</cfscript>
