package com.aiosman.ravenow.data.api

import com.aiosman.ravenow.data.AccountFavourite
import com.aiosman.ravenow.data.AccountFollow
import com.aiosman.ravenow.data.AccountLike
import com.aiosman.ravenow.data.AccountNotice
import com.aiosman.ravenow.data.AccountProfile
import com.aiosman.ravenow.data.Agent
import com.aiosman.ravenow.data.Comment
import com.aiosman.ravenow.data.DataContainer
import com.aiosman.ravenow.data.ListContainer
import com.aiosman.ravenow.data.Moment
import com.aiosman.ravenow.data.RecommendationsResponse
import com.aiosman.ravenow.data.Room
import com.aiosman.ravenow.entity.ChatNotification
import com.aiosman.ravenow.data.membership.MembershipConfigData
import com.aiosman.ravenow.data.membership.ValidateData
import com.aiosman.ravenow.data.membership.ValidateProductRequestBody
import com.google.gson.annotations.SerializedName
import okhttp3.MultipartBody
import okhttp3.RequestBody
import retrofit2.Response
import retrofit2.http.Body
import retrofit2.http.DELETE
import retrofit2.http.GET
import retrofit2.http.Multipart
import retrofit2.http.PATCH
import retrofit2.http.POST
import retrofit2.http.Part
import retrofit2.http.Path
import retrofit2.http.Query

data class RegisterRequestBody(
    @SerializedName("username")
    val username: String,
    @SerializedName("password")
    val password: String
)
data class AgentMomentRequestBody(
    @SerializedName("generateText")
    val generateText: String,
    @SerializedName("sessionId")
    val sessionId: String
)

data class SingleChatRequestBody(
    @SerializedName("agentOpenId")
    val agentOpenId: String? = null,
    @SerializedName("agentTrtcId")
    val agentTrtcId: String? = null,
)

data class GroupChatRequestBody(
    @SerializedName("trtcGroupId")
    val trtcGroupId: String,
)


data class SendChatAiRequestBody(
    @SerializedName("trtcGroupId")
    val trtcGroupId: String? = null,
    @SerializedName("fromTrtcUserId")
    val fromTrtcUserId: String? = null,
    @SerializedName("toTrtcUserId")
    val toTrtcUserId: String? = null,
    @SerializedName("message")
    val message: String,
    @SerializedName("skipTrtc")
    val skipTrtc: Boolean? = true,

)


data class CreateGroupChatRequestBody(
    @SerializedName("name")
    val name: String,
    @SerializedName("userIds")
    val userIds: List<String>,
    @SerializedName("promptIds")
    val promptIds: List<String>,
    )

data class JoinGroupChatRequestBody(
    @SerializedName("trtcId")
    val trtcId: String? = null,
    @SerializedName("roomId")
    val roomId: Int? = null,
)

data class BatchTrtcUserIdRequestBody(
    @SerializedName("trtcUserIds")
    val trtcUserIds: List<String>,
    @SerializedName("includeAI")
    val includeAI: Boolean? = null,
)

data class LoginUserRequestBody(
    @SerializedName("username")
    val username: String? = null,
    @SerializedName("password")
    val password: String? = null,
    @SerializedName("googleId")
    val googleId: String? = null,
    @SerializedName("captcha")
    val captcha: CaptchaInfo? = null,
)

data class GuestLoginRequestBody(
    @SerializedName("deviceID")
    val deviceId: String,
    @SerializedName("platform")
    val platform: String = "android",
    @SerializedName("deviceInfo")
    val deviceInfo: String? = null,
    @SerializedName("userAgent")
    val userAgent: String? = null,
    @SerializedName("ipAddress")
    val ipAddress: String? = null
)

data class GoogleRegisterRequestBody(
    @SerializedName("idToken")
    val idToken: String
)

data class AuthResult(
    @SerializedName("code")
    val code: Int,
    @SerializedName("expire")
    val expire: String,
    @SerializedName("token")
    val token: String
)

data class ValidateTokenResult(
    @SerializedName("id")
    val id: Int,
)

data class CommentRequestBody(
    @SerializedName("content")
    val content: String,
    @SerializedName("parentCommentId")
    val parentCommentId: Int? = null,
    @SerializedName("replyUserId")
    val replyUserId: Int? = null,
    @SerializedName("replyCommentId")
    val replyCommentId: Int? = null,
)

data class ChangePasswordRequestBody(
    @SerializedName("currentPassword")
    val oldPassword: String = "",
    @SerializedName("newPassword")
    val newPassword: String = ""
)

data class UpdateNoticeRequestBody(
    @SerializedName("lastLookLikeTime")
    val lastLookLikeTime: String? = null,
    @SerializedName("lastLookFollowTime")
    val lastLookFollowTime: String? = null,
    @SerializedName("lastLookFavoriteTime")
    val lastLookFavouriteTime: String? = null
)

data class RegisterMessageChannelRequestBody(
    @SerializedName("client")
    val client: String,
    @SerializedName("identifier")
    val identifier: String,
)

data class UnRegisterMessageChannelRequestBody(
    @SerializedName("client")
    val client: String,
    @SerializedName("identifier")
    val identifier: String,
)
data class ResetPasswordRequestBody(
    @SerializedName("username")
    val username: String,
)

data class UpdateUserLangRequestBody(
    @SerializedName("language")
    val lang: String,
    @SerializedName("timeOffset")
    val timeOffset: Int,
    @SerializedName("timezone")
    val timezone: String,
)

data class TrtcSignResponseBody(
    @SerializedName("sig")
    val sig: String,
    @SerializedName("userId")
    val userId: String,
)

data class AppConfig(
    @SerializedName("trtcAppId")
    val trtcAppId: Int,
)

data class DictItem(
    @SerializedName("key")
    val key: String,
    @SerializedName("value")
    val value: Any,
    @SerializedName("desc")
    val desc: String,
)

data class CaptchaRequestBody(
    @SerializedName("source")
    val source: String,
)

data class CaptchaResponseBody(
    @SerializedName("id")
    val id: Int,
    @SerializedName("thumb_base64")
    val thumbBase64: String,
    @SerializedName("master_base64")
    val masterBase64: String,
    @SerializedName("count")
    val count: Int,
)

data class CheckLoginCaptchaRequestBody(
    @SerializedName("username")
    val username: String,
)

data class GenerateLoginCaptchaRequestBody(
    @SerializedName("username")
    val username: String,
)

data class DotPosition(
    @SerializedName("index")
    val index: Int,
    @SerializedName("x")
    val x: Int,
    @SerializedName("y")
    val y: Int,
)

data class CaptchaInfo(
    @SerializedName("id")
    val id: Int,
    @SerializedName("dot")
    val dot: List<DotPosition>
)


data class UpdateChatNotificationRequestBody(
    @SerializedName("targetUserId")
    val targetUserId: Int,
    @SerializedName("strategy")
    val strategy: String,
)


data class CreateReportRequestBody(
    @SerializedName("reportType")
    val reportType: String,
    @SerializedName("reportId")
    val reportId: Int,
    @SerializedName("reason")
    val reason: Int,
    @SerializedName("extra")
    val extra: String,
    @SerializedName("base64Images")
    val base64Images: List<String>,
)

data class RemoveAccountRequestBody(
    @SerializedName("password")
    val password: String,
)

// ========== Room Member Management 相关数据类 ==========

/**
 * 添加用户到房间请求体
 * @param roomId 房间ID（与trtcId互斥，二者必须提供其一）
 * @param trtcId TRTC群组ID（与roomId互斥，二者必须提供其一）
 * @param openIds 要添加的用户OpenID列表
 */
data class AddUserToRoomRequestBody(
    @SerializedName("roomId")
    val roomId: Int? = null,
    @SerializedName("trtcId")
    val trtcId: String? = null,
    @SerializedName("openIds")
    val openIds: List<String>
)

/**
 * 添加智能体到房间请求体
 * @param roomId 房间ID（与trtcId互斥，二者必须提供其一）
 * @param trtcId TRTC群组ID（与roomId互斥，二者必须提供其一）
 * @param agentOpenIds 要添加的智能体OpenID列表
 */
data class AddAgentToRoomRequestBody(
    @SerializedName("roomId")
    val roomId: Int? = null,
    @SerializedName("trtcId")
    val trtcId: String? = null,
    @SerializedName("agentOpenIds")
    val agentOpenIds: List<String>
)

/**
 * 从房间移除智能体请求体
 * @param roomId 房间ID（与trtcId互斥，二者必须提供其一）
 * @param trtcId TRTC群组ID（与roomId互斥，二者必须提供其一）
 * @param agentOpenIds 要移除的智能体OpenID列表
 */
data class RemoveAgentFromRoomRequestBody(
    @SerializedName("roomId")
    val roomId: Int? = null,
    @SerializedName("trtcId")
    val trtcId: String? = null,
    @SerializedName("agentOpenIds")
    val agentOpenIds: List<String>
)

