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

<!--- Only allow from localhost --->
<cfif NOT (cgi.remote_addr EQ "127.0.0.1" OR cgi.remote_addr EQ "::1" OR findNoCase("localhost", cgi.server_name))>
    <cfoutput>#serializeJSON({"OK": false, "ERROR": "admin_only"})#</cfoutput>
    <cfabort>
</cfif>

<cfscript>
/**
 * Eliminate Categories Table - Schema Migration
 *
 * Final unified schema:
 *   - Everything is an Item with BusinessID
 *   - ParentID=0 items are either categories or templates (derived from usage)
 *   - Categories = items at ParentID=0 that have menu items as children
 *   - Templates = items at ParentID=0 that appear in lt_ItemID_TemplateItemID
 *   - Orphans = ParentID=0 items that are neither (cleanup candidates)
 *
 * Steps:
 * 1. Add BusinessID column to Items
 * 2. For each Category: create Item, re-parent menu items, set BusinessID
 * 3. Set BusinessID on templates based on linked items
 *
 * Query param: ?dryRun=1 to preview without making changes
 */

response = { "OK": false, "steps": [], "migrations": [], "dryRun": false };

try {
    dryRun = structKeyExists(url, "dryRun") && url.dryRun == 1;
    response["dryRun"] = dryRun;

    // Step 1: Add BusinessID column if it doesn't exist
    try {
        if (!dryRun) {
            queryExecute("
                ALTER TABLE Items ADD COLUMN BusinessID INT DEFAULT 0 AFTER ItemID
            ", {}, { datasource: "payfrit" });
        }
        arrayAppend(response.steps, "Added BusinessID column to Items table");
    } catch (any e) {
        if (findNoCase("Duplicate column", e.message)) {
            arrayAppend(response.steps, "BusinessID column already exists");
        } else {
            throw(e);
        }
    }

    // Step 2: Add index on BusinessID
    try {
        if (!dryRun) {
            queryExecute("
                CREATE INDEX idx_item_business ON Items (BusinessID)
            ", {}, { datasource: "payfrit" });
        }
        arrayAppend(response.steps, "Added index on BusinessID");
    } catch (any e) {
        if (findNoCase("Duplicate key name", e.message)) {
            arrayAppend(response.steps, "Index idx_item_business already exists");
        } else {
            arrayAppend(response.steps, "Index warning: " & e.message);
        }
    }

    // Step 3: Drop foreign key constraint on CategoryID if it exists
    try {
        if (!dryRun) {
            queryExecute("
                ALTER TABLE Items DROP FOREIGN KEY Items_ibfk_1
            ", {}, { datasource: "payfrit" });
        }
        arrayAppend(response.steps, "Dropped foreign key constraint Items_ibfk_1");
    } catch (any e) {
        if (findNoCase("check that column", e.message) || findNoCase("Can't DROP", e.message)) {
            arrayAppend(response.steps, "Foreign key Items_ibfk_1 already dropped or doesn't exist");
        } else {
            arrayAppend(response.steps, "FK warning: " & e.message);
        }
    }

    // Step 4: Get all Categories
    qCategories = queryExecute("
        SELECT ID, BusinessID, Name
        FROM Categories
        ORDER BY BusinessID, Name
    ", {}, { datasource: "payfrit" });

    arrayAppend(response.steps, "Found " & qCategories.recordCount & " categories to migrate");

    // Step 4: Migrate each category
    for (cat in qCategories) {
        migration = {
            "oldCategoryID": cat.ID,
            "categoryName": cat.Name,
            "businessID": cat.BusinessID,
            "newItemID": 0,
            "itemsUpdated": 0
        };

        if (!dryRun) {
            // Create new Item for this category (ParentID=0, no template flag needed)
            // Note: CategoryID set to 0 temporarily until we drop that column
            queryExecute("
                INSERT INTO Items (
                    BusinessID,
                    CategoryID,
                    Name,
                    Description,
                    ParentItemID,
                    Price,
                    IsActive,
                    IsCheckedByDefault,
                    RequiresChildSelection,
                    SortOrder,
                    AddedOn
                ) VALUES (
                    :businessID,
                    0,
                    :categoryName,
                    '',
                    0,
                    0,
                    1,
                    0,
                    0,
                    0,
                    NOW()
                )
            ", {
                businessID: cat.BusinessID,
                categoryName: cat.Name
            }, { datasource: "payfrit" });

            // Get the new Item ID
            qNewItem = queryExecute("
                SELECT ID FROM Items
                WHERE BusinessID = :businessID
                  AND Name = :categoryName
                  AND ParentItemID = 0
                ORDER BY ID DESC
                LIMIT 1
            ", {
                businessID: cat.BusinessID,
                categoryName: cat.Name
            }, { datasource: "payfrit" });

            newItemID = qNewItem.ID;
            migration["newItemID"] = newItemID;

            // Update menu items in this category:
            // - Set ParentItemID = newItemID (for top-level items only)
            // - Set BusinessID = businessID (for all items)
            queryExecute("
                UPDATE Items
                SET BusinessID = :businessID,
                    ParentItemID = :newItemID
                WHERE CategoryID = :categoryID
                  AND ParentItemID = 0
            ", {
                businessID: cat.BusinessID,
                newItemID: newItemID,
                categoryID: cat.ID
            }, { datasource: "payfrit" });

            // Set BusinessID on ALL items in this category (including nested)
            queryExecute("
                UPDATE Items
                SET BusinessID = :businessID
                WHERE CategoryID = :categoryID
                  AND (BusinessID IS NULL OR BusinessID = 0)
            ", {
                businessID: cat.BusinessID,
                categoryID: cat.ID
            }, { datasource: "payfrit" });

            // Count how many were updated
            qCount = queryExecute("
                SELECT COUNT(*) as cnt FROM Items
                WHERE ParentItemID = :newItemID
            ", { newItemID: newItemID }, { datasource: "payfrit" });

            migration["itemsUpdated"] = qCount.cnt;
        } else {
            // Dry run - count what would be updated
            qCount = queryExecute("
                SELECT COUNT(*) as cnt FROM Items
                WHERE CategoryID = :categoryID
                  AND ParentItemID = 0
            ", { categoryID: cat.ID }, { datasource: "payfrit" });

            migration["itemsToUpdate"] = qCount.cnt;
        }

        arrayAppend(response.migrations, migration);
    }

    // Step 5: Set BusinessID for templates (items in lt_ItemID_TemplateItemID)
    // Templates get their BusinessID from the items they're linked to
    if (!dryRun) {
        queryExecute("
            UPDATE Items t
            INNER JOIN lt_ItemID_TemplateItemID tl ON tl.TemplateItemID = t.ItemID
            INNER JOIN Items i ON i.ID = tl.ItemID
            SET t.BusinessID = i.BusinessID
            WHERE (t.BusinessID IS NULL OR t.BusinessID = 0)
              AND i.BusinessID > 0
        ", {}, { datasource: "payfrit" });

        arrayAppend(response.steps, "Set BusinessID on templates from linked items");

        // Set BusinessID on template children (options)
        queryExecute("
            UPDATE Items c
            INNER JOIN Items t ON t.ItemID = c.ParentItemID
            SET c.BusinessID = t.BusinessID
            WHERE t.BusinessID > 0
              AND (c.BusinessID IS NULL OR c.BusinessID = 0)
        ", {}, { datasource: "payfrit" });

        arrayAppend(response.steps, "Set BusinessID on template children");

        // Make sure templates have ParentID=0 (they live at top level)
        queryExecute("
            UPDATE Items t
            INNER JOIN lt_ItemID_TemplateItemID tl ON tl.TemplateItemID = t.ItemID
            SET t.ParentItemID = 0
            WHERE t.ParentItemID != 0
        ", {}, { datasource: "payfrit" });

        arrayAppend(response.steps, "Ensured templates have ParentItemID=0");
    }

    response["OK"] = true;

    if (dryRun) {
        arrayAppend(response.steps, "DRY RUN COMPLETE - No changes made. Run without ?dryRun=1 to execute.");
    } else {
        arrayAppend(response.steps, "MIGRATION COMPLETE - Categories converted to Items");
        arrayAppend(response.steps, "Run cleanupCategories.cfm to drop old columns/tables after verification");
    }

} catch (any e) {
    response["ERROR"] = e.message;
    response["DETAIL"] = e.detail;
}

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