syntax = "proto3";

package iam.v1;

option go_package = "github.com/cloud/iam/proto/iam/v1;iamv1";

// ============================================================================
// Authorization Service
// ============================================================================

// IamAuthz provides authorization decision (PDP - Policy Decision Point)
service IamAuthz {
    // Authorize checks if a principal is allowed to perform an action on a resource
    rpc Authorize(AuthorizeRequest) returns (AuthorizeResponse);

    // BatchAuthorize checks multiple authorization requests at once
    rpc BatchAuthorize(BatchAuthorizeRequest) returns (BatchAuthorizeResponse);
}

message AuthorizeRequest {
    // Principal making the request
    PrincipalRef principal = 1;

    // Action being performed (e.g., "compute:instances:create")
    string action = 2;

    // Resource being accessed
    ResourceRef resource = 3;

    // Request context (source IP, metadata, etc.)
    AuthzContext context = 4;
}

message AuthorizeResponse {
    // Whether the action is allowed
    bool allowed = 1;

    // Reason for denial (if not allowed)
    string reason = 2;

    // Matched binding ID (for auditing)
    string matched_binding = 3;

    // Matched role (for auditing)
    string matched_role = 4;
}

message BatchAuthorizeRequest {
    repeated AuthorizeRequest requests = 1;
}

message BatchAuthorizeResponse {
    repeated AuthorizeResponse responses = 1;
}

message AuthzContext {
    // Source IP address
    string source_ip = 1;

    // Request timestamp (Unix seconds)
    uint64 timestamp = 2;

    // HTTP method (if applicable)
    string http_method = 3;

    // Request path (if applicable)
    string request_path = 4;

    // Additional metadata
    map<string, string> metadata = 5;
}

// ============================================================================
// Token Service
// ============================================================================

// IamToken provides token issuance and validation
service IamToken {
    // IssueToken creates a new internal token
    rpc IssueToken(IssueTokenRequest) returns (IssueTokenResponse);

    // ValidateToken validates a token and returns its claims
    rpc ValidateToken(ValidateTokenRequest) returns (ValidateTokenResponse);

    // RevokeToken revokes a token
    rpc RevokeToken(RevokeTokenRequest) returns (RevokeTokenResponse);

    // RefreshToken exchanges a token for a new one
    rpc RefreshToken(RefreshTokenRequest) returns (RefreshTokenResponse);
}

// IamCredential manages S3-style access/secret key credentials.
service IamCredential {
    rpc CreateS3Credential(CreateS3CredentialRequest) returns (CreateS3CredentialResponse);
    rpc GetSecretKey(GetSecretKeyRequest) returns (GetSecretKeyResponse);
    rpc ListCredentials(ListCredentialsRequest) returns (ListCredentialsResponse);
    rpc RevokeCredential(RevokeCredentialRequest) returns (RevokeCredentialResponse);
}

message IssueTokenRequest {
    // Principal to issue token for
    string principal_id = 1;

    // Principal kind
    PrincipalKind principal_kind = 2;

    // Roles to include in the token
    repeated string roles = 3;

    // Scope for the token
    Scope scope = 4;

    // Token TTL in seconds
    uint64 ttl_seconds = 5;
}

message IssueTokenResponse {
    // The issued token
    string token = 1;

    // Expiration timestamp (Unix seconds)
    uint64 expires_at = 2;

    // Session ID
    string session_id = 3;
}

message ValidateTokenRequest {
    // Token to validate
    string token = 1;
}

message ValidateTokenResponse {
    // Whether the token is valid
    bool valid = 1;

    // Token claims (if valid)
    InternalTokenClaims claims = 2;

    // Reason for invalidity (if not valid)
    string reason = 3;
}

message RevokeTokenRequest {
    // Token to revoke (or session_id)
    string token = 1;

    // Revocation reason
    string reason = 2;
}

message RevokeTokenResponse {
    // Whether revocation was successful
    bool success = 1;
}

message RefreshTokenRequest {
    // Current token
    string token = 1;

    // New TTL (optional, defaults to original TTL)
    uint64 ttl_seconds = 2;
}

