// Copyright © 2019 The Things Network Foundation, The Things Industries B.V.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

syntax = "proto3";

import "github.com/envoyproxy/protoc-gen-validate/validate/validate.proto";
import "github.com/gogo/protobuf/gogoproto/gogo.proto";
import "github.com/TheThingsIndustries/protoc-gen-go-flags/annotations.proto";
import "github.com/TheThingsIndustries/protoc-gen-go-json/annotations.proto";
import "protoc-gen-openapiv2/options/annotations.proto";

package ttn.lorawan.v3;

option go_package = "go.thethings.network/lorawan-stack/v3/pkg/ttnpb";

// TODO: Migrate away from GoGo Protobuf (https://github.com/TheThingsNetwork/lorawan-stack/issues/2798).
option (gogoproto.goproto_registration) = true;

message ApplicationIdentifiers {
  option (thethings.flags.message) = { select: true, set: true };
  string application_id = 1 [(validate.rules).string = {pattern: "^[a-z0-9](?:[-]?[a-z0-9]){2,}$" , max_len: 36}];
}

message ClientIdentifiers {
  option (thethings.flags.message) = { select: true, set: true };
  string client_id = 1 [(validate.rules).string = {pattern: "^[a-z0-9](?:[-]?[a-z0-9]){2,}$" , max_len: 36}];
}

message EndDeviceIdentifiers {
  option (thethings.flags.message) = { select: true, set: true };
  string device_id = 1 [(validate.rules).string = {pattern: "^[a-z0-9](?:[-]?[a-z0-9]){2,}$" , max_len: 36}];
  ApplicationIdentifiers application_ids = 2 [(validate.rules).message.required = true];
  // The LoRaWAN DevEUI.
  bytes dev_eui = 4 [
    (validate.rules).bytes = { len: 8, ignore_empty: true },
    (thethings.json.field) = {
      marshaler_func: "go.thethings.network/lorawan-stack/v3/pkg/types.MarshalHEXBytes",
      unmarshaler_func: "go.thethings.network/lorawan-stack/v3/pkg/types.Unmarshal8Bytes"
    },
    (thethings.flags.field) = {
      set_flag_new_func: "go.thethings.network/lorawan-stack/v3/cmd/ttn-lw-cli/customflags.New8BytesFlag",
      set_flag_getter_func: "go.thethings.network/lorawan-stack/v3/cmd/ttn-lw-cli/customflags.GetExactBytes"
    },
    (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
      type: STRING, format: "string", example: "\"70B3D57ED000ABCD\""
    }
  ];
  // The LoRaWAN JoinEUI (AppEUI until LoRaWAN 1.0.3 end devices).
  bytes join_eui = 5 [
    (validate.rules).bytes = { len: 8, ignore_empty: true },
    (thethings.json.field) = {
      marshaler_func: "go.thethings.network/lorawan-stack/v3/pkg/types.MarshalHEXBytes",
      unmarshaler_func: "go.thethings.network/lorawan-stack/v3/pkg/types.Unmarshal8Bytes"
    },
    (thethings.flags.field) = {
      set_flag_new_func: "go.thethings.network/lorawan-stack/v3/cmd/ttn-lw-cli/customflags.New8BytesFlag",
      set_flag_getter_func: "go.thethings.network/lorawan-stack/v3/cmd/ttn-lw-cli/customflags.GetExactBytes"
    },
    (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
      type: STRING, format: "string", example: "\"70B3D57ED000ABCD\""
    }
  ];
  // The LoRaWAN DevAddr.
  bytes dev_addr = 6 [
    (validate.rules).bytes = { len: 4, ignore_empty: true },
    (thethings.json.field) = {
      marshaler_func: "go.thethings.network/lorawan-stack/v3/pkg/types.MarshalHEXBytes",
      unmarshaler_func: "go.thethings.network/lorawan-stack/v3/pkg/types.Unmarshal4Bytes"
    },
    (thethings.flags.field) = {
      set_flag_new_func: "go.thethings.network/lorawan-stack/v3/cmd/ttn-lw-cli/customflags.New4BytesFlag",
      set_flag_getter_func: "go.thethings.network/lorawan-stack/v3/cmd/ttn-lw-cli/customflags.GetExactBytes"
    },
    (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
      type: STRING, format: "string", example: "\"2600ABCD\""
    }
  ];
}

