syntax = "proto3";

package coda.admin.v1;

option java_package = "coda.admin.v1";
option java_outer_classname = "AccessProto";

import "coda/admin/v1/access_types.proto";
import "coda/admin/v1/types.proto";

service AccessService {
  // Check whether a user has a specific permission in a tenant.
  rpc Check(CheckRequest) returns (CheckResponse);

  // Check multiple permissions in a single round-trip.
  rpc CheckBatch(CheckBatchRequest) returns (CheckBatchResponse);

  // Return the full effective permission set for a user in a tenant.
  rpc GetEffective(GetEffectiveRequest) returns (GetEffectiveResponse);

  // Resolve a tenant by slug or ID and return its info.
  rpc ResolveTenant(ResolveTenantRequest) returns (ResolveTenantResponse);
}

// ─── Check ───────────────────────────────────────────────────────────

message CheckRequest {
  string tenant_id = 1;
  string user_id = 2;
  string permission = 3;
  // Optional resource context for condition evaluation
  string resource_type = 4;
  string resource_id = 5;
}

message CheckResponse {
  Outcome outcome = 1;
  // Human-readable reason when denied or step-up required
  string reason = 2;
  // Permissions that would satisfy step-up, if outcome is STEP_UP_REQUIRED
  repeated string required_permissions = 3;
  // Structured detail about the permission check decision.
  CheckDetail detail = 4;
}

// Structured detail attached to CheckResponse/CheckBatchResult explaining
// the decision. Enables callers to programmatically inspect the result
// (e.g., which permission was missing, which role granted it).
message CheckDetail {
  // The permission that was checked.
  string permission = 1;
  // The outcome of the check.
  Outcome outcome = 2;
  // Human-readable explanation (e.g., "role:admin grants accounts:read").
  string reason = 3;
  // Permissions the user would need to be granted access (only on DENIED).
  repeated string missing_permissions = 4;
  // The role that granted the permission (only on GRANTED).
  string granting_role = 5;
}

// ─── CheckBatch ──────────────────────────────────────────────────────

// NOTE: The CheckBatch design deviates from the original spec (which used
// `repeated string permissions` + `map<string, Outcome> results`).
// This implementation uses structured items with resource context support,
// enabling resource-scoped batch checks. The spec should be updated to match.

message CheckBatchRequest {
  string tenant_id = 1;
  string user_id = 2;
  repeated CheckBatchItem items = 3;
}

message CheckBatchItem {
  string permission = 1;
  string resource_type = 2;
  string resource_id = 3;
}

message CheckBatchResponse {
  repeated CheckBatchResult results = 1;
}

message CheckBatchResult {
  string permission = 1;
  Outcome outcome = 2;
  string reason = 3;
}

// ─── GetEffective ────────────────────────────────────────────────────

message GetEffectiveRequest {
  string tenant_id = 1;
  string user_id = 2;
}

message GetEffectiveResponse {
  repeated string granted_permissions = 1;
  repeated string denied_permissions = 2;
  repeated UserRoleInfo roles = 3;
  bool is_super_admin = 4;
  SuperAdminLevel super_admin_level = 5;
}

// ─── ResolveTenant ───────────────────────────────────────────────────

message ResolveTenantRequest {
  // Resolve by slug or ID (explicit tenant selection)
  string slug = 1;
  string tenant_id = 2;
  // Identity fields for auto-provisioning (passed from JWT by middleware)
  string identity_id = 3;
  string email = 4;
}

message ResolveTenantResponse {
  TenantInfo tenant = 1;
  TenantUserInfo membership = 2;
  // True if the user was auto-provisioned during this call
  bool provisioned = 3;
}