message RefreshTokenResponse {
    // New token
    string token = 1;

    // Expiration timestamp
    uint64 expires_at = 2;
}

message CreateS3CredentialRequest {
    string principal_id = 1;
    string description = 2;
    optional uint64 expires_at = 3;
    optional string org_id = 4;
    optional string project_id = 5;
    PrincipalKind principal_kind = 6;
}

message CreateS3CredentialResponse {
    string access_key_id = 1;
    string secret_key = 2;
    uint64 created_at = 3;
    optional uint64 expires_at = 4;
}

message GetSecretKeyRequest {
    string access_key_id = 1;
}

message GetSecretKeyResponse {
    string secret_key = 1;
    string principal_id = 2;
    optional uint64 expires_at = 3;
    optional string org_id = 4;
    optional string project_id = 5;
    PrincipalKind principal_kind = 6;
}

message ListCredentialsRequest {
    string principal_id = 1;
}

message Credential {
    string access_key_id = 1;
    string principal_id = 2;
    uint64 created_at = 3;
    optional uint64 expires_at = 4;
    bool revoked = 5;
    string description = 6;
    optional string org_id = 7;
    optional string project_id = 8;
    PrincipalKind principal_kind = 9;
}

message ListCredentialsResponse {
    repeated Credential credentials = 1;
}

message RevokeCredentialRequest {
    string access_key_id = 1;
}

message RevokeCredentialResponse {
    bool success = 1;
}

message InternalTokenClaims {
    string principal_id = 1;
    PrincipalKind principal_kind = 2;
    string principal_name = 3;
    repeated string roles = 4;
    Scope scope = 5;
    optional string org_id = 6;
    optional string project_id = 7;
    optional string node_id = 8;
    uint64 iat = 9;
    uint64 exp = 10;
    string session_id = 11;
    string auth_method = 12;
}

// ============================================================================
// Admin Service
// ============================================================================

// IamAdmin provides administrative operations
service IamAdmin {
    // Principal management
    rpc CreatePrincipal(CreatePrincipalRequest) returns (Principal);
    rpc GetPrincipal(GetPrincipalRequest) returns (Principal);
    rpc UpdatePrincipal(UpdatePrincipalRequest) returns (Principal);
    rpc DeletePrincipal(DeletePrincipalRequest) returns (DeletePrincipalResponse);
    rpc ListPrincipals(ListPrincipalsRequest) returns (ListPrincipalsResponse);

    // Organization management
    rpc CreateOrganization(CreateOrganizationRequest) returns (Organization);
    rpc GetOrganization(GetOrganizationRequest) returns (Organization);
    rpc UpdateOrganization(UpdateOrganizationRequest) returns (Organization);
    rpc DeleteOrganization(DeleteOrganizationRequest) returns (DeleteOrganizationResponse);
    rpc ListOrganizations(ListOrganizationsRequest) returns (ListOrganizationsResponse);

    // Project management
    rpc CreateProject(CreateProjectRequest) returns (Project);
    rpc GetProject(GetProjectRequest) returns (Project);
    rpc UpdateProject(UpdateProjectRequest) returns (Project);
    rpc DeleteProject(DeleteProjectRequest) returns (DeleteProjectResponse);
    rpc ListProjects(ListProjectsRequest) returns (ListProjectsResponse);

    // Role management
    rpc CreateRole(CreateRoleRequest) returns (Role);
    rpc GetRole(GetRoleRequest) returns (Role);
    rpc UpdateRole(UpdateRoleRequest) returns (Role);
    rpc DeleteRole(DeleteRoleRequest) returns (DeleteRoleResponse);
    rpc ListRoles(ListRolesRequest) returns (ListRolesResponse);

    // Binding management
    rpc CreateBinding(CreateBindingRequest) returns (PolicyBinding);
    rpc GetBinding(GetBindingRequest) returns (PolicyBinding);
    rpc UpdateBinding(UpdateBindingRequest) returns (PolicyBinding);
    rpc DeleteBinding(DeleteBindingRequest) returns (DeleteBindingResponse);
    rpc ListBindings(ListBindingsRequest) returns (ListBindingsResponse);

    // Group membership management
    rpc AddGroupMember(AddGroupMemberRequest) returns (AddGroupMemberResponse);
    rpc RemoveGroupMember(RemoveGroupMemberRequest) returns (RemoveGroupMemberResponse);
    rpc ListGroupMembers(ListGroupMembersRequest) returns (ListGroupMembersResponse);
    rpc ListPrincipalGroups(ListPrincipalGroupsRequest) returns (ListPrincipalGroupsResponse);
}

