syntax = "proto3";

package referral.v1;

// ReferralService owns referral attribution, referral commissions, bonus balances,
// weekly payout holds, and payout lifecycle for ArbiExchange/ArbiWallet.
service ReferralService {
  rpc EnsureReferralProfile(EnsureReferralProfileRequest) returns (ReferralProfileResponse);
  rpc GetReferralLink(GetReferralLinkRequest) returns (GetReferralLinkResponse);
  rpc BindReferralByCode(BindReferralByCodeRequest) returns (BindReferralByCodeResponse);
  rpc GetReferralSummary(GetReferralSummaryRequest) returns (GetReferralSummaryResponse);
  // CRM admin: получить реферальный профиль для формы редактирования пользователя.
  rpc AdminGetReferralProfileByUserId(AdminGetReferralProfileByUserIdRequest) returns (AdminReferralProfileByUserIdResponse);
  // CRM admin: найти реферальный профиль по персональному ref code.
  rpc AdminFindReferralProfileByRefCode(AdminFindReferralProfileByRefCodeRequest) returns (AdminFindReferralProfileByRefCodeResponse);
  // CRM admin: обновить реферальный профиль (реферер, тип начисления, процент, ref code).
  rpc AdminUpdateReferralProfileByUserId(AdminUpdateReferralProfileByUserIdRequest) returns (AdminReferralProfileByUserIdResponse);
  rpc GetUserReferralMetrics(GetUserReferralMetricsRequest) returns (GetUserReferralMetricsResponse);
  rpc ListReferrals(ListReferralsRequest) returns (ListReferralsResponse);
  rpc GetReferredUserIds(GetReferredUserIdsRequest) returns (GetReferredUserIdsResponse);
  rpc BatchGetDirectReferrersByUserIds(BatchGetDirectReferrersByUserIdsRequest) returns (BatchGetDirectReferrersByUserIdsResponse);
  rpc BatchGetExchangeReferralSummaries(BatchGetExchangeReferralSummariesRequest) returns (BatchGetExchangeReferralSummariesResponse);
  rpc BatchGetCommissionsByExchangeIds(BatchGetCommissionsByExchangeIdsRequest) returns (BatchGetCommissionsByExchangeIdsResponse);
  rpc ApplyExchangeCompleted(ApplyExchangeCompletedRequest) returns (ApplyExchangeCompletedResponse);
  rpc ApplyExchangeCancelled(ApplyExchangeCancelledRequest) returns (ApplyExchangeCancelledResponse);
  rpc ListCommissions(ListCommissionsRequest) returns (ListCommissionsResponse);
  rpc CreatePersonalBonus(CreatePersonalBonusRequest) returns (PersonalBonusItem);
  rpc ListPersonalBonuses(ListPersonalBonusesRequest) returns (ListPersonalBonusesResponse);
  rpc GetFinModelBonusAggregates(GetFinModelBonusAggregatesRequest) returns (GetFinModelBonusAggregatesResponse);
  rpc CreatePayout(CreatePayoutRequest) returns (ReferralPayoutResponse);
  rpc ConfirmPayout(ConfirmPayoutRequest) returns (ReferralPayoutResponse);
  rpc UpdatePayout(UpdatePayoutRequest) returns (ReferralPayoutResponse);
  rpc CancelPayout(CancelPayoutRequest) returns (ReferralPayoutResponse);
  rpc DeletePayout(DeletePayoutRequest) returns (DeletePayoutResponse);
  rpc RecreateBonuses(RecreateBonusesRequest) returns (RecreateBonusesResponse);
  rpc CheckReferralIncomeInfo(CheckReferralIncomeInfoRequest) returns (ReferralIncomeInfoResponse);
  rpc RecreateReferralIncome(RecreateReferralIncomeRequest) returns (RecreateReferralIncomeResponse);
  rpc RecreateReferralIncomeWithPayoutProtection(RecreateReferralIncomeRequest) returns (RecreateReferralIncomeResponse);
  rpc GetRecreateReferralIncomeHistoryList(GetRecreateReferralIncomeHistoryListRequest) returns (GetRecreateReferralIncomeHistoryListResponse);
  rpc GetRecreateReferralIncomeHistoryDetails(GetRecreateReferralIncomeHistoryDetailsRequest) returns (ReferralIncomeRecreateHistoryDetails);
  rpc ListPayouts(ListPayoutsRequest) returns (ListPayoutsResponse);
  rpc AdminRecalculateExchange(AdminRecalculateExchangeRequest) returns (AdminRecalculateExchangeResponse);
}

