syntax = "proto3";

package forest.v1;

import "google/protobuf/timestamp.proto";

// UsersService handles user management, authentication, and profile operations.
service UsersService {
  // Authentication
  rpc Register(RegisterRequest) returns (RegisterResponse);
  rpc Login(LoginRequest) returns (LoginResponse);
  rpc RefreshToken(RefreshTokenRequest) returns (RefreshTokenResponse);
  rpc Logout(LogoutRequest) returns (LogoutResponse);

  // User CRUD
  rpc GetUser(GetUserRequest) returns (GetUserResponse);
  rpc UpdateUser(UpdateUserRequest) returns (UpdateUserResponse);
  rpc DeleteUser(DeleteUserRequest) returns (DeleteUserResponse);
  rpc ListUsers(ListUsersRequest) returns (ListUsersResponse);

  // Stats
  rpc GetUserStats(GetUserStatsRequest) returns (GetUserStatsResponse);

  // Password management
  rpc ChangePassword(ChangePasswordRequest) returns (ChangePasswordResponse);

  // Email management
  rpc AddEmail(AddEmailRequest) returns (AddEmailResponse);
  rpc VerifyEmail(VerifyEmailRequest) returns (VerifyEmailResponse);
  rpc RemoveEmail(RemoveEmailRequest) returns (RemoveEmailResponse);

  // Social / OAuth login
  rpc OAuthLogin(OAuthLoginRequest) returns (OAuthLoginResponse);
  rpc LinkOAuthProvider(LinkOAuthProviderRequest) returns (LinkOAuthProviderResponse);
  rpc UnlinkOAuthProvider(UnlinkOAuthProviderRequest) returns (UnlinkOAuthProviderResponse);

  // Personal access tokens
  rpc CreatePersonalAccessToken(CreatePersonalAccessTokenRequest) returns (CreatePersonalAccessTokenResponse);
  rpc ListPersonalAccessTokens(ListPersonalAccessTokensRequest) returns (ListPersonalAccessTokensResponse);
  rpc DeletePersonalAccessToken(DeletePersonalAccessTokenRequest) returns (DeletePersonalAccessTokenResponse);

  // Token introspection (requires valid access token)
  rpc TokenInfo(TokenInfoRequest) returns (TokenInfoResponse);

  // MFA
  rpc SetupMfa(SetupMfaRequest) returns (SetupMfaResponse);
  rpc VerifyMfa(VerifyMfaRequest) returns (VerifyMfaResponse);
  rpc DisableMfa(DisableMfaRequest) returns (DisableMfaResponse);
}

// ─── Core types ──────────────────────────────────────────────────────

message User {
  string user_id = 1; // UUID
  string username = 2;
  repeated UserEmail emails = 3;
  repeated OAuthConnection oauth_connections = 4;
  bool mfa_enabled = 5;
  google.protobuf.Timestamp created_at = 6;
  google.protobuf.Timestamp updated_at = 7;
}

message UserEmail {
  string email = 1;
  bool verified = 2;
}

enum OAuthProvider {
  OAUTH_PROVIDER_UNSPECIFIED = 0;
  OAUTH_PROVIDER_GITHUB = 1;
  OAUTH_PROVIDER_GOOGLE = 2;
  OAUTH_PROVIDER_GITLAB = 3;
  OAUTH_PROVIDER_MICROSOFT = 4;
}

message OAuthConnection {
  OAuthProvider provider = 1;
  string provider_user_id = 2;
  string provider_email = 3;
  google.protobuf.Timestamp linked_at = 4;
}

// ─── Authentication ──────────────────────────────────────────────────

message RegisterRequest {
  string username = 1;
  string email = 2;
  string password = 3;
}

message RegisterResponse {
  User user = 1;
  AuthTokens tokens = 2;
}

message LoginRequest {
  // Login with either username or email
  oneof identifier {
    string username = 1;
    string email = 2;
  }
  string password = 3;
}

message LoginResponse {
  User user = 1;
  AuthTokens tokens = 2;
}

message RefreshTokenRequest {
  string refresh_token = 1;
}

message RefreshTokenResponse {
  AuthTokens tokens = 1;
}

message LogoutRequest {
  string refresh_token = 1;
}

message LogoutResponse {}

message AuthTokens {
  string access_token = 1;
  string refresh_token = 2;
  int64 expires_in_seconds = 3;
}

// ─── Token introspection ─────────────────────────────────────────────

message TokenInfoRequest {}