/**
 * 从房间移除用户请求体
 * @param roomId 房间ID（与trtcId互斥，二者必须提供其一）
 * @param trtcId TRTC群组ID（与roomId互斥，二者必须提供其一）
 * @param userIds 要移除的用户ID列表（OpenID）
 */
data class RemoveUserFromRoomRequestBody(
    @SerializedName("roomId")
    val roomId: Int? = null,
    @SerializedName("trtcId")
    val trtcId: String? = null,
    @SerializedName("userIds")
    val userIds: List<String>
)

/**
 * 添加用户成功项目
 */
data class AddUserToRoomItem(
    @SerializedName("userId")
    val userId: String,
    @SerializedName("type")
    val type: String
)

/**
 * 添加用户失败项目
 */
data class AddUserToRoomFailedItem(
    @SerializedName("userId")
    val userId: String,
    @SerializedName("type")
    val type: String,
    @SerializedName("error")
    val error: String
)

/**
 * 添加用户到房间的结果
 */
data class AddUserToRoomResult(
    @SerializedName("totalCount")
    val totalCount: Int,
    @SerializedName("successCount")
    val successCount: Int,
    @SerializedName("failedCount")
    val failedCount: Int,
    @SerializedName("skippedCount")
    val skippedCount: Int,
    @SerializedName("successItems")
    val successItems: List<AddUserToRoomItem>,
    @SerializedName("failedItems")
    val failedItems: List<AddUserToRoomFailedItem>,
    @SerializedName("skippedItems")
    val skippedItems: List<AddUserToRoomItem>
)

/**
 * 添加用户到房间响应
 */
data class AddUserToRoomResponse(
    @SerializedName("message")
    val message: String,
    @SerializedName("operationType")
    val operationType: String,
    @SerializedName("result")
    val result: AddUserToRoomResult
)

/**
 * 添加智能体成功项目
 */
data class AddAgentToRoomItem(
    @SerializedName("agentOpenId")
    val agentOpenId: String,
    @SerializedName("type")
    val type: String
)

/**
 * 添加智能体失败项目
 */
data class AddAgentToRoomFailedItem(
    @SerializedName("agentOpenId")
    val agentOpenId: String,
    @SerializedName("type")
    val type: String,
    @SerializedName("error")
    val error: String
)

/**
 * 添加智能体到房间的结果
 */
data class AddAgentToRoomResult(
    @SerializedName("totalCount")
    val totalCount: Int,
    @SerializedName("successCount")
    val successCount: Int,
    @SerializedName("failedCount")
    val failedCount: Int,
    @SerializedName("skippedCount")
    val skippedCount: Int,
    @SerializedName("successItems")
    val successItems: List<AddAgentToRoomItem>,
    @SerializedName("failedItems")
    val failedItems: List<AddAgentToRoomFailedItem>,
    @SerializedName("skippedItems")
    val skippedItems: List<AddAgentToRoomItem>
)

/**
 * 添加智能体到房间响应
 */
data class AddAgentToRoomResponse(
    @SerializedName("message")
    val message: String,
    @SerializedName("operationType")
    val operationType: String,
    @SerializedName("result")
    val result: AddAgentToRoomResult
)

/**
 * 移除智能体成功项目
 */
data class RemoveAgentFromRoomItem(
    @SerializedName("agentOpenId")
    val agentOpenId: String,
    @SerializedName("type")
    val type: String
)

/**
 * 移除智能体失败项目
 */
data class RemoveAgentFromRoomFailedItem(
    @SerializedName("agentOpenId")
    val agentOpenId: String,
    @SerializedName("type")
    val type: String,
    @SerializedName("error")
    val error: String
)

/**
 * 从房间移除智能体的结果
 */
data class RemoveAgentFromRoomResult(
    @SerializedName("totalCount")
    val totalCount: Int,
    @SerializedName("successCount")
    val successCount: Int,
    @SerializedName("failedCount")
    val failedCount: Int,
    @SerializedName("skippedCount")
    val skippedCount: Int,
    @SerializedName("successItems")
    val successItems: List<RemoveAgentFromRoomItem>,
    @SerializedName("failedItems")
    val failedItems: List<RemoveAgentFromRoomFailedItem>,
    @SerializedName("skippedItems")
    val skippedItems: List<RemoveAgentFromRoomItem>
)

/**
 * 移除用户成功项目
 */
data class RemoveUserFromRoomItem(
    @SerializedName("userId")
    val userId: String,
    @SerializedName("type")
    val type: String
)

/**
 * 移除用户失败项目
 */
data class RemoveUserFromRoomFailedItem(
    @SerializedName("userId")
    val userId: String,
    @SerializedName("type")
    val type: String,
    @SerializedName("error")
    val error: String
)

/**
 * 从房间移除用户的结果
 */
data class RemoveUserFromRoomResult(
    @SerializedName("totalCount")
    val totalCount: Int,
    @SerializedName("successCount")
    val successCount: Int,
    @SerializedName("failedCount")
    val failedCount: Int,
    @SerializedName("skippedCount")
    val skippedCount: Int,
    @SerializedName("successItems")
    val successItems: List<RemoveUserFromRoomItem>,
    @SerializedName("failedItems")
    val failedItems: List<RemoveUserFromRoomFailedItem>,
    @SerializedName("skippedItems")
    val skippedItems: List<RemoveUserFromRoomItem>
)

// API 错误响应（用于加入房间等接口的错误处理）
data class ApiErrorResponse(
    @SerializedName("err")
    val error: String,
    @SerializedName("success")
    val success: Boolean
)

// 群聊中的用户信息
data class GroupChatUser(
    @SerializedName("ID")
    val id: Int,
    @SerializedName("CreatedAt")
    val createdAt: String,
    @SerializedName("UpdatedAt")
    val updatedAt: String,
    @SerializedName("DeletedAt")
    val deletedAt: String?,
    @SerializedName("userSessionId")
    val userSessionId: String,
    @SerializedName("sessions")
    val sessions: Any?, // 根据实际需要可以定义具体类型
    @SerializedName("prompts")
    val prompts: Any?, // 根据实际需要可以定义具体类型
    @SerializedName("isAgent")
    val isAgent: Boolean
)

// 智能体角色信息
data class GroupChatPrompt(
    @SerializedName("ID")
    val id: Int,
    @SerializedName("CreatedAt")
    val createdAt: String,
    @SerializedName("UpdatedAt")
    val updatedAt: String,
    @SerializedName("DeletedAt")
    val deletedAt: String?,
    @SerializedName("Title")
    val title: String,
    @SerializedName("Desc")
    val desc: String,
    @SerializedName("Value")
    val value: String,
    @SerializedName("Enable")
    val enable: Boolean,
    @SerializedName("UserSessions")
    val userSessions: Any?, // 根据实际需要可以定义具体类型
    @SerializedName("Avatar")
    val avatar: String,
    @SerializedName("AuthorId")
    val authorId: Int?,
    @SerializedName("Author")
    val author: Any?, // 根据实际需要可以定义具体类型
    @SerializedName("TokenCount")
    val tokenCount: Int,
    @SerializedName("OpenId")
    val openId: String,
    @SerializedName("Public")
    val public: Boolean,
    @SerializedName("BreakMode")
    val breakMode: Boolean,
    @SerializedName("DocNamespace")
    val docNamespace: String,
    @SerializedName("UseRag")
    val useRag: Boolean,
    @SerializedName("RagThreshold")
    val ragThreshold: Double,
    @SerializedName("WorkflowId")
    val workflowId: Int?,
    @SerializedName("Workflow")
    val workflow: Any?, // 根据实际需要可以定义具体类型
    @SerializedName("WorkflowInputs")
    val workflowInputs: Any?, // 根据实际需要可以定义具体类型
    @SerializedName("Source")
    val source: String,
    @SerializedName("categories")
    val categories: Any? // 根据实际需要可以定义具体类型
)

// 群聊详细信息响应
data class GroupChatResponse(
    @SerializedName("ID")
    val id: Int,
    @SerializedName("CreatedAt")
    val createdAt: String,
    @SerializedName("UpdatedAt")
    val updatedAt: String,
    @SerializedName("DeletedAt")
    val deletedAt: String?,
    @SerializedName("name")
    val name: String,
    @SerializedName("description")
    val description: String,
    @SerializedName("creatorId")
    val creatorId: Int,
    @SerializedName("creator")
    val creator: Any?, // 根据实际需要可以定义具体类型
    @SerializedName("trtcRoomId")
    val trtcRoomId: String,
    @SerializedName("trtcType")
    val trtcType: String,
    @SerializedName("cover")
    val cover: String,
    @SerializedName("avatar")
    val avatar: String,
    @SerializedName("recommendBanner")
    val recommendBanner: String,
    @SerializedName("isRecommended")
    val isRecommended: Boolean,
    @SerializedName("allowInHot")
    val allowInHot: Boolean,
    @SerializedName("users")
    val users: List<GroupChatUser>,
    @SerializedName("prompts")
    val prompts: List<GroupChatPrompt>,
    @SerializedName("source")
    val source: String
)


