// Copyright: Ankitects Pty Ltd and contributors
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html

syntax = "proto3";

option java_multiple_files = true;
// the DeckConfig message clashes with the name of the file
option java_outer_classname = "DeckConf";

package anki.deck_config;

import "anki/generic.proto";
import "anki/collection.proto";
import "anki/decks.proto";

service DeckConfigService {
  rpc AddOrUpdateDeckConfigLegacy(generic.Json) returns (DeckConfigId);
  rpc GetDeckConfig(DeckConfigId) returns (DeckConfig);
  rpc AllDeckConfigLegacy(generic.Empty) returns (generic.Json);
  rpc GetDeckConfigLegacy(DeckConfigId) returns (generic.Json);
  rpc NewDeckConfigLegacy(generic.Empty) returns (generic.Json);
  rpc RemoveDeckConfig(DeckConfigId) returns (generic.Empty);
  rpc GetDeckConfigsForUpdate(decks.DeckId) returns (DeckConfigsForUpdate);
  rpc UpdateDeckConfigs(UpdateDeckConfigsRequest)
      returns (collection.OpChanges);
}

// Implicitly includes any of the above methods that are not listed in the
// backend service.
service BackendDeckConfigService {}

message DeckConfigId {
  int64 dcid = 1;
}

message DeckConfig {
  message Config {
    enum NewCardInsertOrder {
      NEW_CARD_INSERT_ORDER_DUE = 0;
      NEW_CARD_INSERT_ORDER_RANDOM = 1;
    }
    enum NewCardGatherPriority {
      // Decks in alphabetical order (preorder), then ascending position.
      // Siblings are consecutive, provided they have the same position.
      NEW_CARD_GATHER_PRIORITY_DECK = 0;
      // Notes are randomly picked from each deck in alphabetical order.
      // Siblings are consecutive, provided they have the same position.
      NEW_CARD_GATHER_PRIORITY_DECK_THEN_RANDOM_NOTES = 5;
      // Ascending position.
      // Siblings are consecutive, provided they have the same position.
      NEW_CARD_GATHER_PRIORITY_LOWEST_POSITION = 1;
      // Descending position.
      // Siblings are consecutive, provided they have the same position.
      NEW_CARD_GATHER_PRIORITY_HIGHEST_POSITION = 2;
      // Siblings are consecutive.
      NEW_CARD_GATHER_PRIORITY_RANDOM_NOTES = 3;
      // Siblings are neither grouped nor ordered.
      NEW_CARD_GATHER_PRIORITY_RANDOM_CARDS = 4;
    }
    enum NewCardSortOrder {
      // Ascending card template ordinal.
      // For a given ordinal, cards appear in gather order.
      NEW_CARD_SORT_ORDER_TEMPLATE = 0;
      // Preserves original gather order (eg deck order).
      NEW_CARD_SORT_ORDER_NO_SORT = 1;
      // Ascending card template ordinal.
      // For a given ordinal, cards appear in random order.
      NEW_CARD_SORT_ORDER_TEMPLATE_THEN_RANDOM = 2;
      // Random note order. For a given note, cards appear in template order.
      NEW_CARD_SORT_ORDER_RANDOM_NOTE_THEN_TEMPLATE = 3;
      // Fully randomized order.
      NEW_CARD_SORT_ORDER_RANDOM_CARD = 4;
    }
    enum ReviewCardOrder {
      REVIEW_CARD_ORDER_DAY = 0;
      REVIEW_CARD_ORDER_DAY_THEN_DECK = 1;
      REVIEW_CARD_ORDER_DECK_THEN_DAY = 2;
      REVIEW_CARD_ORDER_INTERVALS_ASCENDING = 3;
      REVIEW_CARD_ORDER_INTERVALS_DESCENDING = 4;
      REVIEW_CARD_ORDER_EASE_ASCENDING = 5;
      REVIEW_CARD_ORDER_EASE_DESCENDING = 6;
      REVIEW_CARD_ORDER_RETRIEVABILITY_ASCENDING = 7;
      REVIEW_CARD_ORDER_RETRIEVABILITY_DESCENDING = 11;
      REVIEW_CARD_ORDER_RANDOM = 8;
      REVIEW_CARD_ORDER_ADDED = 9;
      REVIEW_CARD_ORDER_REVERSE_ADDED = 10;
    }
    enum ReviewMix {
      REVIEW_MIX_MIX_WITH_REVIEWS = 0;
      REVIEW_MIX_AFTER_REVIEWS = 1;
      REVIEW_MIX_BEFORE_REVIEWS = 2;
    }
    enum LeechAction {
      LEECH_ACTION_SUSPEND = 0;
      LEECH_ACTION_TAG_ONLY = 1;
    }
    enum AnswerAction {
      ANSWER_ACTION_BURY_CARD = 0;
      ANSWER_ACTION_ANSWER_AGAIN = 1;
      ANSWER_ACTION_ANSWER_GOOD = 2;
      ANSWER_ACTION_ANSWER_HARD = 3;
      ANSWER_ACTION_SHOW_REMINDER = 4;
    }
    enum QuestionAction {
      QUESTION_ACTION_SHOW_ANSWER = 0;
      QUESTION_ACTION_SHOW_REMINDER = 1;
    }
    repeated float learn_steps = 1;
    repeated float relearn_steps = 2;

    repeated float fsrs_params_4 = 3;
    repeated float fsrs_params_5 = 5;

    // consider saving remaining ones for fsrs param changes
    reserved 6 to 8;

    uint32 new_per_day = 9;
    uint32 reviews_per_day = 10;

    // not currently used
    uint32 new_per_day_minimum = 35;

    float initial_ease = 11;
    float easy_multiplier = 12;
    float hard_multiplier = 13;
    float lapse_multiplier = 14;
    float interval_multiplier = 15;

    uint32 maximum_review_interval = 16;
    uint32 minimum_lapse_interval = 17;

    uint32 graduating_interval_good = 18;
    uint32 graduating_interval_easy = 19;

    NewCardInsertOrder new_card_insert_order = 20;
    NewCardGatherPriority new_card_gather_priority = 34;
    NewCardSortOrder new_card_sort_order = 32;
    ReviewMix new_mix = 30;

    ReviewCardOrder review_order = 33;

    ReviewMix interday_learning_mix = 31;

    LeechAction leech_action = 21;
    uint32 leech_threshold = 22;

    bool disable_autoplay = 23;
    uint32 cap_answer_time_to_secs = 24;
    bool show_timer = 25;
    bool stop_timer_on_answer = 38;
    float seconds_to_show_question = 41;
    float seconds_to_show_answer = 42;
    QuestionAction question_action = 36;
    AnswerAction answer_action = 43;
    bool wait_for_audio = 44;
    bool skip_question_when_replaying_answer = 26;

    bool bury_new = 27;
    bool bury_reviews = 28;
    bool bury_interday_learning = 29;

    // for fsrs
    float desired_retention = 37;
    string ignore_revlogs_before_date = 46;
    repeated float easy_days_percentages = 4;
    // used for fsrs_reschedule in the past
    reserved 39;
    float historical_retention = 40;
    string param_search = 45;

    bytes other = 255;
  }

  int64 id = 1;
  string name = 2;
  int64 mtime_secs = 3;
  int32 usn = 4;
  Config config = 5;
}

