<cfsetting showdebugoutput="false">
<cfsetting enablecfoutputonly="true">
<cfcontent type="application/json; charset=utf-8" reset="true">
<cfheader name="Cache-Control" value="no-store">

<!---
  Avatar Upload/Get API

  GET: Returns avatar URL for authenticated user
  POST: Uploads new avatar image (multipart form data)

  Stores images as: /uploads/users/{UserID}.jpg
--->

<cfscript>
function apiAbort(required struct payload) {
  writeOutput(serializeJSON(payload));
  abort;
}

// Helper to get header value - use servlet request object (CGI scope doesn't expose custom HTTP headers in Lucee)
function getHeader(name) {
  try {
    req = getPageContext().getRequest();
    val = req.getHeader(arguments.name);
    if (!isNull(val)) return trim(val);
  } catch (any e) {
    // Fall back to CGI scope
    k = "HTTP_" & ucase(reReplace(arguments.name, "[^A-Za-z0-9]", "_", "all"));
    if (structKeyExists(cgi, k)) return trim(cgi[k]);
  }
  return "";
}

// Get authenticated user ID - try request scope first, then do our own token lookup
userId = 0;
debugInfo = {
  "requestUserID": structKeyExists(request, "UserID") ? request.UserID : "not_set",
  "headerToken": "",
  "tokenLookupResult": "not_attempted"
};

if (structKeyExists(request, "UserID") && isNumeric(request.UserID) && request.UserID > 0) {
  userId = request.UserID;
  debugInfo.source = "request_scope";
} else {
  // Do our own token lookup for multipart requests
  userToken = getHeader("X-User-Token");
  debugInfo.headerToken = len(userToken) ? left(userToken, 8) & "..." : "empty";

  if (len(userToken)) {
    try {
      qTok = queryExecute(
        "SELECT UserID FROM UserTokens WHERE Token = ? LIMIT 1",
        [ { value = userToken, cfsqltype = "cf_sql_varchar" } ],
        { datasource = "payfrit" }
      );
      debugInfo.tokenLookupResult = "found_#qTok.recordCount#_records";
      if (qTok.recordCount EQ 1) {
        userId = qTok.UserID;
        debugInfo.source = "token_lookup";
      }
    } catch (any e) {
      debugInfo.tokenLookupResult = "error: " & e.message;
    }
  }
}

if (userId <= 0) {
  apiAbort({ "OK": false, "ERROR": "not_logged_in", "MESSAGE": "Authentication required", "DEBUG": debugInfo });
}

// Use absolute path from web root
uploadsPath = expandPath("/uploads/users/");

// Check for avatar with various extensions (case-insensitive)
function findAvatarFile(basePath, userId) {
  extensions = ["jpg", "jpeg", "png", "gif", "webp", "JPG", "JPEG", "PNG", "GIF", "WEBP"];
  for (ext in extensions) {
    testPath = basePath & userId & "." & ext;
    if (fileExists(testPath)) {
      return { "exists": true, "path": testPath, "filename": userId & "." & ext };
    }
  }
  return { "exists": false, "path": basePath & userId & ".jpg", "filename": userId & ".jpg" };
}

avatarInfo = findAvatarFile(uploadsPath, userId);
avatarPath = avatarInfo.path;
avatarFilename = avatarInfo.filename;
avatarUrl = application.baseUrl & "/uploads/users/" & avatarFilename;

// Handle GET - return current avatar URL
if (cgi.REQUEST_METHOD == "GET") {
  hasAvatar = avatarInfo.exists;

  writeOutput(serializeJSON({
    "OK": true,
    "HAS_AVATAR": hasAvatar,
    "AVATAR_URL": hasAvatar ? (avatarUrl & "?t=" & getTickCount()) : ""
  }));
  abort;
}

// Handle POST - upload new avatar
if (cgi.REQUEST_METHOD == "POST") {
  try {
    // Check if file was uploaded
    if (!structKeyExists(form, "avatar") || !len(form.avatar)) {
      apiAbort({ "OK": false, "ERROR": "missing_file", "MESSAGE": "No avatar file provided" });
    }

    // Get uploaded file info
    uploadedFile = form.avatar;

    // Ensure uploads directory exists
    if (!directoryExists(uploadsPath)) {
      directoryCreate(uploadsPath);
    }

    // Process the upload
    uploadResult = fileUpload(
      destination = uploadsPath,
      fileField = "avatar",
      nameConflict = "overwrite",
      accept = "image/jpeg,image/png,image/gif,image/webp"
    );

    // Rename to userId.jpg (convert if needed)
    uploadedPath = uploadsPath & uploadResult.serverFile;

    // Read the image and save as JPEG
    try {
      img = imageRead(uploadedPath);

      // Resize if too large (max 500x500 for avatars)
      if (img.width > 500 || img.height > 500) {
        if (img.width > img.height) {
          imageScaleToFit(img, 500, "");
        } else {
          imageScaleToFit(img, "", 500);
        }
      }

      // Save as JPEG
      imageWrite(img, avatarPath, 0.85);

      // Delete original if different from target
      if (uploadedPath != avatarPath && fileExists(uploadedPath)) {
        fileDelete(uploadedPath);
      }

    } catch (any imgErr) {
      // If image processing fails, just rename the file
      if (uploadedPath != avatarPath) {
        if (fileExists(avatarPath)) {
          fileDelete(avatarPath);
        }
        fileMove(uploadedPath, avatarPath);
      }
    }

    writeOutput(serializeJSON({
      "OK": true,
      "MESSAGE": "Avatar uploaded successfully",
      "AVATAR_URL": avatarUrl & "?t=" & getTickCount()
    }));
    abort;

  } catch (any e) {
    apiAbort({
      "OK": false,
      "ERROR": "upload_error",
      "MESSAGE": "Failed to upload avatar",
      "DETAIL": e.message
    });
  }
}

// Unknown method
apiAbort({ "OK": false, "ERROR": "bad_method", "MESSAGE": "Use GET or POST" });
</cfscript>