data class CategoryTranslation(
    @SerializedName("name")
    val name: String?,
    @SerializedName("description")
    val description: String?
)

data class CategoryTemplate(
    @SerializedName("id")
    val id: Int,
    @SerializedName("name")
    val name: String,
    @SerializedName("description")
    val description: String,
    @SerializedName("avatar")
    val avatar: String,
    @SerializedName("parentId")
    val parentId: Int?,
    @SerializedName("parent")
    val parent: CategoryTemplate?,
    @SerializedName("children")
    val children: List<CategoryTemplate>?,
    @SerializedName("sort")
    val sort: Int,
    @SerializedName("isActive")
    val isActive: Boolean,
    @SerializedName("promptCount")
    val promptCount: Int?,
    @SerializedName("createdAt")
    val createdAt: String,
    @SerializedName("updatedAt")
    val updatedAt: String,
    @SerializedName("translations")
    val translations: Map<String, CategoryTranslation>?
) {
    /**
     * 根据语言代码获取翻译后的名称，如果没有翻译则返回默认名称
     */
    fun getLocalizedName(lang: String): String {
        // 尝试获取完整的语言标记（如 "zh-CN"）
        val translation = translations?.get(lang)
        if (translation?.name != null && translation.name.isNotEmpty()) {
            return translation.name
        }
        
        // 如果没有找到，尝试语言代码的前缀（如 "zh"）
        val langPrefix = lang.split("-", "_").firstOrNull()
        if (langPrefix != null) {
            translations?.entries?.forEach { (key, value) ->
                if (key.startsWith(langPrefix) && value.name != null && value.name.isNotEmpty()) {
                    return value.name
                }
            }
        }
        
        // 如果没有翻译，返回默认名称
        return name
    }
    
    /**
     * 根据语言代码获取翻译后的描述，如果没有翻译则返回默认描述
     */
    fun getLocalizedDescription(lang: String): String {
        // 尝试获取完整的语言标记（如 "zh-CN"）
        val translation = translations?.get(lang)
        if (translation?.description != null && translation.description.isNotEmpty()) {
            return translation.description
        }
        
        // 如果没有找到，尝试语言代码的前缀（如 "zh"）
        val langPrefix = lang.split("-", "_").firstOrNull()
        if (langPrefix != null) {
            translations?.entries?.forEach { (key, value) ->
                if (key.startsWith(langPrefix) && value.description != null && value.description.isNotEmpty()) {
                    return value.description
                }
            }
        }
        
        // 如果没有翻译，返回默认描述
        return description
    }
}

data class CategoryListResponse(
    @SerializedName("page")
    val page: Int,
    @SerializedName("pageSize")
    val pageSize: Int,
    @SerializedName("total")
    val total: Int,
    @SerializedName("list")
    val list: List<CategoryTemplate>
)

// ========== Agent Rule 相关数据类 ==========

/**
 * 创建规则请求体
 * @param rule 规则内容，不能为空
 * @param promptId 智能体ID，与 openId 二选一，promptId 优先
 * @param openId 智能体的 OpenID（UUID格式），与 promptId 二选一
 */
data class CreateAgentRuleRequestBody(
    @SerializedName("rule")
    val rule: String,
    @SerializedName("promptId")
    val promptId: Int? = null,
    @SerializedName("openId")
    val openId: String? = null
)

/**
 * 修改规则请求体
 * @param id 规则ID，必填
 * @param rule 新的规则内容，不能为空
 * @param promptId 要更改关联的智能体ID（可选）
 * @param openId 要更改关联的智能体 OpenID（可选）
 */
data class UpdateAgentRuleRequestBody(
    @SerializedName("id")
    val id: Int,
    @SerializedName("rule")
    val rule: String,
    @SerializedName("promptId")
    val promptId: Int? = null,
    @SerializedName("openId")
    val openId: String? = null
)

/**
 * 规则关联的智能体信息
 * @param id 智能体ID
 * @param title 智能体标题
 * @param avatar 智能体头像URL
 */
data class AgentRuleAgent(
    @SerializedName("id")
    val id: Int,
    @SerializedName("title")
    val title: String,
    @SerializedName("avatar")
    val avatar: String
)

/**
 * 规则详情
 * @param id 规则ID
 * @param rule 规则内容
 * @param creator 创建者名称
 * @param creatorType 创建者类型（如 "user"）
 * @param scope 作用域（如 "personal"）
 * @param prompt 关联的智能体信息
 * @param createdAt 创建时间（ISO 8601 格式）
 * @param updatedAt 更新时间（ISO 8601 格式）
 */
data class AgentRule(
    @SerializedName("id")
    val id: Int,
    @SerializedName("rule")
    val rule: String,
    @SerializedName("creator")
    val creator: String,
    @SerializedName("creator_type")
    val creatorType: String,
    @SerializedName("scope")
    val scope: String,
    @SerializedName("prompt")
    val prompt: AgentRuleAgent,
    @SerializedName("created_at")
    val createdAt: String,
    @SerializedName("updated_at")
    val updatedAt: String
)

/**
 * 规则列表响应
 * @param page 当前页码
 * @param pageSize 每页数量
 * @param total 总记录数
 * @param list 规则列表
 */
data class AgentRuleListResponse(
    @SerializedName("page")
    val page: Int,
    @SerializedName("pageSize")
    val pageSize: Int,
    @SerializedName("total")
    val total: Int,
    @SerializedName("list")
    val list: List<AgentRule>
)

/**
 * 规则配额信息
 * @param promptId 智能体ID
 * @param promptTitle 智能体标题
 * @param baseMaxCount 基础条数限制（免费配额）
 * @param purchasedCount 用户购买的额外条数
 * @param totalMaxCount 总可用条数（基础+购买）
 * @param currentCount 当前已创建的规则条数
 * @param remainingCount 剩余可用条数
 * @param usagePercent 使用百分比（0-100）
 */
data class AgentRuleQuota(
    @SerializedName("promptId")
    val promptId: Int,
    @SerializedName("promptTitle")
    val promptTitle: String,
    @SerializedName("baseMaxCount")
    val baseMaxCount: Int,
    @SerializedName("purchasedCount")
    val purchasedCount: Int,
    @SerializedName("totalMaxCount")
    val totalMaxCount: Int,
    @SerializedName("currentCount")
    val currentCount: Int,
    @SerializedName("remainingCount")
    val remainingCount: Int,
    @SerializedName("usagePercent")
    val usagePercent: Double
)

// ========== Room Rule 相关数据类 ==========

/**
 * 创建房间规则请求体
 * @param rule 规则内容，不能为空
 * @param roomId 房间ID，与 trtcId 二选一
 * @param trtcId TRTC房间ID（字符串格式），与 roomId 二选一
 */
data class CreateRoomRuleRequestBody(
    @SerializedName("rule")
    val rule: String,
    @SerializedName("roomId")
    val roomId: Int? = null,
    @SerializedName("trtcId")
    val trtcId: String? = null
)

/**
 * 修改房间规则请求体
 * @param id 规则ID，必填
 * @param rule 新的规则内容，不能为空
 */
data class UpdateRoomRuleRequestBody(
    @SerializedName("id")
    val id: Int,
    @SerializedName("rule")
    val rule: String
)

/**
 * 房间规则创建者信息
 * @param id 创建者ID
 * @param nickname 创建者昵称
 * @param avatar 创建者头像文件名
 * @param avatarMedium 中等头像文件名
 * @param avatarLarge 大头像文件名
 * @param avatarDirectUrl 小头像直接访问URL
 * @param avatarMediumDirectUrl 中等头像直接访问URL
 * @param avatarLargeDirectUrl 大头像直接访问URL
 */
data class RoomRuleCreator(
    @SerializedName("id")
    val id: Int,
    @SerializedName("nickname")
    val nickname: String,
    @SerializedName("avatar")
    val avatar: String,
    @SerializedName("avatarMedium")
    val avatarMedium: String? = null,
    @SerializedName("avatarLarge")
    val avatarLarge: String? = null,
    @SerializedName("avatarDirectUrl")
    val avatarDirectUrl: String? = null,
    @SerializedName("avatarMediumDirectUrl")
    val avatarMediumDirectUrl: String? = null,
    @SerializedName("avatarLargeDirectUrl")
    val avatarLargeDirectUrl: String? = null
)

/**
 * 房间规则详情
 * @param id 规则ID
 * @param rule 规则内容
 * @param creator 创建者信息（可能为 null）
 * @param creatorType 创建者类型（如 "user"）
 * @param roomId 所属房间ID
 * @param createdAt 创建时间（ISO 8601 格式）
 * @param updatedAt 更新时间（ISO 8601 格式）
 */
data class RoomRule(
    @SerializedName("id")
    val id: Int,
    @SerializedName("rule")
    val rule: String,
    @SerializedName("creator")
    val creator: RoomRuleCreator?,
    @SerializedName("creatorType")
    val creatorType: String,
    @SerializedName("roomId")
    val roomId: Int,
    @SerializedName("createdAt")
    val createdAt: String,
    @SerializedName("updatedAt")
    val updatedAt: String
)