// ----------------------------------------------------------------------------
// Principal Messages
// ----------------------------------------------------------------------------

message CreatePrincipalRequest {
    // Principal ID (unique identifier)
    string id = 1;

    // Principal kind
    PrincipalKind kind = 2;

    // Display name
    string name = 3;

    // Organization ID (optional)
    optional string org_id = 4;

    // Project ID (for service accounts)
    optional string project_id = 5;

    // Email (for users)
    optional string email = 6;

    // Metadata
    map<string, string> metadata = 7;
}

message GetPrincipalRequest {
    PrincipalRef principal = 1;
}

message UpdatePrincipalRequest {
    // Principal to update
    PrincipalRef principal = 1;

    // Fields to update
    optional string name = 2;
    optional string email = 3;
    map<string, string> metadata = 4;
    optional bool enabled = 5;
}

message DeletePrincipalRequest {
    PrincipalRef principal = 1;
}

message DeletePrincipalResponse {
    bool deleted = 1;
}

message ListPrincipalsRequest {
    // Filter by kind
    optional PrincipalKind kind = 1;

    // Filter by org
    optional string org_id = 2;

    // Filter by project
    optional string project_id = 3;

    // Pagination
    int32 page_size = 4;
    string page_token = 5;
}

message ListPrincipalsResponse {
    repeated Principal principals = 1;
    string next_page_token = 2;
}

// ----------------------------------------------------------------------------
// Organization Messages
// ----------------------------------------------------------------------------

message CreateOrganizationRequest {
    string id = 1;
    string name = 2;
    string description = 3;
    map<string, string> metadata = 4;
}

message GetOrganizationRequest {
    string id = 1;
}

message UpdateOrganizationRequest {
    string id = 1;
    optional string name = 2;
    optional string description = 3;
    map<string, string> metadata = 4;
    optional bool enabled = 5;
}

message DeleteOrganizationRequest {
    string id = 1;
}

message DeleteOrganizationResponse {
    bool deleted = 1;
}

message ListOrganizationsRequest {
    bool include_disabled = 1;
    int32 page_size = 2;
    string page_token = 3;
}

message ListOrganizationsResponse {
    repeated Organization organizations = 1;
    string next_page_token = 2;
}

// ----------------------------------------------------------------------------
// Project Messages
// ----------------------------------------------------------------------------

message CreateProjectRequest {
    string id = 1;
    string org_id = 2;
    string name = 3;
    string description = 4;
    map<string, string> metadata = 5;
}

message GetProjectRequest {
    string org_id = 1;
    string id = 2;
}

message UpdateProjectRequest {
    string org_id = 1;
    string id = 2;
    optional string name = 3;
    optional string description = 4;
    map<string, string> metadata = 5;
    optional bool enabled = 6;
}

message DeleteProjectRequest {
    string org_id = 1;
    string id = 2;
}

message DeleteProjectResponse {
    bool deleted = 1;
}

message ListProjectsRequest {
    optional string org_id = 1;
    bool include_disabled = 2;
    int32 page_size = 3;
    string page_token = 4;
}

message ListProjectsResponse {
    repeated Project projects = 1;
    string next_page_token = 2;
}

// ----------------------------------------------------------------------------
// Role Messages
// ----------------------------------------------------------------------------

message CreateRoleRequest {
    // Role name (unique identifier)
    string name = 1;

    // Display name
    string display_name = 2;

    // Description
    string description = 3;

    // Scope where this role can be applied
    Scope scope = 4;

    // Permissions granted by this role
    repeated Permission permissions = 5;
}