enum ReferralProfileStatus {
  REFERRAL_PROFILE_STATUS_ACTIVE = 0;
  REFERRAL_PROFILE_STATUS_BLOCKED = 1;
}

enum ReferralBonusType {
  REFERRAL_BONUS_TYPE_PROFIT = 0;
  REFERRAL_BONUS_TYPE_VOLUME = 1;
}

enum ReferralCommissionStatus {
  REFERRAL_COMMISSION_STATUS_CONFIRMED = 0;
  REFERRAL_COMMISSION_STATUS_CANCELLED = 1;
}

enum ReferralPayoutStatus {
  REFERRAL_PAYOUT_STATUS_CREATED = 0;
  REFERRAL_PAYOUT_STATUS_CONFIRMED = 1;
  REFERRAL_PAYOUT_STATUS_CANCELLED = 2;
}

message EnsureReferralProfileRequest {
  string wallet_user_id = 1;
  optional int64 legacy_customer_id = 2;
  optional string telegram_id = 3;
  optional string ref_code = 4;
  optional string referrer_code = 5;
  optional string source = 6;
  optional string utm_json = 7;
}

message ReferralProfileResponse {
  int64 id = 1;
  string wallet_user_id = 2;
  optional int64 legacy_customer_id = 3;
  optional string telegram_id = 4;
  string ref_code = 5;
  optional int64 referrer_profile_id = 6;
  ReferralBonusType bonus_type = 7;
  string ref_percent = 8;
  ReferralProfileStatus status = 9;
  string created_at = 10;
  string updated_at = 11;
  bool is_multilevel = 12;
}

message GetReferralLinkRequest {
  string wallet_user_id = 1;
  optional string base_url = 2;
}

message GetReferralLinkResponse {
  string ref_code = 1;
  string link = 2;
}

message BindReferralByCodeRequest {
  string wallet_user_id = 1;
  string ref_code = 2;
  optional string source = 3;
  optional string utm_json = 4;
}

message BindReferralByCodeResponse {
  bool success = 1;
  ReferralProfileResponse profile = 2;
  optional ReferralProfileResponse referrer = 3;
}

message GetReferralSummaryRequest {
  string wallet_user_id = 1;
}

message ReferralBalanceItem {
  string currency = 1;
  string total = 2;
  string available = 3;
  string held_current_week = 4;
}

message GetReferralSummaryResponse {
  ReferralProfileResponse profile = 1;
  repeated ReferralBalanceItem balances = 2;
  int32 referrals_count = 3;
  string total_usd_volume = 4;
  string total_usdt_balance = 5;
  string available_usdt_balance = 6;
}

message AdminGetReferralProfileByUserIdRequest {
  int32 user_id = 1;
}

message AdminFindReferralProfileByRefCodeRequest {
  string ref_code = 1;
}

message AdminFindReferralProfileByRefCodeResponse {
  string profile_id = 1;
  int32 user_id = 2;
  string ref_code = 3;
  ReferralProfileStatus status = 4;
  string created_at = 5;
  string updated_at = 6;
}

message AdminReferralProfileByUserIdResponse {
  string profile_id = 1;
  int32 user_id = 2;
  string ref_code = 3;
  optional int32 referrer_user_id = 4;
  // Строковый тип для admin-flow, чтобы избежать тихого enum-default в gRPC loader.
  // Нормализуется сервисом в ReferralBonusType (PROFIT/VOLUME).
  string bonus_type = 5;
  string ref_percent = 6;
  ReferralProfileStatus status = 7;
  string created_at = 8;
  string updated_at = 9;
  // true, если в рамках AdminUpdateReferralProfileByUserId был установлен referrer_user_id.
  bool referrer_changed = 10;
}