/**
 * 房间规则列表响应
 * @param page 当前页码
 * @param pageSize 每页数量
 * @param total 总记录数
 * @param list 规则列表
 */
data class RoomRuleListResponse(
    @SerializedName("page")
    val page: Int,
    @SerializedName("pageSize")
    val pageSize: Int,
    @SerializedName("total")
    val total: Long,
    @SerializedName("list")
    val list: List<RoomRule>
)

/**
 * 房间规则配额信息
 * @param baseMaxCount 基础条数限制（系统配置的免费配额）
 * @param purchasedCount 用户购买的额外条数（通过自动扩容机制）
 * @param totalMaxCount 总可用条数（baseMaxCount + purchasedCount）
 * @param currentCount 当前已创建的规则条数（该用户在该房间）
 * @param remainingCount 剩余可用条数（totalMaxCount - currentCount）
 * @param usagePercent 使用百分比（0-100）
 */
data class RoomRuleQuota(
    @SerializedName("baseMaxCount")
    val baseMaxCount: Int,
    @SerializedName("purchasedCount")
    val purchasedCount: Int,
    @SerializedName("totalMaxCount")
    val totalMaxCount: Int,
    @SerializedName("currentCount")
    val currentCount: Int,
    @SerializedName("remainingCount")
    val remainingCount: Int,
    @SerializedName("usagePercent")
    val usagePercent: Double
)

/**
 * 积分不足错误响应
 * 
 * 当创建房间规则时积分不足，服务器会返回此特殊错误格式。
 * 包含当前余额和所需金额信息，便于客户端提示用户。
 * 
 * @param success 是否成功，固定为 false
 * @param code 错误码，固定为 35600（积分不足）
 * @param message 错误消息，包含所需积分和当前余额的详细说明
 * @param err 错误类型，固定为 "InsufficientBalance"
 * @param currentBalance 当前积分余额
 * @param requiredAmount 所需积分数量
 * @param traceId 追踪ID（可选）
 */
data class InsufficientBalanceError(
    @SerializedName("success")
    val success: Boolean,
    @SerializedName("code")
    val code: Int,
    @SerializedName("message")
    val message: String,
    @SerializedName("err")
    val err: String,
    @SerializedName("currentBalance")
    val currentBalance: Int,
    @SerializedName("requiredAmount")
    val requiredAmount: Int,
    @SerializedName("traceId")
    val traceId: String?
)

// ========== Points 相关数据类 ==========

/**
 * 积分余额信息
 * @param balance 当前积分余额
 * @param totalEarned 累计获得积分（可选）
 * @param totalSpent 累计消费积分（可选）
 */
data class PointsBalance(
    @SerializedName("balance")
    val balance: Int,
    @SerializedName("totalEarned")
    val totalEarned: Int? = null,
    @SerializedName("totalSpent")
    val totalSpent: Int? = null
)

/**
 * 积分变更日志
 * @param id 日志记录ID
 * @param changeType 变更类型（add: 增加, subtract: 减少, adjust: 调整）
 * @param before 变更前余额
 * @param after 变更后余额
 * @param amount 本次变更数量（增加为正数，减少为负数）
 * @param reason 变更原因代码
 * @param createdAt 创建时间，格式：YYYY-MM-DD HH:mm:ss
 */
data class PointsChangeLog(
    @SerializedName("id")
    val id: Int,
    @SerializedName("changeType")
    val changeType: String,
    @SerializedName("before")
    val before: Int,
    @SerializedName("after")
    val after: Int,
    @SerializedName("amount")
    val amount: Int,
    @SerializedName("reason")
    val reason: String,
    @SerializedName("createdAt")
    val createdAt: String
)

/**
 * 积分变更日志列表响应
 * @param success 请求是否成功
 * @param list 积分变更日志列表
 * @param total 总记录数
 * @param page 当前页码
 * @param pageSize 每页数量
 */
data class PointsChangeLogsResponse(
    @SerializedName("success")
    val success: Boolean,
    @SerializedName("list")
    val list: List<PointsChangeLog>,
    @SerializedName("total")
    val total: Int,
    @SerializedName("page")
    val page: Int,
    @SerializedName("pageSize")
    val pageSize: Int
)

interface RaveNowAPI {
    @GET("membership/config")
    @retrofit2.http.Headers("X-Requires-Auth: true")
    suspend fun getMembershipConfig(): Response<DataContainer<MembershipConfigData>>

    @POST("membership/android/product/validate")
    @retrofit2.http.Headers("X-Requires-Auth: true")
    suspend fun validateAndroidProduct(
        @Body body: ValidateProductRequestBody
    ): Response<DataContainer<ValidateData>>
    @POST("register")
    suspend fun register(@Body body: RegisterRequestBody): Response<Unit>

    @POST("login")
    suspend fun login(@Body body: LoginUserRequestBody): Response<AuthResult>

    @POST("guest/login")
    suspend fun guestLogin(@Body body: GuestLoginRequestBody): Response<AuthResult>

    @GET("auth/token")
    suspend fun checkToken(): Response<ValidateTokenResult>

    @GET("auth/refresh_token")
    suspend fun refreshToken(
        @Query("token") token: String
    ): Response<AuthResult>

    @GET("posts")
    suspend fun getPosts(
        @Query("page") page: Int = 1,
        @Query("pageSize") pageSize: Int = 20,
        @Query("timelineId") timelineId: Int? = null,
        @Query("authorId") authorId: Int? = null,
        @Query("contentSearch") contentSearch: String? = null,
        @Query("postUser") postUser: Int? = null,
        @Query("trend") trend: String? = null,
        @Query("favouriteUserId") favouriteUserId: Int? = null,
        @Query("explore") explore: String? = null,
        @Query("newsFilter") newsFilter: String? = null,
        @Query("videoFilter") videoFilter: String? = null,
    ): Response<ListContainer<Moment>>

    @Multipart
    @POST("posts")
    suspend fun createPost(
        @Part image: List<MultipartBody.Part>,
        @Part("textContent") textContent: RequestBody,
    ): Response<DataContainer<Moment>>

    @GET("post/{id}")
    suspend fun getPost(
        @Path("id") id: Int
    ): Response<DataContainer<Moment>>

    @POST("post/{id}/like")
    suspend fun likePost(
        @Path("id") id: Int
    ): Response<Unit>

    @POST("post/{id}/dislike")
    suspend fun dislikePost(
        @Path("id") id: Int
    ): Response<Unit>

    @POST("post/{id}/favorite")
    suspend fun favoritePost(
        @Path("id") id: Int
    ): Response<Unit>

    @POST("post/{id}/unfavorite")
    suspend fun unfavoritePost(
        @Path("id") id: Int
    ): Response<Unit>

    @POST("post/{id}/comment")
    suspend fun createComment(
        @Path("id") id: Int,
        @Body body: CommentRequestBody
    ): Response<DataContainer<Comment>>

    @POST("comment/{id}/like")
    suspend fun likeComment(
        @Path("id") id: Int
    ): Response<Unit>

    @POST("comment/{id}/dislike")
    suspend fun dislikeComment(
        @Path("id") id: Int
    ): Response<Unit>

    @POST("comment/{id}/read")
    suspend fun updateReadStatus(
        @Path("id") id: Int
    ): Response<Unit>


    @GET("comments")
    suspend fun getComments(
        @Query("page") page: Int = 1,
        @Query("postId") postId: Int? = null,
        @Query("pageSize") pageSize: Int = 20,
        @Query("postUser") postUser: Int? = null,
        @Query("selfNotice") selfNotice: Int? = 0,
        @Query("order") order: String? = null,
        @Query("parentCommentId") parentCommentId: Int? = null,
    ): Response<ListContainer<Comment>>

    @GET("account/my")
    suspend fun getMyAccount(): Response<DataContainer<AccountProfile>>

    @Multipart
    @PATCH("account/my/profile")
    suspend fun updateProfile(
        @Part avatar: MultipartBody.Part?,
        @Part banner: MultipartBody.Part?,
        @Part("nickname") nickname: RequestBody?,
        @Part("bio") bio: RequestBody?,
    ): Response<Unit>

    @POST("account/my/password")
    suspend fun changePassword(
        @Body body: ChangePasswordRequestBody
    ): Response<Unit>

    @GET("account/my/notice/like")
    suspend fun getMyLikeNotices(
        @Query("page") page: Int = 1,
        @Query("pageSize") pageSize: Int = 20,
    ): Response<ListContainer<AccountLike>>

    @GET("account/my/notice/follow")
    suspend fun getMyFollowNotices(
        @Query("page") page: Int = 1,
        @Query("pageSize") pageSize: Int = 20,
    ): Response<ListContainer<AccountFollow>>

    @GET("account/my/notice/favourite")
    suspend fun getMyFavouriteNotices(
        @Query("page") page: Int = 1,
        @Query("pageSize") pageSize: Int = 20,
    ): Response<ListContainer<AccountFavourite>>