message GetRoleRequest {
    string name = 1;
}

message UpdateRoleRequest {
    // Role to update
    string name = 1;

    // Fields to update
    optional string display_name = 2;
    optional string description = 3;
    repeated Permission permissions = 4;
}

message DeleteRoleRequest {
    string name = 1;
}

message DeleteRoleResponse {
    bool deleted = 1;
}

message ListRolesRequest {
    // Filter by scope
    optional Scope scope = 1;

    // Include builtin roles
    bool include_builtin = 2;

    // Pagination
    int32 page_size = 3;
    string page_token = 4;
}

message ListRolesResponse {
    repeated Role roles = 1;
    string next_page_token = 2;
}

// ----------------------------------------------------------------------------
// Binding Messages
// ----------------------------------------------------------------------------

message CreateBindingRequest {
    // Principal to bind
    PrincipalRef principal = 1;

    // Role to assign (e.g., "roles/ProjectAdmin")
    string role = 2;

    // Scope for the binding
    Scope scope = 3;

    // Optional condition
    optional Condition condition = 4;

    // Expiration (optional, Unix seconds)
    optional uint64 expires_at = 5;
}

message GetBindingRequest {
    string id = 1;
}

message UpdateBindingRequest {
    // Binding to update
    string id = 1;

    // Fields to update
    optional Condition condition = 2;
    optional uint64 expires_at = 3;
    optional bool enabled = 4;
}

message DeleteBindingRequest {
    string id = 1;
}

message DeleteBindingResponse {
    bool deleted = 1;
}

message ListBindingsRequest {
    // Filter by principal
    optional PrincipalRef principal = 1;

    // Filter by role
    optional string role = 2;

    // Filter by scope
    optional Scope scope = 3;

    // Include disabled bindings
    bool include_disabled = 4;

    // Pagination
    int32 page_size = 5;
    string page_token = 6;
}

message ListBindingsResponse {
    repeated PolicyBinding bindings = 1;
    string next_page_token = 2;
}

// ----------------------------------------------------------------------------
// Group Membership Messages
// ----------------------------------------------------------------------------

message AddGroupMemberRequest {
    string group_id = 1;
    PrincipalRef principal = 2;
}

message AddGroupMemberResponse {
    bool added = 1;
}

message RemoveGroupMemberRequest {
    string group_id = 1;
    PrincipalRef principal = 2;
}

message RemoveGroupMemberResponse {
    bool removed = 1;
}

message ListGroupMembersRequest {
    string group_id = 1;
    int32 page_size = 2;
    string page_token = 3;
}

message ListGroupMembersResponse {
    repeated Principal members = 1;
    string next_page_token = 2;
}

message ListPrincipalGroupsRequest {
    PrincipalRef principal = 1;
    int32 page_size = 2;
    string page_token = 3;
}

message ListPrincipalGroupsResponse {
    repeated Principal groups = 1;
    string next_page_token = 2;
}

// ============================================================================
// Common Types
// ============================================================================

enum PrincipalKind {
    PRINCIPAL_KIND_UNSPECIFIED = 0;
    PRINCIPAL_KIND_USER = 1;
    PRINCIPAL_KIND_SERVICE_ACCOUNT = 2;
    PRINCIPAL_KIND_GROUP = 3;
}

message PrincipalRef {
    PrincipalKind kind = 1;
    string id = 2;
}

message Principal {
    string id = 1;
    PrincipalKind kind = 2;
    string name = 3;
    optional string org_id = 4;
    optional string project_id = 5;
    optional string email = 6;
    optional string oidc_sub = 7;
    optional string node_id = 8;
    map<string, string> metadata = 9;
    uint64 created_at = 10;
    uint64 updated_at = 11;
    bool enabled = 12;
}

message Organization {
    string id = 1;
    string name = 2;
    string description = 3;
    map<string, string> metadata = 4;
    uint64 created_at = 5;
    uint64 updated_at = 6;
    bool enabled = 7;
}

