syntax = "v1"

type (
	// ===== Permission catalog =====

	PermissionCatalogQuery {
		Status string `form:"status,optional,options=open|close" validate:"omitempty,oneof=open close"`                            // 狀態篩選；可選值: open / close
		Type   string `form:"type,optional,options=backend_user|frontend_user" validate:"omitempty,oneof=backend_user frontend_user"` // 權限類型篩選；可選值: backend_user / frontend_user
		Tree   bool   `form:"tree,optional"`                                                                                      // 是否回傳樹狀結構（false 則扁平 list）
	}

	PermissionNode {
		ID          string           `json:"id"`
		Parent      string           `json:"parent,omitempty"`
		Name        string           `json:"name"`
		HTTPMethods string           `json:"http_methods,omitempty"`
		HTTPPath    string           `json:"http_path,omitempty"`
		Status      string           `json:"status"`
		Type        string           `json:"type"`
		Children    []PermissionNode `json:"children,omitempty"`
	}

	PermissionCatalogData {
		Tree []PermissionNode `json:"tree,omitempty"`
		List []PermissionNode `json:"list,omitempty"`
	}

	// ===== Me permissions =====

	MePermissionsQuery {
		IncludeTree bool `form:"include_tree,optional"` // 是否同時回傳 permission tree（true 會多包一份樹狀結構）
	}

	MePermissionsData {
		UID         string            `json:"uid"`
		TenantID    string            `json:"tenant_id"`
		Roles       []string          `json:"roles"`
		Permissions map[string]string `json:"permissions"`
		Tree        []PermissionNode  `json:"tree,omitempty"`
	}

	// ===== Roles =====

	RoleData {
		ID          string `json:"id"`
		TenantID    string `json:"tenant_id"`
		Key         string `json:"key"`
		DisplayName string `json:"display_name"`
		CreatorUID  string `json:"creator_uid,omitempty"`
		Status      string `json:"status"`
		IsSystem    bool   `json:"is_system"`
		CreateAt    int64  `json:"create_at"`
		UpdateAt    int64  `json:"update_at"`
	}

	RoleListData {
		Roles []RoleData `json:"roles"`
	}

	CreateRoleReq {
		Key         string `json:"key" validate:"required,min=2,max=64"`                              // 角色 key（2-64 字元，不可以 system. / platform_ 開頭）
		DisplayName string `json:"display_name,optional"`                                             // 角色顯示名稱（給人看的）
		Status      string `json:"status,optional,options=open|close" validate:"omitempty,oneof=open close"` // 角色狀態；可選值: open / close（預設 open）
	}

	UpdateRoleReq {
		DisplayName string `json:"display_name,optional"`                                                    // 角色顯示名稱
		Status      string `json:"status,optional,options=open|close" validate:"omitempty,oneof=open close"` // 角色狀態；可選值: open / close
	}

	UpdateRoleByIDReq {
		ID          string `path:"id"`                                                                       // Role ID（path）
		DisplayName string `json:"display_name,optional"`                                                    // 角色顯示名稱
		Status      string `json:"status,optional,options=open|close" validate:"omitempty,oneof=open close"` // 角色狀態；可選值: open / close
	}

	DeleteRoleByIDReq {
		ID string `path:"id"` // Role ID（path）
	}

	GetRolePermissionsByIDReq {
		ID string `path:"id"` // Role ID（path）
	}

	ReplaceRolePermissionsByIDReq {
		ID            string   `path:"id"`             // Role ID（path）
		PermissionIDs []string `json:"permission_ids"` // 要勾選的 Permission ID 陣列（全量取代，會自動補齊父權限）
	}

	ListUserRolesReq {
		UID string `path:"uid"` // 使用者 UID（path）
	}

	AssignUserRoleByUIDReq {
		UID    string `path:"uid"`                                                                                            // 使用者 UID（path）
		RoleID string `json:"role_id" validate:"required"`                                                                    // 要指派的 Role ID
		Source string `json:"source,optional,options=manual|zitadel|ldap|scim" validate:"omitempty,oneof=manual zitadel ldap scim"` // 指派來源；可選值: manual / zitadel / ldap / scim（預設 manual）
	}

	RevokeUserRoleByIDReq {
		UID    string `path:"uid"`     // 使用者 UID（path）
		RoleID string `path:"role_id"` // Role ID（path）
	}

	// ===== Role permissions =====

	RolePermissionsListData {
		Permissions []PermissionNode `json:"permissions"`
	}

	ReplaceRolePermissionsReq {
		PermissionIDs []string `json:"permission_ids"` // 要勾選的 Permission ID 陣列（全量取代，會自動補齊父權限）
	}

	// ===== User roles =====

	UIDPath {
		UID string `path:"uid"` // 使用者 UID（path）
	}

	UserRoleData {
		ID              string `json:"id"`
		TenantID        string `json:"tenant_id"`
		UID             string `json:"uid"`
		RoleID          string `json:"role_id"`
		RoleKey         string `json:"role_key"`
		RoleDisplayName string `json:"role_display_name"`
		Source          string `json:"source"`
		CreateAt        int64  `json:"create_at"`
		UpdateAt        int64  `json:"update_at"`
	}

	UserRoleListData {
		UserRoles []UserRoleData `json:"user_roles"`
	}

	AssignUserRoleReq {
		RoleID string `json:"role_id" validate:"required"`                                                                          // 要指派的 Role ID
		Source string `json:"source,optional,options=manual|zitadel|ldap|scim" validate:"omitempty,oneof=manual zitadel ldap scim"` // 指派來源；可選值: manual / zitadel / ldap / scim（預設 manual）
	}

	UserRoleIDPath {
		UID    string `path:"uid"`     // 使用者 UID（path）
		RoleID string `path:"role_id"` // Role ID（path）
	}

	// ===== Role mappings =====

	RoleMappingData {
		ID              string `json:"id"`
		TenantID        string `json:"tenant_id"`
		ExternalSource  string `json:"external_source"`
		ExternalKey     string `json:"external_key"`
		InternalRoleID  string `json:"internal_role_id"`
		InternalRoleKey string `json:"internal_role_key"`
		CreateAt        int64  `json:"create_at"`
		UpdateAt        int64  `json:"update_at"`
	}

	RoleMappingListData {
		Mappings []RoleMappingData `json:"mappings"`
		Total    int64             `json:"total"`
		Offset   int64             `json:"offset"`
		Limit    int64             `json:"limit"`
	}

	RoleMappingListQuery {
		Source string `form:"source,optional,options=zitadel|ldap|scim" validate:"omitempty,oneof=zitadel ldap scim"` // 外部來源篩選；可選值: zitadel / ldap / scim
		Offset int64  `form:"offset,optional"`                                                                       // 分頁起點（從 0 起算）
		Limit  int64  `form:"limit,optional"`                                                                        // 每頁筆數（最大值由 server 限制）
	}

	UpsertRoleMappingReq {
		ExternalSource  string `json:"external_source,options=zitadel|ldap|scim" validate:"required,oneof=zitadel ldap scim"` // 外部來源；可選值: zitadel / ldap / scim
		ExternalKey     string `json:"external_key" validate:"required"`                                                      // 外部群組 / claim 的 key（例如 zitadel role 名稱）
		InternalRoleKey string `json:"internal_role_key" validate:"required"`                                                 // 對映的內部角色 key（必須存在於 roles 集合）
	}

	DeleteRoleMappingReq {
		ExternalSource string `json:"external_source,options=zitadel|ldap|scim" validate:"required,oneof=zitadel ldap scim"` // 外部來源；可選值: zitadel / ldap / scim
		ExternalKey    string `json:"external_key" validate:"required"`                                                      // 外部群組 / claim 的 key
	}

	// ===== Policy reload =====

	PolicyReloadReq {
		TenantID string `json:"tenant_id,optional"` // 指定要 reload 的租戶 ID；留空則 reload 所有租戶
	}

	PolicyReloadData {
		Tenant string `json:"tenant"`
		TS     int64  `json:"ts"`
	}

	// ===== OK envelopes for swagger =====

	PermissionCatalogOKStatus {
		Code    int64                 `json:"code"`
		Message string                `json:"message"`
		Data    PermissionCatalogData `json:"data"`
	}

	MePermissionsOKStatus {
		Code    int64             `json:"code"`
		Message string            `json:"message"`
		Data    MePermissionsData `json:"data"`
	}

	RoleListOKStatus {
		Code    int64        `json:"code"`
		Message string       `json:"message"`
		Data    RoleListData `json:"data"`
	}

	RoleOKStatus {
		Code    int64    `json:"code"`
		Message string   `json:"message"`
		Data    RoleData `json:"data"`
	}

	RolePermissionsListOKStatus {
		Code    int64                   `json:"code"`
		Message string                  `json:"message"`
		Data    RolePermissionsListData `json:"data"`
	}

	UserRoleListOKStatus {
		Code    int64            `json:"code"`
		Message string           `json:"message"`
		Data    UserRoleListData `json:"data"`
	}

	UserRoleOKStatus {
		Code    int64        `json:"code"`
		Message string       `json:"message"`
		Data    UserRoleData `json:"data"`
	}

	RoleMappingListOKStatus {
		Code    int64               `json:"code"`
		Message string              `json:"message"`
		Data    RoleMappingListData `json:"data"`
	}

	RoleMappingOKStatus {
		Code    int64           `json:"code"`
		Message string          `json:"message"`
		Data    RoleMappingData `json:"data"`
	}

	PolicyReloadOKStatus {
		Code    int64            `json:"code"`
		Message string           `json:"message"`
		Data    PolicyReloadData `json:"data"`
	}
)

