syntax = "proto2";

// Note: this file name must be unique due to how the iOS megazord works :(

package mozilla.appservices.places.protobuf;

option java_package = "mozilla.appservices.places";
option java_outer_classname = "MsgTypes";
option swift_prefix = "MsgTypes_";
option optimize_for = LITE_RUNTIME;

message HistoryVisitInfo {
    required string url = 1;
    optional string title = 2;
    required int64 timestamp = 3;
    required int32 visit_type = 4;
    required bool is_hidden = 5;
    optional string preview_image_url = 6;
}

message HistoryVisitInfos {
    repeated HistoryVisitInfo infos = 1;
}

message HistoryVisitInfosWithBound {
    repeated HistoryVisitInfo infos = 1;
    required int64 bound = 2;
    required int64 offset = 3;
}

/**
 * A bookmark node.
 *
 * We use a single message type for bookmarks. It covers insertion, deletion,
 * and update, and represents all three bookmark types.
 *
 * This simplifies the FFI by reducing the number of types that must go across
 * it, and retuces boilderplate, but removes some static-ish guarantees we
 * might have otherwise.
 *
 * Note that these docs comments are internal, and don't necessarily impact the actual
 * API we expose to Kotlin/Swift (this is particularly true around reads).
 */
message BookmarkNode {
    /**
     * The type of this bookmark, a `BookmarkType` (from `types.rs`).
     *
     * This impacts which fields may be present.
     *
     * It's illegal to attempt to change this when updating a bookmark.
     *
     * Note: this probably should be an `enum`, but prost seems to get upset
     * about it so we're just using int32 for now.
     *
     * Note: this is `node_type` and not `type` because `type` is reserved
     * in Rust.
     *
     * - Always returned on reads.
     * - Required for inserts.
     * - Not provided for updates.
     */
    optional int32 node_type = 1;

    /**
     * The bookmarks guid.
     *
     * - Always returned on reads.
     * - Not allowed for inserts.
     * - Required for updates (specifies which record is being changed)
     */
    optional string guid = 2;

    /**
     * Creation time, in milliseconds since the unix epoch.
     *
     * May not be a local timestamp, and may shift if new devices are able to
     * provide an earlier (but still valid) timestamp.
     *
     * - Always returned on reads.
     * - Ignored for insertion and update.
     */
    optional int64 date_added = 3;

    /**
     * Last modification time, in milliseconds since the unix epoch.
     *
     * - Always returned on reads.
     * - Ignored for insertion and update.
     */
    optional int64 last_modified = 4;

    /**
     * Guid of the parent record.
     *
     * - Returned on reads, except for reads of the bookmark root.
     * - Required for insertion.
     * - On updates, if provided, we treat it as a move.
     *     - Interacts with `position`, see its documentation below
     *       for details on how.
     */
    optional string parent_guid = 5;

    /**
     * Zero based index within the parent.
     *
     * - Not provided on reads (for now).
     *
     * - Allowed for insertion.
     *    - Leaving it out means 'end of folder'.
     *
     * - Allowed for updates.
     *     - If `parent_guid` is not provided and `position` is, we treat this
     *       a move within the same folder.
     *
     *     - If `parent_guid` and `position` are both provided, we treat this as
     *       a move to / within that folder, and we insert at the requested
     *       position.
     *
     *     - If `position` is not provided (and `parent_guid` is) then it's
     *       treated as a move to the end of that folder.
     */
    optional uint32 position = 6;

    /**
     * Bookmark title. Not present for type = `BookmarkType::Separator`.
     *
     * - Returned on reads if it exists.
     * - Required when inserting folders.
     */
    optional string title = 7;

    /**
     * Bookmark URL. Only allowed/present for type = `BookmarkType::Bookmark`.
     *
     * - Always returned on reads (for `BookmarkType::Bookmark`).
     * - Required when inserting a new bookmark.
     */
    optional string url = 8;

    /**
     * IDs of folder children, in order. Only present for type =
     * `BookmarkType::Folder`.
     *
     * - Returned on reads (for `BookmarkType::Folder`).
     * - Forbidden for insertions and updates.
     * - Not provided if `child_nodes` is provided, to avoid sending more data
     *   over the FFI than necessary.
     */
    repeated string child_guids = 9;

    /**
     * Data about folder children, in order. Only present for type =
     * `BookmarkType::Folder`.
     *
     * For performance reasons, this only is provided if it's requested.
     */
    repeated BookmarkNode child_nodes = 10;

    /**
     * Returned by reads, and used to distinguish between the cases of
     * "empty child_nodes because the API doesn't return children" and
     * "empty child_nodes because this folder has no children (but
     * we'd populate them if it had them)".
     *
     * Only required because you can't have `optional repeated`.
     *
     * Leaving this out is equivalent to false.
     */
    optional bool have_child_nodes = 11;
}

/** An array of bookmark nodes, since we can't represent that directly */
message BookmarkNodeList {
    repeated BookmarkNode nodes = 1;
}

// Protobuf allows nesting these, but prost behaves weirdly if we do.
enum SearchResultReason {
    // Never used in practice. Maybe remove this from here and from the rust enum?
    KEYWORD = 1;
    ORIGIN = 2;
    URL = 3;
    PREVIOUS_USE = 4;
    BOOKMARK = 5;
    // If we get real tag support, just add `optional string tags` to SearchResult below, but
    // for now expose that it was because of tags.
    TAG = 6;
}

message SearchResultMessage {
    required string url = 1;
    required string title = 2;
    required int64 frecency = 3;
    repeated SearchResultReason reasons = 4 [packed = true];
}

message SearchResultList {
    repeated SearchResultMessage results = 1;
}

message TopFrecentSiteInfo {
    required string url = 1;
    optional string title = 2;
}

message TopFrecentSiteInfos {
    repeated TopFrecentSiteInfo infos = 1;
}