message AdminUpdateReferralProfileByUserIdRequest {
  int32 user_id = 1;
  // Разрешено только если у профиля еще нет реферера.
  // Если текущий реферер уже задан, сервис возвращает ошибку REFERRER_ALREADY_SET.
  optional int32 referrer_user_id = 2;
  // Строковый тип для admin-flow, чтобы избежать тихого enum-default в gRPC loader.
  // Допустимые значения: PROFIT | VOLUME | REFERRAL_BONUS_TYPE_PROFIT | REFERRAL_BONUS_TYPE_VOLUME.
  optional string bonus_type = 3;
  optional string ref_percent = 4;
  optional string ref_code = 5;
  optional string changed_by = 6;
  // true — в этом запросе нужно выполнить изменение referrer_user_id;
  // false/отсутствует — referrer_user_id игнорируется.
  optional bool referrer_changed = 7;
}

message GetUserReferralMetricsRequest {
  string wallet_user_id = 1;
  optional string date_from = 2;
  optional string date_to = 3;
}

message GetUserReferralMetricsResponse {
  int32 referrals_count = 1;
  int32 referrals_today = 2;
}

message ListReferralsRequest {
  string wallet_user_id = 1;
  optional int32 page = 2;
  optional int32 limit = 3;
}

message ReferralListItem {
  int64 profile_id = 1;
  string wallet_user_id = 2;
  optional int64 legacy_customer_id = 3;
  optional string telegram_id = 4;
  string ref_code = 5;
  string created_at = 6;
}

message ListReferralsResponse {
  repeated ReferralListItem items = 1;
  int32 total = 2;
  int32 page = 3;
  int32 limit = 4;
}

message GetReferredUserIdsRequest {
  int32 user_id = 1;
}

message GetReferredUserIdsResponse {
  repeated int32 referred_user_ids = 1;
}

message BatchGetDirectReferrersByUserIdsRequest {
  repeated int32 user_ids = 1;
}

message BatchGetDirectReferrersByUserIdsResponse {
  repeated int32 direct_referrer_ids = 1;
}

message BatchGetExchangeReferralSummariesRequest {
  repeated string exchange_ids = 1;
}

message ExchangeReferralSummary {
  string exchange_id = 1;
  string amount = 2;
  string percent = 3;
}

message BatchGetExchangeReferralSummariesResponse {
  repeated ExchangeReferralSummary summaries = 1;
}

message BatchGetCommissionsByExchangeIdsRequest {
  string wallet_user_id = 1;
  repeated string exchange_ids = 2;
}

message BatchGetCommissionsByExchangeIdsResponse {
  repeated ReferralCommissionItem items = 1;
}

message ApplyExchangeCompletedRequest {
  string exchange_id = 1;
  string wallet_user_id = 2;
  optional int64 legacy_customer_id = 3;
  string output_amount = 4;
  optional string fact_output_amount = 5;
  string output_currency = 6;
  string profit_amount = 7;
  string profit_currency = 8;
  optional string courier_expenses = 9;
  optional string usdt_rate = 10;
  optional string completed_at = 11;
  optional string calculation_snapshot_json = 12;
}

message ApplyExchangeCompletedResponse {
  bool created = 1;
  optional ReferralCommissionItem commission = 2;
  repeated ReferralBalanceItem balances = 3;
}

message ApplyExchangeCancelledRequest {
  string exchange_id = 1;
  optional string reason = 2;
}

message ApplyExchangeCancelledResponse {
  int32 cancelled_count = 1;
  repeated ReferralBalanceItem balances = 2;
}

message ListCommissionsRequest {
  string wallet_user_id = 1;
  optional int32 page = 2;
  optional int32 limit = 3;
}

message ReferralCommissionItem {
  int64 id = 1;
  string exchange_id = 2;
  int64 referrer_profile_id = 3;
  int64 referred_profile_id = 4;
  int32 level = 5;
  ReferralBonusType bonus_type = 6;
  string percent = 7;
  string base_amount = 8;
  string amount = 9;
  string currency = 10;
  ReferralCommissionStatus status = 11;
  string created_at = 12;
  optional string cancelled_at = 13;
}

