syntax = "proto3";

package memos.api.v1;

import "api/v1/user_service.proto";
import "google/api/annotations.proto";
import "google/api/client.proto";
import "google/api/field_behavior.proto";
import "google/api/resource.proto";
import "google/protobuf/field_mask.proto";
import "google/type/color.proto";

option go_package = "gen/api/v1";

service InstanceService {
  // Gets the instance profile.
  rpc GetInstanceProfile(GetInstanceProfileRequest) returns (InstanceProfile) {
    option (google.api.http) = {get: "/api/v1/instance/profile"};
  }

  // Gets an instance setting.
  rpc GetInstanceSetting(GetInstanceSettingRequest) returns (InstanceSetting) {
    option (google.api.http) = {get: "/api/v1/{name=instance/settings/*}"};
    option (google.api.method_signature) = "name";
  }

  // Updates an instance setting.
  rpc UpdateInstanceSetting(UpdateInstanceSettingRequest) returns (InstanceSetting) {
    option (google.api.http) = {
      patch: "/api/v1/{setting.name=instance/settings/*}"
      body: "setting"
    };
    option (google.api.method_signature) = "setting,update_mask";
  }
}

// Instance profile message containing basic instance information.
message InstanceProfile {
  // Version is the current version of instance.
  string version = 2;

  // Demo indicates if the instance is in demo mode.
  bool demo = 3;

  // Instance URL is the URL of the instance.
  string instance_url = 6;

  // The first administrator who set up this instance.
  // When null, instance requires initial setup (creating the first admin account).
  User admin = 7;
}

// Request for instance profile.
message GetInstanceProfileRequest {}