    @GET("account/my/notice")
    suspend fun getMyNoticeInfo(): Response<DataContainer<AccountNotice>>

    @POST("account/my/notice")
    suspend fun updateNoticeInfo(
        @Body body: UpdateNoticeRequestBody
    ): Response<Unit>

    @POST("account/my/messaging")
    suspend fun registerMessageChannel(
        @Body body: RegisterMessageChannelRequestBody
    ): Response<Unit>

    @POST("account/my/messaging/unregister")
    suspend fun unRegisterMessageChannel(
        @Body body: UnRegisterMessageChannelRequestBody
    ): Response<Unit>

    @GET("profile/{id}")
    suspend fun getAccountProfileById(
        @Path("id") id: Int
    ): Response<DataContainer<AccountProfile>>

    @GET("profile/trtc/{id}")
    suspend fun getAccountProfileByTrtcUserId(
        @Path("id") id: String,
        @Query("includeAI") includeAI: Int
    ): Response<DataContainer<AccountProfile>>


    @GET("profile/aichat/profile/{id}")
    suspend fun getAccountProfileByOpenId(
        @Path("id") id: String
    ): Response<DataContainer<AccountProfile>>

    @POST("profile/trtc/batch")
    suspend fun getAccountProfilesByTrtcBatch(
        @Body body: BatchTrtcUserIdRequestBody
    ): Response<DataContainer<List<AccountProfile>>>

    @POST("user/{id}/follow")
    suspend fun followUser(
        @Path("id") id: Int
    ): Response<Unit>

    @POST("user/{id}/unfollow")
    suspend fun unfollowUser(
        @Path("id") id: Int
    ): Response<Unit>

    @GET("users")
    suspend fun getUsers(
        @Query("page") page: Int = 1,
        @Query("pageSize") pageSize: Int = 20,
        @Query("nickname") search: String? = null,
        @Query("followerId") followerId: Int? = null,
        @Query("followingId") followingId: Int? = null,
        @Query("includeAI") includeAI: Boolean? = true,
        @Query("chatSessionIdNotNull") chatSessionIdNotNull: Boolean? = true,
    ): Response<ListContainer<AccountProfile>>

    @POST("register/google")
    suspend fun registerWithGoogle(@Body body: GoogleRegisterRequestBody): Response<AuthResult>

    @DELETE("post/{id}")
    suspend fun deletePost(
        @Path("id") id: Int
    ): Response<Unit>

    @DELETE("comment/{id}")
    suspend fun deleteComment(
        @Path("id") id: Int
    ): Response<Unit>

    @POST("account/my/password/reset")
    suspend fun resetPassword(
        @Body body: ResetPasswordRequestBody
    ): Response<Unit>

    @GET("comment/{id}")
    suspend fun getComment(
        @Path("id") id: Int
    ): Response<DataContainer<Comment>>

    @PATCH("account/my/extra")
    suspend fun updateUserExtra(
        @Body body: UpdateUserLangRequestBody
    ): Response<Unit>

    @GET("account/my/chat/sign")
    suspend fun getChatSign(): Response<DataContainer<TrtcSignResponseBody>>

    @GET("app/info")
    suspend fun getAppConfig(): Response<DataContainer<AppConfig>>

    @GET("dict")
    suspend fun getDict(
        @Query("key") key: String
    ): Response<DataContainer<DictItem>>

    @GET("dicts")
    suspend fun getDicts(
        @Query("keys") keys: String
    ): Response<ListContainer<DictItem>>

    @GET("/outside/dict")
    suspend fun getOutsideDict(
        @Query("key") key: String
    ): Response<DataContainer<DictItem>>

    @GET("/outside/dicts")
    suspend fun getOutsideDicts(
        @Query("keys") keys: String
    ): Response<ListContainer<DictItem>>

    @POST("captcha/generate")
    suspend fun generateCaptcha(
        @Body body: CaptchaRequestBody
    ): Response<DataContainer<CaptchaResponseBody>>

    @POST("login/needCaptcha")
    suspend fun checkLoginCaptcha(
        @Body body: CheckLoginCaptchaRequestBody
    ): Response<DataContainer<Boolean>>

    @POST("captcha/login/generate")
    suspend fun generateLoginCaptcha(
        @Body body: GenerateLoginCaptchaRequestBody
    ): Response<DataContainer<CaptchaResponseBody>>

    @GET("chat/notification")
    suspend fun getChatNotification(
        @Query("targetTrtcId") targetTrtcId: String
    ): Response<DataContainer<ChatNotification>>

    @POST("chat/notification")
    suspend fun updateChatNotification(
        @Body body: UpdateChatNotificationRequestBody
    ): Response<DataContainer<ChatNotification>>

    @POST("reports")
    suspend fun createReport(
        @Body body: CreateReportRequestBody
    ): Response<Unit>

    @POST("account/my/delete")
    suspend fun deleteAccount(
        @Body body: RemoveAccountRequestBody
    ): Response<Unit>

    @GET("outside/prompts")
    suspend fun getAgent(
        @Query("page") page: Int = 1,
        @Query("pageSize") pageSize: Int = 20,
        @Query("withWorkflow") withWorkflow: Int = 1,
        @Query("authorId") authorId: Int? = null,
        @Query("categoryIds") categoryIds: List<Int>? = null,
        @Query("random") random: Int? = null,
        @Query("title") title: String? = null,
        @Query("desc") desc: String? = null,
        @Query("excludeRoomId") excludeRoomId: Int? = null,
    ): Response<DataContainer<ListContainer<Agent>>>

    @GET("outside/my/prompts")
    suspend fun getMyAgent(
        @Query("page") page: Int = 1,
        @Query("pageSize") pageSize: Int = 20,
        @Query("withWorkflow") withWorkflow: Int = 1,
    ): Response<ListContainer<Agent>>

    @Multipart
    @POST("outside/prompts")
    suspend fun createAgent(
        @Part avatar: MultipartBody.Part?,
        @Part("title") title: RequestBody?,
        @Part("value") value: RequestBody?,
        @Part("desc") desc: RequestBody?,
        @Part("workflowId") workflowId: RequestBody?,
        @Part("public") isPublic: RequestBody?,
        @Part("breakMode") breakMode: RequestBody?,
        @Part("useWorkflow") useWorkflow: RequestBody?,
        @Part("workflowInputs") workflowInputs: RequestBody?,
    ): Response<DataContainer<Agent>>


    @POST("generate/postText")
    suspend fun agentMoment(@Body body: AgentMomentRequestBody): Response<DataContainer<String>>

    @GET("outside/rooms/open")
    suspend fun createGroupChatAi(
        @Query("trtcGroupId") trtcGroupId: String? = null,
        @Query("roomId") roomId: Int? = null
    ): Response<DataContainer<GroupChatResponse>>

    @POST("outside/rooms/create-single-chat")
    suspend fun createSingleChat(@Body body: SingleChatRequestBody): Response<DataContainer<Unit>>

    @POST("outside/rooms/message")
    suspend fun sendChatAiMessage(@Body body: SendChatAiRequestBody): Response<DataContainer<Unit>>

    @POST("outside/rooms")
    suspend fun createGroupChat(@Body body: CreateGroupChatRequestBody): Response<DataContainer<Unit>>

    /**
     * 获取房间列表
     * 
     * 支持游客和认证用户访问，根据用户类型返回不同的房间数据。
     * 游客模式返回公开推荐房间列表，认证用户模式返回用户可访问的群聊列表。
     * 
     * @param page 页码，默认 1
     * @param pageSize 每页数量，默认 20（游客模式最大50）
     * @param roomId 房间ID，用于精确查询特定房间（仅认证用户）
     * @param includeUsers 是否包含用户列表，默认false（仅认证用户）
     * @param isRecommended 是否推荐过滤器：1=推荐，0=非推荐，null=不过滤（仅认证用户）
     * @param roomType 房间类型过滤：all=公有私有都显示, public=只显示公有, private=只显示私有, created=只显示自己创建的, joined=只显示自己加入的（仅认证用户）
     * @param search 搜索关键字，支持房间名称、描述、智能体名称模糊匹配
     * @param random 是否随机排序，字符串长度不为0则为true（传任意非空字符串即可）
     * @param ownerSessionId 创建者用户ID（ChatAIID），用于过滤特定创建者的房间
     * @param showPublic 是否显示公有房间，只有明确设置为true时才生效（优先级高于roomType，仅认证用户）
     * @param showCreated 是否显示自己创建的房间，只有明确设置为true时才生效（优先级高于roomType，仅认证用户）
     * @param showJoined 是否显示自己加入的房间，只有明确设置为true时才生效（优先级高于roomType，仅认证用户）
     */
    @GET("outside/rooms")
    suspend fun getRooms(
        @Query("page") page: Int = 1,
        @Query("pageSize") pageSize: Int = 20,
        @Query("roomId") roomId: Long? = null,
        @Query("includeUsers") includeUsers: Boolean? = null,
        @Query("isRecommended") isRecommended: Int? = null,
        @Query("roomType") roomType: String? = null,
        @Query("search") search: String? = null,
        @Query("random") random: String? = null,
        @Query("ownerSessionId") ownerSessionId: String? = null,
        @Query("showPublic") showPublic: Boolean? = null,
        @Query("showCreated") showCreated: Boolean? = null,
        @Query("showJoined") showJoined: Boolean? = null,
    ): Response<ListContainer<Room>>