message GatewayIdentifiers {
  option (thethings.flags.message) = { select: true, set: true };
  string gateway_id = 1 [(validate.rules).string = {pattern: "^[a-z0-9](?:[-]?[a-z0-9]){2,}$" , max_len: 36}];

  // Secondary identifier, which can only be used in specific requests.
  bytes eui = 2 [
    (validate.rules).bytes = { len: 8, ignore_empty: true },
    (thethings.json.field) = {
      marshaler_func: "go.thethings.network/lorawan-stack/v3/pkg/types.MarshalHEXBytes",
      unmarshaler_func: "go.thethings.network/lorawan-stack/v3/pkg/types.Unmarshal8Bytes"
    },
    (thethings.flags.field) = {
      set_flag_new_func: "go.thethings.network/lorawan-stack/v3/cmd/ttn-lw-cli/customflags.New8BytesFlag",
      set_flag_getter_func: "go.thethings.network/lorawan-stack/v3/cmd/ttn-lw-cli/customflags.GetExactBytes"
    },
    (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
      type: STRING, format: "string", example: "\"70B3D57ED000ABCD\""
    }
  ];
}

message OrganizationIdentifiers {
  option (thethings.flags.message) = { select: true, set: true };
  // This ID shares namespace with user IDs.
  string organization_id = 1 [(validate.rules).string = {pattern: "^[a-z0-9](?:[-]?[a-z0-9]){2,}$" , max_len: 36}];
}

message UserIdentifiers {
  option (thethings.flags.message) = { select: true, set: true };
  // This ID shares namespace with organization IDs.
  string user_id = 1 [
    (validate.rules).string = {
      pattern: "^[a-z0-9](?:[-]?[a-z0-9]){1,}$", // NOTE: User IDs allow a shorter minimum length than other IDs.
      max_len: 36
    }
  ];

  // Secondary identifier, which can only be used in specific requests.
  string email = 2 [(thethings.flags.field).hidden = true];
}

// OrganizationOrUserIdentifiers contains either organization or user identifiers.
message OrganizationOrUserIdentifiers {
  option (thethings.flags.message) = { select: true, set: true };
  oneof ids {
    option (validate.required) = true;
    OrganizationIdentifiers organization_ids = 1;
    UserIdentifiers user_ids = 2;
  }
}

// EntityIdentifiers contains one of the possible entity identifiers.
message EntityIdentifiers {
  oneof ids {
    option (validate.required) = true;
    ApplicationIdentifiers application_ids = 1;
    ClientIdentifiers client_ids = 2;
    EndDeviceIdentifiers device_ids = 3;
    GatewayIdentifiers gateway_ids = 4;
    OrganizationIdentifiers organization_ids = 5;
    UserIdentifiers user_ids = 6;
  }
}

// Identifies an end device model with version information.
message EndDeviceVersionIdentifiers {
  option (thethings.flags.message) = { select: true, set: true };
  string brand_id = 1 [(validate.rules).string = {pattern: "^[a-z0-9](?:[-]?[a-z0-9]){2,}$", max_len: 36, ignore_empty: true}];
  string model_id = 2 [(validate.rules).string = {pattern: "^[a-z0-9](?:[-]?[a-z0-9]){2,}$", max_len: 36, ignore_empty: true}];
  string hardware_version = 3 [(validate.rules).string.max_len = 32];
  string firmware_version = 4 [(validate.rules).string.max_len = 32];
  string band_id = 5 [(validate.rules).string.max_len = 32];
  // VendorID managed by the LoRa Alliance, as defined in TR005.
  uint32 vendor_id = 6;
  // ID of the LoRaWAN end device profile assigned by the vendor.
  uint32 vendor_profile_id = 7;
  string serial_number = 8 [(validate.rules).string = {pattern: "^[a-z0-9](?:[-]?[a-z0-9]){2,}$", max_len: 36, ignore_empty: true}];
}

// Identifies a Network Server.
message NetworkIdentifiers {
  option (thethings.flags.message) = { select: true, set: false };
  // LoRa Alliance NetID.
  bytes net_id = 1 [
    (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
      type: STRING, format: "string", example: "\"000013\""
    },
    (validate.rules).bytes = { len: 3, ignore_empty: true },
    (thethings.json.field) = {
      marshaler_func: "go.thethings.network/lorawan-stack/v3/pkg/types.MarshalHEXBytes",
      unmarshaler_func: "go.thethings.network/lorawan-stack/v3/pkg/types.Unmarshal3Bytes"
    },
    (thethings.flags.field) = {
      set_flag_new_func: "go.thethings.network/lorawan-stack/v3/cmd/ttn-lw-cli/customflags.New3BytesFlag",
      set_flag_getter_func: "go.thethings.network/lorawan-stack/v3/cmd/ttn-lw-cli/customflags.GetExactBytes"
    }
  ];
  // Optional tenant identifier for multi-tenant deployments.
  string tenant_id = 2 [(validate.rules).string = {pattern: "^[a-z0-9](?:[-]?[a-z0-9]){2,}$|^$", max_len: 36}];
  // Cluster identifier of the Network Server.
  string cluster_id = 3 [(validate.rules).string.max_len = 64];
  // Cluster address of the Network Server.
  string cluster_address = 4 [(validate.rules).string.max_len = 256];
  // Optional tenant address for multi-tenant deployments.
  string tenant_address = 5 [(validate.rules).string.max_len = 256];
}