message ListCommissionsResponse {
  repeated ReferralCommissionItem items = 1;
  int32 total = 2;
  int32 page = 3;
  int32 limit = 4;
}

message CreatePersonalBonusRequest {
  string wallet_user_id = 1;
  string amount = 2;
  string currency = 3;
  optional string reason = 4;
  optional string comment = 5;
  optional string created_by = 6;
}

message PersonalBonusItem {
  int64 id = 1;
  int64 profile_id = 2;
  string amount = 3;
  string currency = 4;
  optional string reason = 5;
  optional string comment = 6;
  optional string created_by = 7;
  string created_at = 8;
  string updated_at = 9;
}

message ListPersonalBonusesRequest {
  string wallet_user_id = 1;
  optional int32 page = 2;
  optional int32 limit = 3;
}

message ListPersonalBonusesResponse {
  repeated PersonalBonusItem items = 1;
  int32 total = 2;
  int32 page = 3;
  int32 limit = 4;
}

message GetFinModelBonusAggregatesRequest {
  string date_from = 1;
  string date_to = 2;
}

message FinModelBonusAggregateItem {
  string currency = 1;
  string amount = 2;
}

message GetFinModelBonusAggregatesResponse {
  repeated FinModelBonusAggregateItem personal_bonuses = 1;
  repeated FinModelBonusAggregateItem referral_bonuses = 2;
}

message CreatePayoutRequest {
  string wallet_user_id = 1;
  string amount = 2;
  string currency = 3;
  string payment_method = 4;
  optional string output_currency = 5;
  optional string comment = 6;
  optional string created_by_manager_id = 7;
}

message ConfirmPayoutRequest {
  int64 payout_id = 1;
  optional string confirmed_by_manager_id = 2;
}

message UpdatePayoutRequest {
  int64 payout_id = 1;
  optional string amount = 2;
  optional string currency = 3;
  optional string payment_method = 4;
  optional string output_currency = 5;
  optional string comment = 6;
  optional string wallet_user_id = 7;
}

message CancelPayoutRequest {
  int64 payout_id = 1;
  optional string reason = 2;
}

message DeletePayoutRequest {
  int64 payout_id = 1;
}

message DeletePayoutResponse {
  bool deleted = 1;
}

message ReferralPayoutResponse {
  int64 id = 1;
  int64 profile_id = 2;
  string amount = 3;
  string currency = 4;
  string payment_method = 5;
  optional string output_currency = 6;
  ReferralPayoutStatus status = 7;
  optional string comment = 8;
  string created_at = 9;
  string updated_at = 10;
  optional string wallet_user_id = 11;
}

message ListPayoutsRequest {
  string wallet_user_id = 1;
  optional int32 page = 2;
  optional int32 limit = 3;
}

message ListPayoutsResponse {
  repeated ReferralPayoutResponse items = 1;
  int32 total = 2;
  int32 page = 3;
  int32 limit = 4;
}

message RecreateBonusesRequest {
  string wallet_user_id = 1;
}

message RecreateBonusesBalanceItem {
  string currency = 1;
  string amount = 2;
}

message RecreateBonusesResponse {
  bool success = 1;
  int32 commissions_count = 2;
  int32 payouts_count = 3;
  repeated RecreateBonusesBalanceItem balances = 4;
}

message CheckReferralIncomeInfoRequest {
  string wallet_user_id = 1;
  optional bool protect_payout_covered_income = 2;
}

message RecreateReferralIncomeRequest {
  string wallet_user_id = 1;
  optional string requested_by = 2;
}

message ReferralIncomeCurrencyAmount {
  string currency = 1;
  string amount = 2;
  int32 count = 3;
}