    @GET("outside/rooms/detail")
    suspend fun getRoomDetail(@Query("trtcId") trtcId: String,
    ): Response<DataContainer<Room>>

    @POST("outside/rooms/join")
    suspend fun joinRoom(@Body body: JoinGroupChatRequestBody,
    ): Response<DataContainer<Room>>

    @GET("outside/categories")
    suspend fun getCategories(
        @Query("page") page: Int? = null,
        @Query("pageSize") pageSize: Int? = null,
        @Query("parentId") parentId: Int? = null,
        @Query("isActive") isActive: Boolean? = null,
        @Query("name") name: String? = null,
        @Query("withChildren") withChildren: Boolean? = null,
        @Query("withParent") withParent: Boolean? = null,
        @Query("withCount") withCount: Boolean? = null,
        @Query("hideEmpty") hideEmpty: Boolean? = null,
        @Query("lang") lang: String? = null
    ): Response<CategoryListResponse>

    @GET("outside/categories/tree")
    suspend fun getCategoryTree(
        @Query("withCount") withCount: Boolean? = null,
        @Query("hideEmpty") hideEmpty: Boolean? = null
    ): Response<DataContainer<List<CategoryTemplate>>>

    @GET("outside/categories/{id}")
    suspend fun getCategoryById(
        @Path("id") id: Int
    ): Response<DataContainer<CategoryTemplate>>

    @GET("outside/prompts")
    suspend fun getPromptsByCategory(
        @Query("categoryIds") categoryIds: List<Int>? = null,
        @Query("categoryName") categoryName: String? = null,
        @Query("uncategorized") uncategorized: String? = null,
        @Query("page") page: Int? = null,
        @Query("pageSize") pageSize: Int? = null
    ): Response<ListContainer<Agent>>

    /**
     * 获取Prompt详情（支持ID或OpenId）
     * @param promptId Prompt ID或OpenId（UUID格式）
     */
    @GET("outside/prompt/{promptId}")
    suspend fun getPromptDetail(
        @Path("promptId") promptId: String
    ): Response<DataContainer<Agent>>

    /**
     * 更新Prompt（支持ID或OpenId）
     * @param promptId Prompt ID或OpenId（UUID格式）
     * @param avatar 头像文件（可选）
     * @param title 标题（可选）
     * @param desc 描述（可选）
     * @param value 内容（可选）
     * @param isPublic 是否公开（可选）
     */
    @Multipart
    @PATCH("outside/prompt/{promptId}")
    suspend fun updatePrompt(
        @Path("promptId") promptId: String,
        @Part avatar: MultipartBody.Part?,
        @Part("title") title: RequestBody?,
        @Part("desc") desc: RequestBody?,
        @Part("value") value: RequestBody?,
        @Part("public") isPublic: RequestBody?,
    ): Response<DataContainer<Agent>>

// ========== Agent Rule API ==========

    /**
     * 创建智能体规则
     * 
     * 功能说明：
     * - 为指定的智能体创建一条新规则
     * - 规则必须关联到存在的智能体（通过 promptId 或 openId 指定）
     * - 创建前会自动检查配额限制，如果超出会尝试自动扩容
     * - 只有创建者可以修改和删除该规则
     * 
     * @param body 创建规则请求体
     *   - rule: 规则内容，不能为空
     *   - promptId: 智能体ID（与 openId 二选一，promptId 优先）
     *   - openId: 智能体的 OpenID（UUID格式，与 promptId 二选一）
     * 
     * @return 成功时返回空 Unit，失败时返回错误信息
     * 
     * 示例：
     * ```kotlin
     * val request = CreatePromptRuleRequestBody(
     *     rule = "禁止讨论政治话题",
     *     promptId = 123
     * )
     * val response = api.createPromptRule(request)
     * ```
     */
    @POST("outside/prompt/rule")
    suspend fun createAgentRule(
        @Body body: CreateAgentRuleRequestBody
    ): Response<Unit>

    /**
     * 修改智能体规则
     * 
     * 功能说明：
     * - 修改已存在的规则内容或关联的智能体
     * - 只有规则的创建者可以修改
     * - 可以同时修改规则内容和关联的智能体
     * - 修改关联智能体时会重新验证配额限制
     * 
     * @param body 修改规则请求体
     *   - id: 规则ID，必填
     *   - rule: 新的规则内容，不能为空
     *   - promptId: 要更改关联的智能体ID（可选）
     *   - openId: 要更改关联的智能体 OpenID（可选）
     * 
     * @return 成功时返回空 Unit，失败时返回错误信息
     * 
     * 权限要求：
     * - 必须是规则的创建者（creator_type 为 "user" 且 create_id 匹配）
     * 
     * 示例：
     * ```kotlin
     * val request = UpdatePromptRuleRequestBody(
     *     id = 456,
     *     rule = "禁止讨论政治和敏感话题"
     * )
     * val response = api.updatePromptRule(request)
     * ```
     */
    @retrofit2.http.PUT("outside/prompt/rule")
    suspend fun updateAgentRule(
        @Body body: UpdateAgentRuleRequestBody
    ): Response<Unit>

    /**
     * 删除智能体规则
     * 
     * 功能说明：
     * - 删除指定的规则
     * - 只有规则的创建者可以删除
     * - 删除操作不可恢复，请谨慎操作
     * 
     * @param id 规则ID
     * 
     * @return 成功时返回空 Unit，失败时返回错误信息
     * 
     * 权限要求：
     * - 必须是规则的创建者（creator_type 为 "user" 且 create_id 匹配）
     * 
     * 示例：
     * ```kotlin
     * val response = api.deletePromptRule(456)
     * ```
     */
    @DELETE("outside/prompt/rule/{id}")
    suspend fun deleteAgentRule(
        @Path("id") id: Int
    ): Response<Unit>

    /**
     * 查询智能体规则列表
     * 
     * 功能说明：
     * - 查询指定智能体下当前用户创建的规则列表
     * - 支持分页和关键词模糊搜索
     * - 只返回当前用户创建的规则，不会返回其他用户的规则
     * 
     * @param promptId 智能体ID，支持数字ID或UUID格式的 openId
     * @param rule 规则内容关键词（模糊搜索），可选
     * @param page 页码，默认 1
     * @param pageSize 每页数量，默认 10
     * 
     * @return 返回分页的规则列表，包含规则详情和关联的智能体信息
     * 
     * 响应数据说明：
     * - page: 当前页码
     * - pageSize: 每页数量
     * - total: 总记录数
     * - list: 规则列表
     *   - id: 规则ID
     *   - rule: 规则内容
     *   - creator: 创建者名称
     *   - creator_type: 创建者类型
     *   - scope: 作用域
     *   - prompt: 关联的智能体信息（id, title, avatar）
     *   - created_at: 创建时间
     *   - updated_at: 更新时间
     * 
     * 示例：
     * ```kotlin
     * // 使用数字ID查询
     * val response1 = api.getPromptRuleList("123", page = 1, pageSize = 10)
     * 
     * // 使用 OpenID 查询
     * val response2 = api.getPromptRuleList(
     *     "550e8400-e29b-41d4-a716-446655440000",
     *     page = 1,
     *     pageSize = 10
     * )
     * 
     * // 带关键词搜索
     * val response3 = api.getPromptRuleList(
     *     "123",
     *     rule = "政治",
     *     page = 1,
     *     pageSize = 10
     * )
     * ```
     */
    @GET("outside/prompt/{promptId}/rule/list")
    suspend fun getAgentRuleList(
        @Path("promptId") promptId: String,
        @Query("rule") rule: String? = null,
        @Query("page") page: Int = 1,
        @Query("pageSize") pageSize: Int = 10
    ): Response<DataContainer<AgentRuleListResponse>>