@server(
	group:      permission
	prefix:     /api/v1/permissions
	middleware: AuthJWT
	tags:       "Permission - 權限（讀取）"
	summary:    "Catalog / Me（需 Bearer，不過 RBAC 檢查）"
)
service gateway {
	@doc "取得全局 Permission Catalog（樹狀或扁平；可篩 status/type）"
	/*
		@respdoc-200 (PermissionCatalogOKStatus) // 成功（code=102000）
		@respdoc-401 (
			31501000: (APIErrorStatus) 未授權
		) // 未授權
		@respdoc-500 (
			31201000: (APIErrorStatus) 資料庫錯誤
			31601000: (APIErrorStatus) 系統內部錯誤
		) // 內部錯誤
		@respdoc-501 (
			31605000: (APIErrorStatus) Permission 模組未配置
		) // 未實作
	*/
	@handler getPermissionCatalog
	get /catalog (PermissionCatalogQuery) returns (PermissionCatalogData)

	@doc "取得當前使用者的 role / permission map（前端渲染選單）"
	/*
		@respdoc-200 (MePermissionsOKStatus) // 成功（code=102000）
		@respdoc-401 (
			31501000: (APIErrorStatus) 缺少 Bearer 或 X-Tenant-ID/X-UID
		) // 未授權
		@respdoc-500 (
			31201000: (APIErrorStatus) 資料庫錯誤
			31601000: (APIErrorStatus) 系統內部錯誤
		) // 內部錯誤
		@respdoc-501 (
			31605000: (APIErrorStatus) Permission 模組未配置
		) // 未實作
	*/
	@handler getMePermissions
	get /me (MePermissionsQuery) returns (MePermissionsData)
}