message DeckConfigsForUpdate {
  message ConfigWithExtra {
    DeckConfig config = 1;
    uint32 use_count = 2;
  }
  message CurrentDeck {
    message Limits {
      optional uint32 review = 1;
      optional uint32 new = 2;
      optional uint32 review_today = 3;
      optional uint32 new_today = 4;
      // Whether review_today applies to today or a past day.
      bool review_today_active = 5;
      // Whether new_today applies to today or a past day.
      bool new_today_active = 6;
    }
    string name = 1;
    int64 config_id = 2;
    repeated int64 parent_config_ids = 3;
    Limits limits = 4;
  }

  repeated ConfigWithExtra all_config = 1;
  CurrentDeck current_deck = 2;
  DeckConfig defaults = 3;
  bool schema_modified = 4;
  // only applies to v3 scheduler
  string card_state_customizer = 6;
  // only applies to v3 scheduler
  bool new_cards_ignore_review_limit = 7;
  bool fsrs = 8;
  bool apply_all_parent_limits = 9;
  uint32 days_since_last_fsrs_optimize = 10;
}

enum UpdateDeckConfigsMode {
  UPDATE_DECK_CONFIGS_MODE_NORMAL = 0;
  UPDATE_DECK_CONFIGS_MODE_APPLY_TO_CHILDREN = 1;
  UPDATE_DECK_CONFIGS_MODE_COMPUTE_ALL_PARAMS = 2;
}

message UpdateDeckConfigsRequest {
  int64 target_deck_id = 1;
  /// Unchanged, non-selected configs can be omitted. Deck will
  /// be set to whichever entry comes last.
  repeated DeckConfig configs = 2;
  repeated int64 removed_config_ids = 3;
  UpdateDeckConfigsMode mode = 4;
  string card_state_customizer = 5;
  DeckConfigsForUpdate.CurrentDeck.Limits limits = 6;
  bool new_cards_ignore_review_limit = 7;
  bool fsrs = 8;
  bool apply_all_parent_limits = 9;
  bool fsrs_reschedule = 10;
}