    /**
     * 查询智能体规则配额信息
     * 
     * 功能说明：
     * - 查询指定智能体的规则条数使用情况
     * - 包括基础配额、已购买配额、已使用数量等完整信息
     * - 用于判断是否还能创建新规则
     * 
     * @param promptId 智能体ID，支持数字ID或UUID格式的 openId
     * 
     * @return 返回配额详细信息
     * 
     * 响应数据说明：
     * - promptId: 智能体ID
     * - promptTitle: 智能体标题
     * - baseMaxCount: 基础条数限制（免费配额，由智能体等级决定）
     * - purchasedCount: 用户购买的额外条数
     * - totalMaxCount: 总可用条数（baseMaxCount + purchasedCount）
     * - currentCount: 当前已创建的规则条数（只统计当前用户创建的）
     * - remainingCount: 剩余可用条数（totalMaxCount - currentCount）
     * - usagePercent: 使用百分比，0-100（currentCount / totalMaxCount * 100）
     * 
     * 使用场景：
     * 1. 创建规则前检查是否有足够配额
     * 2. 展示规则使用情况统计
     * 3. 提示用户购买额外配额
     * 
     * 示例：
     * ```kotlin
     * // 使用数字ID查询
     * val response1 = api.getPromptRuleQuota("123")
     * 
     * // 使用 OpenID 查询
     * val response2 = api.getPromptRuleQuota("550e8400-e29b-41d4-a716-446655440000")
     * 
     * // 处理响应
     * response1.body()?.data?.let { quota ->
     *     if (quota.remainingCount > 0) {
     *         // 可以创建新规则
     *         println("还可以创建 ${quota.remainingCount} 条规则")
     *     } else {
     *         // 配额已用完
     *         println("规则配额已用完，已使用 ${quota.currentCount}/${quota.totalMaxCount}")
     *     }
     * }
     * ```
     */
    @GET("outside/prompt/{promptId}/rule/count")
    suspend fun getAgentRuleQuota(
        @Path("promptId") promptId: String
    ): Response<DataContainer<AgentRuleQuota>>

    // ========== Room Rule API ==========

    /**
     * 创建房间规则
     * 
     * 功能说明：
     * - 为指定的房间创建一条新规则
     * - 规则会被添加到AI对话上下文中，用于约束房间内的行为和交互方式
     * - 必须是房间成员或房间创建者才能创建规则
     * - 每个用户在每个房间有基础条数限制，达到限制后会自动扣费扩容
     * - 如果积分不足，会返回特殊的错误响应（错误码 35600）
     * 
     * @param body 创建规则请求体
     *   - rule: 规则内容，不能为空
     *   - roomId: 房间ID（与 trtcId 二选一）
     *   - trtcId: TRTC房间ID（与 roomId 二选一）
     * 
     * @return 成功时返回空 Unit，失败时返回错误信息
     * 
     * 错误响应说明：
     * - 400 (40001): 缺少房间标识（必须提供 roomId 或 trtcId）
     * - 400 (40002): 规则内容为空
     * - 400 (40003): 规则内容超出字数限制
     * - 400 (35600): 积分不足（自动扩容失败），返回 InsufficientBalanceError 格式
     * - 401 (40101): 未登录
     * - 403 (40301): 无权限为该房间创建规则
     * - 400 (40005): 房间不存在
     * 
     * 示例：
     * ```kotlin
     * // 使用 roomId 创建规则
     * val request1 = CreateRoomRuleRequestBody(
     *     rule = "禁止在房间内讨论政治话题",
     *     roomId = 123
     * )
     * val response1 = api.createRoomRule(request1)
     * 
     * // 使用 trtcId 创建规则
     * val request2 = CreateRoomRuleRequestBody(
     *     rule = "请使用文明用语",
     *     trtcId = "room_trtc_123"
     * )
     * val response2 = api.createRoomRule(request2)
     * 
     * // 处理积分不足错误
     * if (!response1.isSuccessful && response1.code() == 400) {
     *     val errorBody = response1.errorBody()?.string()
     *     // 解析为 InsufficientBalanceError 获取余额信息
     * }
     * ```
     */
    @POST("outside/room/rule")
    suspend fun createRoomRule(
        @Body body: CreateRoomRuleRequestBody
    ): Response<Unit>

    /**
     * 修改房间规则
     * 
     * 功能说明：
     * - 修改指定的房间规则内容
     * - 只能修改自己创建的规则（creator_type 为 "user"）
     * - 修改不会增加规则条数，因此不会触发扣费
     * 
     * @param body 修改规则请求体
     *   - id: 规则ID，必填
     *   - rule: 新的规则内容，不能为空
     * 
     * @return 成功时返回空 Unit，失败时返回错误信息
     * 
     * 权限要求：
     * - 必须是规则的创建者
     * - 规则必须是用户类型（creator_type = "user"）
     * 
     * 错误响应说明：
     * - 400 (40002): 规则内容为空
     * - 400 (40003): 规则内容超出字数限制
     * - 401 (40101): 未登录
     * - 403 (40301): 无权限修改该规则
     * - 404 (40401): 规则不存在
     * 
     * 示例：
     * ```kotlin
     * val request = UpdateRoomRuleRequestBody(
     *     id = 456,
     *     rule = "请保持友善交流"
     * )
     * val response = api.updateRoomRule(request)
     * ```
     */
    @retrofit2.http.PUT("outside/room/rule")
    suspend fun updateRoomRule(
        @Body body: UpdateRoomRuleRequestBody
    ): Response<Unit>

    /**
     * 删除房间规则
     * 
     * 功能说明：
     * - 删除指定的房间规则
     * - 只能删除自己创建的规则（creator_type 为 "user"）
     * - 删除操作不可恢复，请谨慎操作
     * - 删除规则不会退还已扣除的积分
     * 
     * @param id 规则ID
     * 
     * @return 成功时返回空 Unit，失败时返回错误信息
     * 
     * 权限要求：
     * - 必须是规则的创建者
     * - 规则必须是用户类型（creator_type = "user"）
     * 
     * 错误响应说明：
     * - 400 (40006): 无效的规则ID
     * - 401 (40101): 未登录
     * - 403 (40301): 无权限删除该规则
     * 
     * 示例：
     * ```kotlin
     * val response = api.deleteRoomRule(456)
     * ```
     */
    @DELETE("outside/room/rule/{id}")
    suspend fun deleteRoomRule(
        @Path("id") id: Int
    ): Response<Unit>

    /**
     * 查询房间规则列表
     * 
     * 功能说明：
     * - 查询指定房间的规则列表，支持分页
     * - 返回该房间所有用户创建的规则，包含创建者信息
     * - 必须是房间成员或房间创建者才能查询
     * 
     * @param roomId 房间ID，与 trtcId 二选一
     * @param trtcId TRTC房间ID，与 roomId 二选一
     * @param page 页码，默认 1
     * @param pageSize 每页数量，默认 10
     * 
     * @return 返回分页的规则列表，包含规则详情和创建者信息
     * 
     * 响应数据说明：
     * - page: 当前页码
     * - pageSize: 每页数量
     * - total: 总记录数
     * - list: 规则列表
     *   - id: 规则ID
     *   - rule: 规则内容
     *   - creator: 创建者信息（id, nickname, avatar）
     *   - creatorType: 创建者类型（"user" 等）
     *   - roomId: 所属房间ID
     *   - createdAt: 创建时间（ISO 8601格式）
     *   - updatedAt: 更新时间（ISO 8601格式）
     * 
     * 错误响应说明：
     * - 400 (40001): 缺少房间标识（必须提供 roomId 或 trtcId）
     * - 401 (40101): 未登录
     * - 403 (40301): 无权限查看该房间的规则
     * 
     * 示例：
     * ```kotlin
     * // 使用 roomId 查询
     * val response1 = api.getRoomRuleList(
     *     roomId = 123,
     *     page = 1,
     *     pageSize = 10
     * )
     * 
     * // 使用 trtcId 查询
     * val response2 = api.getRoomRuleList(
     *     trtcId = "room_trtc_123",
     *     page = 1,
     *     pageSize = 10
     * )
     * 
     * // 处理响应
     * response1.body()?.let { result ->
     *     println("共 ${result.total} 条规则，当前第 ${result.page} 页")
     *     result.list.forEach { rule ->
     *         println("规则: ${rule.rule}, 创建者: ${rule.creator?.nickname}")
     *     }
     * }
     * ```
     */
    @GET("outside/room/rule")
    suspend fun getRoomRuleList(
        @Query("roomId") roomId: Int? = null,
        @Query("trtcId") trtcId: String? = null,
        @Query("page") page: Int = 1,
        @Query("pageSize") pageSize: Int = 10
    ): Response<RoomRuleListResponse>