@server(
	group:      permission
	prefix:     /api/v1/permissions
	middleware: AuthJWT,CasbinRBAC
	tags:       "Permission - 權限（管理）"
	summary:    "角色 / 使用者角色 / 外部映射 / Policy（需 Bearer + RBAC）"
)
service gateway {
	@doc "列出租戶內所有角色（含 system role）"
	/*
		@respdoc-200 (RoleListOKStatus) // 成功
		@respdoc-401 (
			31501000: (APIErrorStatus) 未授權
		) // 未授權
		@respdoc-500 (
			31201000: (APIErrorStatus) 資料庫錯誤
		) // 內部錯誤
	*/
	@handler listRoles
	get /roles returns (RoleListData)

	@doc "建立租戶自訂角色（key 不可改、不可使用 system./platform_ 開頭）"
	/*
		@respdoc-200 (RoleOKStatus) // 成功
		@respdoc-400 (
			10101000: (APIErrorStatus) 參數格式錯誤
			31101000: (APIErrorStatus) role key 格式或保留字錯誤
		) // 參數錯誤
		@respdoc-401 (
			31501000: (APIErrorStatus) 未授權
		) // 未授權
		@respdoc-409 (
			31303000: (APIErrorStatus) 同名 role 已存在
		) // 衝突
		@respdoc-500 (
			31201000: (APIErrorStatus) 資料庫錯誤
		) // 內部錯誤
	*/
	@handler createRole
	post /roles (CreateRoleReq) returns (RoleData)

	@doc "更新角色（display_name / status；is_system 角色不可改 status）"
	/*
		@respdoc-200 (RoleOKStatus) // 成功
		@respdoc-400 (
			10101000: (APIErrorStatus) 參數格式錯誤
		) // 參數錯誤
		@respdoc-401 (
			31501000: (APIErrorStatus) 未授權
		) // 未授權
		@respdoc-404 (
			31301000: (APIErrorStatus) role 不存在
		) // 不存在
		@respdoc-409 (
			31309000: (APIErrorStatus) 系統角色無法更新此欄位
		) // 衝突
		@respdoc-500 (
			31201000: (APIErrorStatus) 資料庫錯誤
		) // 內部錯誤
	*/
	@handler updateRole
	patch /roles/:id (UpdateRoleByIDReq) returns (RoleData)

	@doc "刪除角色（is_system 不可刪；存在 user 指派時拒絕）"
	/*
		@respdoc-200 (EmptyOKStatus) // 成功
		@respdoc-401 (
			31501000: (APIErrorStatus) 未授權
		) // 未授權
		@respdoc-404 (
			31301000: (APIErrorStatus) role 不存在
		) // 不存在
		@respdoc-409 (
			31309000: (APIErrorStatus) 系統角色無法刪除
			31312000: (APIErrorStatus) 角色仍有使用者指派
		) // 衝突
		@respdoc-500 (
			31201000: (APIErrorStatus) 資料庫錯誤
		) // 內部錯誤
	*/
	@handler deleteRole
	delete /roles/:id (DeleteRoleByIDReq)

	@doc "讀取角色目前勾選的 permission 集合"
	/*
		@respdoc-200 (RolePermissionsListOKStatus) // 成功
		@respdoc-401 (
			31501000: (APIErrorStatus) 未授權
		) // 未授權
		@respdoc-404 (
			31301000: (APIErrorStatus) role 不存在
		) // 不存在
		@respdoc-500 (
			31201000: (APIErrorStatus) 資料庫錯誤
		) // 內部錯誤
	*/
	@handler getRolePermissions
	get /roles/:id/permissions (GetRolePermissionsByIDReq) returns (RolePermissionsListData)

	@doc "全量取代角色的 permission 勾選（自動補齊父權限；觸發 LoadPolicy + Pub/Sub reload）"
	/*
		@respdoc-200 (EmptyOKStatus) // 成功
		@respdoc-400 (
			10101000: (APIErrorStatus) 參數格式錯誤
		) // 參數錯誤
		@respdoc-401 (
			31501000: (APIErrorStatus) 未授權
		) // 未授權
		@respdoc-404 (
			31301000: (APIErrorStatus) role 或 permission 不存在
		) // 不存在
		@respdoc-500 (
			31201000: (APIErrorStatus) 資料庫錯誤
			31601000: (APIErrorStatus) 系統內部錯誤
		) // 內部錯誤
	*/
	@handler replaceRolePermissions
	put /roles/:id/permissions (ReplaceRolePermissionsByIDReq)

	@doc "查詢使用者目前指派的角色（含 RoleKey / DisplayName）"
	/*
		@respdoc-200 (UserRoleListOKStatus) // 成功
		@respdoc-401 (
			31501000: (APIErrorStatus) 未授權
		) // 未授權
		@respdoc-500 (
			31201000: (APIErrorStatus) 資料庫錯誤
		) // 內部錯誤
	*/
	@handler listUserRoles
	get /users/:uid/roles (ListUserRolesReq) returns (UserRoleListData)

	@doc "指派角色給使用者（預設 source=manual；source 來源由 SyncFromX 自動標）"
	/*
		@respdoc-200 (UserRoleOKStatus) // 成功
		@respdoc-400 (
			10101000: (APIErrorStatus) 參數格式錯誤
		) // 參數錯誤
		@respdoc-401 (
			31501000: (APIErrorStatus) 未授權
		) // 未授權
		@respdoc-404 (
			31301000: (APIErrorStatus) role 不存在
		) // 不存在
		@respdoc-409 (
			31303000: (APIErrorStatus) 角色已指派
		) // 衝突
		@respdoc-500 (
			31201000: (APIErrorStatus) 資料庫錯誤
		) // 內部錯誤
	*/
	@handler assignUserRole
	post /users/:uid/roles (AssignUserRoleByUIDReq) returns (UserRoleData)

	@doc "撤銷使用者的單一角色"
	/*
		@respdoc-200 (EmptyOKStatus) // 成功
		@respdoc-401 (
			31501000: (APIErrorStatus) 未授權
		) // 未授權
		@respdoc-404 (
			31301000: (APIErrorStatus) 指派不存在
		) // 不存在
		@respdoc-500 (
			31201000: (APIErrorStatus) 資料庫錯誤
		) // 內部錯誤
	*/
	@handler revokeUserRole
	delete /users/:uid/roles/:role_id (RevokeUserRoleByIDReq)

	@doc "列出外部來源 → 內部 role 的映射（zitadel / ldap / scim）"
	/*
		@respdoc-200 (RoleMappingListOKStatus) // 成功
		@respdoc-401 (
			31501000: (APIErrorStatus) 未授權
		) // 未授權
		@respdoc-500 (
			31201000: (APIErrorStatus) 資料庫錯誤
		) // 內部錯誤
	*/
	@handler listRoleMappings
	get /role-mappings (RoleMappingListQuery) returns (RoleMappingListData)

	@doc "Upsert 外部 IdP 群組到內部 role 的映射"
	/*
		@respdoc-200 (RoleMappingOKStatus) // 成功
		@respdoc-400 (
			10101000: (APIErrorStatus) 參數格式錯誤
		) // 參數錯誤
		@respdoc-401 (
			31501000: (APIErrorStatus) 未授權
		) // 未授權
		@respdoc-404 (
			31301000: (APIErrorStatus) 對應 internal role 不存在
		) // 不存在
		@respdoc-500 (
			31201000: (APIErrorStatus) 資料庫錯誤
		) // 內部錯誤
	*/
	@handler upsertRoleMapping
	put /role-mappings (UpsertRoleMappingReq) returns (RoleMappingData)

	@doc "刪除外部 → 內部 role 映射"
	/*
		@respdoc-200 (EmptyOKStatus) // 成功
		@respdoc-400 (
			10101000: (APIErrorStatus) 參數格式錯誤
		) // 參數錯誤
		@respdoc-401 (
			31501000: (APIErrorStatus) 未授權
		) // 未授權
		@respdoc-404 (
			31301000: (APIErrorStatus) 映射不存在
		) // 不存在
		@respdoc-500 (
			31201000: (APIErrorStatus) 資料庫錯誤
		) // 內部錯誤
	*/
	@handler deleteRoleMapping
	delete /role-mappings (DeleteRoleMappingReq)

	@doc "強制重載 Casbin policy（單租戶或所有租戶；同步 + Pub/Sub broadcast）"
	/*
		@respdoc-200 (PolicyReloadOKStatus) // 成功
		@respdoc-401 (
			31501000: (APIErrorStatus) 未授權
		) // 未授權
		@respdoc-500 (
			31201000: (APIErrorStatus) 資料庫錯誤
			31601000: (APIErrorStatus) 系統內部錯誤
		) // 內部錯誤
		@respdoc-501 (
			31605000: (APIErrorStatus) Casbin enforcer 未配置
		) // 未實作
	*/
	@handler reloadPolicy
	post /policy/reload (PolicyReloadReq) returns (PolicyReloadData)
}