message ReferralIncomeExchangeItem {
  string exchange_id = 1;
  optional int64 referral_commission_id = 2;
  optional int64 referral_volume_ledger_id = 3;
  string referral_user_id = 4;
  string created_at = 5;
  string input_currency = 6;
  string input_amount = 7;
  string output_currency = 8;
  string output_amount = 9;
  string profit_amount = 32;
  string profit_currency = 33;
  bool is_in_current_referral_chain = 10;
  bool is_in_referrer_bonus_exchanges_list = 11;
  string referral_user_text = 12;
  string referral_amount = 13;
  string referral_amount_currency = 14;
  bool is_protected_by_payouts = 15;
  int32 referral_level = 16;
  optional int64 referral_profile_id = 17;
  bool is_exchange_completed = 18;
  string referral_volume_amount_usd = 19;
  bool will_be_deleted = 20;
  bool will_be_recreated = 21;
  string new_calculated_referral_amount = 22;
  string new_calculated_referral_amount_currency = 23;
  string new_calculated_referral_volume_amount_usd = 24;
  string new_calculated_referral_bonus_type = 25;
  string new_calculated_referral_percent = 26;
  string new_calculated_referral_base_amount = 27;
  string new_calculated_referral_profit_amount = 28;
  string new_calculated_referral_courier_expenses = 29;
  string new_calculated_referral_usdt_rate = 30;
  string new_calculated_referral_output_amount = 31;
}

message ReferralIncomeInfoResponse {
  string referrer_user_id = 1;
  ReferralProfileResponse referrer_referral_profile = 2;
  repeated ReferralBalanceItem referrer_referral_balance = 3;
  repeated string referrer_referral_user_ids = 4;
  repeated ReferralPayoutResponse referral_payouts = 5;
  repeated ReferralIncomeCurrencyAmount grouped_payouts = 6;
  repeated ReferralIncomeExchangeItem exchanges_referral_incomings_list = 7;
  repeated ReferralIncomeCurrencyAmount grouped_exchange_referral_incomings = 8;
  repeated ReferralIncomeCurrencyAmount grouped_referral_incomings_current = 9;
  repeated ReferralIncomeCurrencyAmount grouped_referral_incomings_to_delete = 10;
  repeated ReferralIncomeCurrencyAmount grouped_referral_incomings_to_create = 11;
  repeated ReferralIncomeCurrencyAmount grouped_referral_incomings_projected = 12;
  repeated ReferralIncomeCurrencyAmount grouped_referral_incomings_difference = 13;
  repeated ReferralIncomeCurrencyAmount grouped_referral_volume_current = 14;
  repeated ReferralIncomeCurrencyAmount grouped_referral_volume_to_delete = 15;
  repeated ReferralIncomeCurrencyAmount grouped_referral_volume_to_create = 16;
  repeated ReferralIncomeCurrencyAmount grouped_referral_volume_projected = 17;
  repeated ReferralIncomeCurrencyAmount grouped_referral_volume_difference = 18;
}

message RecreateReferralIncomeResponse {
  bool success = 1;
  int64 history_id = 2;
  ReferralIncomeInfoResponse referral_incomings_before = 3;
  ReferralIncomeInfoResponse referral_incomings_after = 4;
}

message GetRecreateReferralIncomeHistoryListRequest {
  optional string wallet_user_id = 1;
  optional int32 page = 2;
  optional int32 limit = 3;
}

message ReferralIncomeRecreateHistoryListItem {
  int64 id = 1;
  string wallet_user_id = 2;
  bool safe = 3;
  string created_at = 4;
  optional string requested_by = 5;
}

message GetRecreateReferralIncomeHistoryListResponse {
  repeated ReferralIncomeRecreateHistoryListItem items = 1;
  int32 total = 2;
  int32 page = 3;
  int32 limit = 4;
}

message GetRecreateReferralIncomeHistoryDetailsRequest {
  int64 id = 1;
}

message ReferralIncomeRecreateHistoryDetails {
  int64 id = 1;
  string wallet_user_id = 2;
  bool safe = 3;
  string created_at = 4;
  optional string requested_by = 5;
  string referral_incomings_before_json = 6;
  string referral_incomings_after_json = 7;
}

message AdminRecalculateExchangeRequest {
  string exchange_id = 1;
  bool dry_run = 2;
}

message AdminRecalculateExchangeResponse {
  bool changed = 1;
  optional ReferralCommissionItem commission = 2;
}