    /**
     * 查询规则额度使用情况
     * 
     * 功能说明：
     * - 查询当前用户在指定房间的规则额度使用情况
     * - 包括基础条数、已购买条数、当前使用数等完整信息
     * - 用于判断用户是否还能创建新规则
     * - 必须是房间成员或房间创建者才能查询
     * 
     * @param roomId 房间ID，与 trtcId 二选一
     * @param trtcId TRTC房间ID，与 roomId 二选一
     * 
     * @return 返回配额详细信息
     * 
     * 响应数据说明：
     * - baseMaxCount: 基础条数限制（系统配置的免费配额）
     * - purchasedCount: 用户购买的额外条数（通过自动扩容机制）
     * - totalMaxCount: 总可用条数（baseMaxCount + purchasedCount）
     * - currentCount: 当前已创建的规则条数（该用户在该房间）
     * - remainingCount: 剩余可用条数（totalMaxCount - currentCount）
     * - usagePercent: 使用百分比，0-100（currentCount / totalMaxCount * 100）
     * 
     * 使用场景：
     * 1. 创建规则前检查是否有足够配额
     * 2. 展示规则使用情况统计
     * 3. 提示用户即将达到配额上限
     * 
     * 错误响应说明：
     * - 400 (40001): 缺少房间标识（必须提供 roomId 或 trtcId）
     * - 401 (40101): 未登录
     * - 403 (40301): 无权限查看该房间的规则条数信息
     * 
     * 示例：
     * ```kotlin
     * // 使用 roomId 查询
     * val response1 = api.getRoomRuleQuota(roomId = 123)
     * 
     * // 使用 trtcId 查询
     * val response2 = api.getRoomRuleQuota(trtcId = "room_trtc_123")
     * 
     * // 处理响应
     * response1.body()?.data?.let { quota ->
     *     if (quota.remainingCount > 0) {
     *         // 可以创建新规则
     *         println("还可以创建 ${quota.remainingCount} 条规则")
     *         println("使用率: ${quota.usagePercent}%")
     *     } else {
     *         // 配额已用完，需要扩容
     *         println("规则配额已用完，已使用 ${quota.currentCount}/${quota.totalMaxCount}")
     *         println("创建新规则将自动扣除积分进行扩容")
     *     }
     * }
     * ```
     */
    @GET("outside/room/rule/length-info")
    suspend fun getRoomRuleQuota(
        @Query("roomId") roomId: Int? = null,
        @Query("trtcId") trtcId: String? = null
    ): Response<DataContainer<RoomRuleQuota>>

    

    @GET("recommendations")
    suspend fun getRecommendations(
        @Query("pool") pool: String? = null,
        @Query("count") count: Int? = null,
        @Query("lang") lang: String? = null,
        @Query("promptReplaceTrans") promptReplaceTrans: Boolean? = null
    ): Response<RecommendationsResponse>

    // ========== Points API ==========

    /**
     * 获取我的积分余额
     * 
     * 功能说明：
     * - 获取当前登录用户的积分余额
     * - 可选返回累计获得和累计消费统计信息
     * 
     * @param includeStatistics 是否包含统计信息（累计获得和累计消费），默认 true
     * 
     * @return 返回积分余额和统计信息
     * 
     * 响应数据说明：
     * - balance: 当前积分余额
     * - totalEarned: 累计获得积分（仅当 includeStatistics 为 true 时返回）
     * - totalSpent: 累计消费积分（仅当 includeStatistics 为 true 时返回）
     * 
     * 示例：
     * ```kotlin
     * // 获取包含统计信息的积分余额
     * val response1 = api.getMyPointsBalance()
     * 
     * // 仅获取当前余额
     * val response2 = api.getMyPointsBalance(includeStatistics = false)
     * ```
     */
    @GET("account/my/points")
    suspend fun getMyPointsBalance(
        @Query("includeStatistics") includeStatistics: Boolean? = null
    ): Response<DataContainer<PointsBalance>>

    /**
     * 获取我的积分变更日志
     * 
     * 功能说明：
     * - 获取当前登录用户的积分变更日志列表
     * - 支持分页、时间范围筛选和变更类型筛选
     * 
     * @param page 页码，默认 1
     * @param pageSize 每页数量，默认 20
     * @param changeType 变更类型筛选（add: 增加, subtract: 减少, adjust: 调整）
     * @param startTime 开始时间，格式：YYYY-MM-DD
     * @param endTime 结束时间，格式：YYYY-MM-DD
     * 
     * @return 返回分页的积分变更日志列表
     * 
     * 响应数据说明：
     * - list: 积分变更日志列表
     * - total: 总记录数
     * - page: 当前页码
     * - pageSize: 每页数量
     * 
     * 示例：
     * ```kotlin
     * // 获取最近的积分变更日志
     * val response1 = api.getMyPointsChangeLogs(page = 1, pageSize = 20)
     * 
     * // 筛选积分增加记录
     * val response2 = api.getMyPointsChangeLogs(changeType = "add")
     * 
     * // 查询指定时间范围的记录
     * val response3 = api.getMyPointsChangeLogs(
     *     startTime = "2024-01-01",
     *     endTime = "2024-01-31"
     * )
     * ```
     */
    @GET("account/my/points/logs")
    suspend fun getMyPointsChangeLogs(
        @Query("page") page: Int = 1,
        @Query("pageSize") pageSize: Int = 20,
        @Query("changeType") changeType: String? = null,
        @Query("startTime") startTime: String? = null,
        @Query("endTime") endTime: String? = null
    ): Response<PointsChangeLogsResponse>

    // ========== Room Member Management API ==========

    /**
     * 添加用户到房间
     * 
     * 功能说明：
     * - 向房间批量添加用户
     * - 支持通过房间ID或TRTC群组ID添加
     * - 只有房间创建者可以使用此接口
     * - 添加数量受房间容量限制
     * - 成功添加后会自动扣除房间创建者的积分用于扩容
     * 
     * @param body 添加用户请求体
     *   - roomId: 房间ID（与 trtcId 二选一）
     *   - trtcId: TRTC群组ID（与 roomId 二选一）
     *   - openIds: 要添加的用户OpenID列表
     * 
     * @return 成功时返回操作结果，包含成功、失败、跳过的用户列表
     * 
     * 示例：
     * ```kotlin
     * val request = AddUserToRoomRequestBody(
     *     roomId = 123,
     *     openIds = listOf("user_openid_1", "user_openid_2")
     * )
     * val response = api.addUserToRoom(request)
     * ```
     */
    @POST("outside/rooms/add-user")
    suspend fun addUserToRoom(
        @Body body: AddUserToRoomRequestBody
    ): Response<DataContainer<AddUserToRoomResponse>>

    /**
     * 添加智能体到房间
     * 
     * 功能说明：
     * - 向房间批量添加智能体（Agent）
     * - 支持通过房间ID或TRTC群组ID添加
     * - 房间创建者可以使用此接口
     * - 当容量不足时会自动扩容并扣除房间创建者的积分
     * - 如果积分不足以支付扩容费用，将返回错误
     * 
     * @param body 添加智能体请求体
     *   - roomId: 房间ID（与 trtcId 二选一）
     *   - trtcId: TRTC群组ID（与 roomId 二选一）
     *   - agentOpenIds: 要添加的智能体OpenID列表
     * 
     * @return 成功时返回操作结果，包含成功、失败、跳过的智能体列表
     * 
     * 示例：
     * ```kotlin
     * val request = AddAgentToRoomRequestBody(
     *     roomId = 123,
     *     agentOpenIds = listOf("agent_openid_1", "agent_openid_2")
     * )
     * val response = api.addAgentToRoom(request)
     * ```
     */
    @POST("outside/rooms/add-agent")
    suspend fun addAgentToRoom(
        @Body body: AddAgentToRoomRequestBody
    ): Response<DataContainer<AddAgentToRoomResponse>>

    /**
     * 从房间移除智能体
     * 
     * 功能说明：
     * - 从房间批量移除智能体（Agent）
     * - 支持通过房间ID或TRTC群组ID操作
     * - 只有房间创建者可以使用此接口
     * - 单聊房间不支持移除智能体
     * - 移除操作会同步到OpenIM系统
     * 
     * @param body 移除智能体请求体
     *   - roomId: 房间ID（与 trtcId 二选一）
     *   - trtcId: TRTC群组ID（与 roomId 二选一）
     *   - agentOpenIds: 要移除的智能体OpenID列表
     * 
     * @return 成功时返回操作结果，包含成功、失败、跳过的智能体列表
     * 
     * 示例：
     * ```kotlin
     * val request = RemoveAgentFromRoomRequestBody(
     *     roomId = 123,
     *     agentOpenIds = listOf("agent_openid_1", "agent_openid_2")
     * )
     * val response = api.removeAgentFromRoom(request)
     * ```
     */
    @POST("outside/rooms/remove-agent")
    suspend fun removeAgentFromRoom(
        @Body body: RemoveAgentFromRoomRequestBody
    ): Response<DataContainer<RemoveAgentFromRoomResult>>

    /**
     * 从房间移除用户
     * 
     * 功能说明：
     * - 从房间批量移除用户
     * - 支持通过房间ID或TRTC群组ID操作
     * - 只有房间创建者可以使用此接口
     * - 单聊房间不支持移除用户
     * - 群主不能移除自己
     * - 移除操作会同步到OpenIM系统
     * 
     * @param body 移除用户请求体
     *   - roomId: 房间ID（与 trtcId 二选一）
     *   - trtcId: TRTC群组ID（与 roomId 二选一）
     *   - userIds: 要移除的用户ID列表（OpenID）
     * 
     * @return 成功时返回操作结果，包含成功、失败、跳过的用户列表
     * 
     * 示例：
     * ```kotlin
     * val request = RemoveUserFromRoomRequestBody(
     *     roomId = 123,
     *     userIds = listOf("user_openid_1", "user_openid_2")
     * )
     * val response = api.removeUserFromRoom(request)
     * ```
     */
    @POST("outside/rooms/remove-user")
    suspend fun removeUserFromRoom(
        @Body body: RemoveUserFromRoomRequestBody
    ): Response<DataContainer<RemoveUserFromRoomResult>>

}

