<cfsetting showdebugoutput="false">
<cfcontent type="application/json; charset=utf-8">
<cfscript>
function readJsonBody() {
    var raw = getHttpRequestData().content;
    if (isNull(raw) || len(trim(raw)) == 0) return {};
    try {
        var data = deserializeJSON(raw);
        return isStruct(data) ? data : {};
    } catch (any e) {
        return {};
    }
}

try {
    data = readJsonBody();

    // Token can come from URL param or JSON body
    token = "";
    if (structKeyExists(url, "token")) token = trim(url.token);
    if (len(token) == 0 && structKeyExists(data, "token")) token = trim(data.token);

    if (len(token) == 0) {
        writeOutput(serializeJSON({ "OK": false, "ERROR": "missing_token", "MESSAGE": "Rating token is required." }));
        abort;
    }

    // Look up the rating by token
    qRating = queryExecute("
        SELECT r.*, t.Title,
               u_for.FirstName AS ForFirstName, u_for.LastName AS ForLastName,
               u_by.FirstName AS ByFirstName, u_by.LastName AS ByLastName
        FROM TaskRatings r
        JOIN Tasks t ON t.ID = r.TaskID
        LEFT JOIN Users u_for ON u_for.ID = r.ForUserID
        LEFT JOIN Users u_by ON u_by.ID = r.ByUserID
        WHERE r.AccessToken = ?
        LIMIT 1
    ", [{ value = token, cfsqltype = "cf_sql_varchar" }]);

    if (qRating.recordCount == 0) {
        writeOutput(serializeJSON({ "OK": false, "ERROR": "invalid_token", "MESSAGE": "Rating not found or link is invalid." }));
        abort;
    }

    // Check if expired
    if (qRating.ExpiresOn < now()) {
        writeOutput(serializeJSON({ "OK": false, "ERROR": "expired", "MESSAGE": "This rating link has expired." }));
        abort;
    }

    // Check if already completed
    if (len(trim(qRating.CompletedOn)) > 0) {
        writeOutput(serializeJSON({ "OK": false, "ERROR": "already_submitted", "MESSAGE": "This rating has already been submitted." }));
        abort;
    }

    // If GET request (or no rating data), return rating info for display
    isSubmission = structKeyExists(data, "onTime") || structKeyExists(data, "completedScope")
                || structKeyExists(data, "requiredFollowup") || structKeyExists(data, "continueAllow")
                || structKeyExists(data, "prepared") || structKeyExists(data, "respectful")
                || structKeyExists(data, "wouldAutoAssign");

    if (!isSubmission) {
        // Return rating details for UI to display
        result = {
            "OK": true,
            "RatingID": qRating.ID,
            "Direction": qRating.Direction,
            "Title": qRating.Title,
            "ForUserName": trim(qRating.ForFirstName & " " & qRating.ForLastName),
            "ExpiresOn": dateTimeFormat(qRating.ExpiresOn, "yyyy-mm-dd HH:nn:ss")
        };

        // Include appropriate questions based on direction
        if (qRating.Direction == "customer_rates_worker" || qRating.Direction == "admin_rates_worker") {
            result["Questions"] = {
                "onTime": "Was the worker on time?",
                "completedScope": "Was the scope completed?",
                "requiredFollowup": "Was follow-up required?",
                "continueAllow": "Continue to allow these tasks?"
            };
        } else if (qRating.Direction == "worker_rates_customer") {
            result["Questions"] = {
                "prepared": "Was the customer prepared?",
                "completedScope": "Was the scope clear?",
                "respectful": "Was the customer respectful?",
                "wouldAutoAssign": "Would you serve this customer again?"
            };
        }

        writeOutput(serializeJSON(result));
        abort;
    }

    // Process submission based on direction
    if (qRating.Direction == "customer_rates_worker" || qRating.Direction == "admin_rates_worker") {
        queryExecute("
            UPDATE TaskRatings SET
                OnTime = ?,
                CompletedScope = ?,
                RequiredFollowup = ?,
                ContinueAllow = ?,
                CompletedOn = NOW()
            WHERE ID = ?
        ", [
            { value = structKeyExists(data,"onTime") ? (data.onTime ? 1 : 0) : javaCast("null",""), cfsqltype = "cf_sql_tinyint", null = !structKeyExists(data,"onTime") },
            { value = structKeyExists(data,"completedScope") ? (data.completedScope ? 1 : 0) : javaCast("null",""), cfsqltype = "cf_sql_tinyint", null = !structKeyExists(data,"completedScope") },
            { value = structKeyExists(data,"requiredFollowup") ? (data.requiredFollowup ? 1 : 0) : javaCast("null",""), cfsqltype = "cf_sql_tinyint", null = !structKeyExists(data,"requiredFollowup") },
            { value = structKeyExists(data,"continueAllow") ? (data.continueAllow ? 1 : 0) : javaCast("null",""), cfsqltype = "cf_sql_tinyint", null = !structKeyExists(data,"continueAllow") },
            { value = qRating.ID, cfsqltype = "cf_sql_integer" }
        ]);
    } else if (qRating.Direction == "worker_rates_customer") {
        queryExecute("
            UPDATE TaskRatings SET
                Prepared = ?,
                CompletedScope = ?,
                Respectful = ?,
                WouldAutoAssign = ?,
                CompletedOn = NOW()
            WHERE ID = ?
        ", [
            { value = structKeyExists(data,"prepared") ? (data.prepared ? 1 : 0) : javaCast("null",""), cfsqltype = "cf_sql_tinyint", null = !structKeyExists(data,"prepared") },
            { value = structKeyExists(data,"completedScope") ? (data.completedScope ? 1 : 0) : javaCast("null",""), cfsqltype = "cf_sql_tinyint", null = !structKeyExists(data,"completedScope") },
            { value = structKeyExists(data,"respectful") ? (data.respectful ? 1 : 0) : javaCast("null",""), cfsqltype = "cf_sql_tinyint", null = !structKeyExists(data,"respectful") },
            { value = structKeyExists(data,"wouldAutoAssign") ? (data.wouldAutoAssign ? 1 : 0) : javaCast("null",""), cfsqltype = "cf_sql_tinyint", null = !structKeyExists(data,"wouldAutoAssign") },
            { value = qRating.ID, cfsqltype = "cf_sql_integer" }
        ]);
    }

    writeOutput(serializeJSON({
        "OK": true,
        "MESSAGE": "Rating submitted successfully. Thank you for your feedback!"
    }));

} catch (any e) {
    writeOutput(serializeJSON({
        "OK": false,
        "ERROR": "server_error",
        "MESSAGE": "Error submitting rating",
        "DETAIL": e.message
    }));
}
</cfscript>