message Project {
    string id = 1;
    string org_id = 2;
    string name = 3;
    string description = 4;
    map<string, string> metadata = 5;
    uint64 created_at = 6;
    uint64 updated_at = 7;
    bool enabled = 8;
}

message ResourceRef {
    // Resource kind (e.g., "instance", "volume")
    string kind = 1;

    // Resource ID
    string id = 2;

    // Organization ID
    string org_id = 3;

    // Project ID
    string project_id = 4;

    // Owner ID (optional)
    optional string owner_id = 5;

    // Node ID (optional)
    optional string node_id = 6;

    // Region (optional)
    optional string region = 7;

    // Tags
    map<string, string> tags = 8;
}

message Scope {
    oneof scope {
        bool system = 1;
        OrgScope org = 2;
        ProjectScope project = 3;
        ResourceScope resource = 4;
    }
}

// Organization scope
message OrgScope {
    string id = 1;
}

// Project scope with parent org context
message ProjectScope {
    string id = 1;
    string org_id = 2;
}

// Resource scope with parent project and org context
message ResourceScope {
    string id = 1;
    string project_id = 2;
    string org_id = 3;
}

message Role {
    string name = 1;
    string display_name = 2;
    string description = 3;
    Scope scope = 4;
    repeated Permission permissions = 5;
    bool builtin = 6;
    uint64 created_at = 7;
    uint64 updated_at = 8;
}

message Permission {
    // Action pattern (e.g., "compute:instances:create")
    string action = 1;

    // Resource pattern (e.g., "project/*/instances/*")
    string resource_pattern = 2;

    // Optional condition
    optional Condition condition = 3;
}

message PolicyBinding {
    string id = 1;
    PrincipalRef principal = 2;
    string role = 3;
    Scope scope = 4;
    optional Condition condition = 5;
    uint64 created_at = 6;
    uint64 updated_at = 7;
    string created_by = 8;
    optional uint64 expires_at = 9;
    bool enabled = 10;
}

message Condition {
    ConditionExpr expression = 1;
}

message ConditionExpr {
    oneof expr {
        StringEqualsExpr string_equals = 1;
        StringNotEqualsExpr string_not_equals = 2;
        StringLikeExpr string_like = 3;
        StringNotLikeExpr string_not_like = 4;
        NumericEqualsExpr numeric_equals = 5;
        NumericLessThanExpr numeric_less_than = 6;
        NumericGreaterThanExpr numeric_greater_than = 7;
        IpAddressExpr ip_address = 8;
        NotIpAddressExpr not_ip_address = 9;
        TimeBetweenExpr time_between = 10;
        ExistsExpr exists = 11;
        StringEqualsAnyExpr string_equals_any = 12;
        BoolExpr bool_expr = 13;
        AndExpr and_expr = 14;
        OrExpr or_expr = 15;
        NotExpr not_expr = 16;
    }
}

message StringEqualsExpr {
    string key = 1;
    string value = 2;
}

message StringNotEqualsExpr {
    string key = 1;
    string value = 2;
}

message StringLikeExpr {
    string key = 1;
    string pattern = 2;
}

message StringNotLikeExpr {
    string key = 1;
    string pattern = 2;
}

message NumericEqualsExpr {
    string key = 1;
    int64 value = 2;
}

message NumericLessThanExpr {
    string key = 1;
    int64 value = 2;
}

message NumericGreaterThanExpr {
    string key = 1;
    int64 value = 2;
}

message IpAddressExpr {
    string key = 1;
    string cidr = 2;
}

message NotIpAddressExpr {
    string key = 1;
    string cidr = 2;
}

message TimeBetweenExpr {
    string start = 1;
    string end = 2;
}

message ExistsExpr {
    string key = 1;
}

message StringEqualsAnyExpr {
    string key = 1;
    repeated string values = 2;
}

message BoolExpr {
    string key = 1;
    bool value = 2;
}

message AndExpr {
    repeated ConditionExpr expressions = 1;
}

message OrExpr {
    repeated ConditionExpr expressions = 1;
}

message NotExpr {
    ConditionExpr expression = 1;
}