message TokenInfoResponse {
  string user_id = 1;
  int64 expires_at = 2; // Unix timestamp (seconds)
}

// ─── User CRUD ───────────────────────────────────────────────────────

message GetUserRequest {
  oneof identifier {
    string user_id = 1;
    string username = 2;
    string email = 3;
  }
}

message GetUserResponse {
  User user = 1;
}

message UpdateUserRequest {
  string user_id = 1;
  optional string username = 2;
}

message UpdateUserResponse {
  User user = 1;
}

message DeleteUserRequest {
  string user_id = 1;
}

message DeleteUserResponse {}

message ListUsersRequest {
  int32 page_size = 1;
  string page_token = 2;
  optional string search = 3; // search across username, email
}

message ListUsersResponse {
  repeated User users = 1;
  string next_page_token = 2;
  int32 total_count = 3;
}

// ─── Password management ─────────────────────────────────────────────

message ChangePasswordRequest {
  string user_id = 1;
  string current_password = 2;
  string new_password = 3;
}

message ChangePasswordResponse {}

// ─── Email management ────────────────────────────────────────────────

message AddEmailRequest {
  string user_id = 1;
  string email = 2;
}

message AddEmailResponse {
  UserEmail email = 1;
}

message VerifyEmailRequest {
  string user_id = 1;
  string email = 2;
}

message VerifyEmailResponse {}

message RemoveEmailRequest {
  string user_id = 1;
  string email = 2;
}

message RemoveEmailResponse {}

// ─── OAuth / Social login ────────────────────────────────────────────

message OAuthLoginRequest {
  OAuthProvider provider = 1;
  string authorization_code = 2;
  string redirect_uri = 3;
}

message OAuthLoginResponse {
  User user = 1;
  AuthTokens tokens = 2;
  bool is_new_user = 3;
}

message LinkOAuthProviderRequest {
  string user_id = 1;
  OAuthProvider provider = 2;
  string authorization_code = 3;
  string redirect_uri = 4;
}

message LinkOAuthProviderResponse {
  OAuthConnection connection = 1;
}

message UnlinkOAuthProviderRequest {
  string user_id = 1;
  OAuthProvider provider = 2;
}

message UnlinkOAuthProviderResponse {}

// ─── Personal access tokens ──────────────────────────────────────────

message PersonalAccessToken {
  string token_id = 1; // UUID
  string name = 2;
  repeated string scopes = 3;
  google.protobuf.Timestamp expires_at = 4;
  google.protobuf.Timestamp last_used = 5;
  google.protobuf.Timestamp created_at = 6;
}

message CreatePersonalAccessTokenRequest {
  string user_id = 1;
  string name = 2;
  repeated string scopes = 3;
  // Duration in seconds; 0 = no expiry
  int64 expires_in_seconds = 4;
}

message CreatePersonalAccessTokenResponse {
  PersonalAccessToken token = 1;
  // The raw token value, only returned on creation
  string raw_token = 2;
}

message ListPersonalAccessTokensRequest {
  string user_id = 1;
}

message ListPersonalAccessTokensResponse {
  repeated PersonalAccessToken tokens = 1;
}

message DeletePersonalAccessTokenRequest {
  string token_id = 1;
}

message DeletePersonalAccessTokenResponse {}

// ─── Stats ──────────────────────────────────────────────────────────

message GetUserStatsRequest {
  oneof identifier {
    string user_id = 1;
    string username = 2;
  }
}

message GetUserStatsResponse {
  UserStats stats = 1;
}

message UserStats {
  int64 total_releases = 1;
  int64 successful_releases = 2;
  int64 failed_releases = 3;
  int64 in_progress_releases = 4;
  int64 total_annotations = 5;
  int64 total_uploads = 6;
}

// ─── MFA ─────────────────────────────────────────────────────────────

enum MfaType {
  MFA_TYPE_UNSPECIFIED = 0;
  MFA_TYPE_TOTP = 1;
}

message SetupMfaRequest {
  string user_id = 1;
  MfaType mfa_type = 2;
}

message SetupMfaResponse {
  string mfa_id = 1; // UUID
  // TOTP provisioning URI (otpauth://...)
  string provisioning_uri = 2;
  // Base32-encoded secret for manual entry
  string secret = 3;
}

message VerifyMfaRequest {
  string mfa_id = 1;
  // The TOTP code to verify setup
  string code = 2;
}

message VerifyMfaResponse {}

message DisableMfaRequest {
  string user_id = 1;
  // Current TOTP code to confirm disable
  string code = 2;
}

message DisableMfaResponse {}