// An instance setting resource.
message InstanceSetting {
  option (google.api.resource) = {
    type: "memos.api.v1/InstanceSetting"
    pattern: "instance/settings/{setting}"
    singular: "instanceSetting"
    plural: "instanceSettings"
  };

  // The name of the instance setting.
  // Format: instance/settings/{setting}
  string name = 1 [(google.api.field_behavior) = IDENTIFIER];

  oneof value {
    GeneralSetting general_setting = 2;
    StorageSetting storage_setting = 3;
    MemoRelatedSetting memo_related_setting = 4;
    TagsSetting tags_setting = 5;
    NotificationSetting notification_setting = 6;
    AISetting ai_setting = 7;
  }

  // Enumeration of instance setting keys.
  enum Key {
    KEY_UNSPECIFIED = 0;
    // GENERAL is the key for general settings.
    GENERAL = 1;
    // STORAGE is the key for storage settings.
    STORAGE = 2;
    // MEMO_RELATED is the key for memo related settings.
    MEMO_RELATED = 3;
    // TAGS is the key for tag metadata.
    TAGS = 4;
    // NOTIFICATION is the key for notification transport settings.
    NOTIFICATION = 5;
    // AI is the key for AI provider settings.
    AI = 6;
  }

  // General instance settings configuration.
  message GeneralSetting {
    // disallow_user_registration disallows user registration.
    bool disallow_user_registration = 2;
    // disallow_password_auth disallows password authentication.
    bool disallow_password_auth = 3;
    // additional_script is the additional script.
    string additional_script = 4;
    // additional_style is the additional style.
    string additional_style = 5;
    // custom_profile is the custom profile.
    CustomProfile custom_profile = 6;
    // week_start_day_offset is the week start day offset from Sunday.
    // 0: Sunday, 1: Monday, 2: Tuesday, 3: Wednesday, 4: Thursday, 5: Friday, 6: Saturday
    // Default is Sunday.
    int32 week_start_day_offset = 7;

    // disallow_change_username disallows changing username.
    bool disallow_change_username = 8;
    // disallow_change_nickname disallows changing nickname.
    bool disallow_change_nickname = 9;

    // Custom profile configuration for instance branding.
    message CustomProfile {
      string title = 1;
      string description = 2;
      string logo_url = 3;
    }
  }

  // Storage configuration settings for instance attachments.
  message StorageSetting {
    // Storage type enumeration for different storage backends.
    enum StorageType {
      STORAGE_TYPE_UNSPECIFIED = 0;
      // DATABASE is the database storage type.
      DATABASE = 1;
      // LOCAL is the local storage type.
      LOCAL = 2;
      // S3 is the S3 storage type.
      S3 = 3;
    }
    // storage_type is the storage type.
    StorageType storage_type = 1;
    // The template of file path.
    // e.g. assets/{timestamp}_{filename}
    string filepath_template = 2;
    // The max upload size in megabytes.
    int64 upload_size_limit_mb = 3;

    // S3 configuration for cloud storage backend.
    // Reference: https://developers.cloudflare.com/r2/examples/aws/aws-sdk-go/
    message S3Config {
      string access_key_id = 1;
      string access_key_secret = 2;
      string endpoint = 3;
      string region = 4;
      string bucket = 5;
      bool use_path_style = 6;
    }
    // The S3 config.
    S3Config s3_config = 4;
  }

  // Memo-related instance settings and policies.
  message MemoRelatedSetting {
    // display_with_update_time orders and displays memo with update time.
    bool display_with_update_time = 2;
    // content_length_limit is the limit of content length. Unit is byte.
    int32 content_length_limit = 3;
    // enable_double_click_edit enables editing on double click.
    bool enable_double_click_edit = 4;
    // reactions is the list of reactions.
    repeated string reactions = 7;
  }

  // Metadata for a tag.
  message TagMetadata {
    // Optional background color for the tag label.
    // When unset, the default tag color is used.
    google.type.Color background_color = 1;
    // Whether memos with this tag should have their content blurred.
    bool blur_content = 2;
  }

  // Tag metadata configuration.
  message TagsSetting {
    // Map of tag name pattern to tag metadata.
    // Each key is treated as an anchored regular expression (^pattern$),
    // so a single entry like "project/.*" matches all tags under that prefix.
    // Exact tag names are also valid (they are trivially valid regex patterns).
    map<string, TagMetadata> tags = 1;
  }

  // Notification transport configuration.
  message NotificationSetting {
    EmailSetting email = 1;

    // Email delivery configuration for notifications.
    message EmailSetting {
      bool enabled = 1;
      string smtp_host = 2;
      int32 smtp_port = 3;
      string smtp_username = 4;
      string smtp_password = 5;
      string from_email = 6;
      string from_name = 7;
      string reply_to = 8;
      bool use_tls = 9;
      bool use_ssl = 10;
    }
  }

  // AI provider configuration settings.
  message AISetting {
    // providers is the list of AI provider configurations available instance-wide.
    repeated AIProviderConfig providers = 1;
  }

  // AIProviderConfig represents one callable AI provider connection.
  message AIProviderConfig {
    string id = 1;
    string title = 2;
    AIProviderType type = 3;
    string endpoint = 4;
    // api_key is write-only and is never returned by GetInstanceSetting.
    string api_key = 5 [(google.api.field_behavior) = INPUT_ONLY];
    // api_key_set indicates whether an API key is stored for this provider.
    bool api_key_set = 8 [(google.api.field_behavior) = OUTPUT_ONLY];
    // api_key_hint is a masked hint for the stored API key.
    string api_key_hint = 9 [(google.api.field_behavior) = OUTPUT_ONLY];
  }

  // AIProviderType is the provider implementation type.
  enum AIProviderType {
    AI_PROVIDER_TYPE_UNSPECIFIED = 0;
    OPENAI = 1;
    GEMINI = 2;
  }
}

// Request message for GetInstanceSetting method.
message GetInstanceSettingRequest {
  // The resource name of the instance setting.
  // Format: instance/settings/{setting}
  string name = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {type: "memos.api.v1/InstanceSetting"}
  ];
}

// Request message for UpdateInstanceSetting method.
message UpdateInstanceSettingRequest {
  // The instance setting resource which replaces the resource on the server.
  InstanceSetting setting = 1 [(google.api.field_behavior) = REQUIRED];

  // The list of fields to update.
  google.protobuf.FieldMask update_mask = 2 [(google.api.field_behavior) = OPTIONAL];
}
