// DragonX Wallet - ImGui Edition
// Copyright 2024-2026 The Hush Developers
// Released under the GPLv3
//
// Lite-wallet rollout / kill-switch policy.
//
// A pure decision core that gates whether the lite wallet may run, given a local override, an
// emergency env kill-switch, an optional rollout manifest, the running app version, and a stable
// per-install rollout bucket. Privacy posture (this is a privacy coin): the manifest is read from a
// LOCAL cache file only — there is NO runtime network fetch (a signed remote fetcher can populate
// that cache later without touching this policy), it is consulted FAIL-OPEN (absent/invalid →
// allowed, so a missing file never bricks a working install), and the install bucket is derived
// from a locally-generated random id that is never transmitted and carries no PII.

#pragma once

#include <string>
#include <vector>

namespace dragonx::wallet {

// User/support local override (persisted in settings as "lite_rollout").
enum class LiteRolloutOverride {
    Auto,      // honor the manifest / staged rollout
    ForceOn,   // always enable; bypasses the manifest + staged rollout, but NOT the env kill-switch
    ForceOff   // always disable
};

enum class LiteRolloutStatus {
    Allowed,
    DisabledByKillSwitchEnv,     // DRAGONX_LITE_KILL_SWITCH=1 (emergency, absolute)
    DisabledByLocalOverride,     // lite_rollout=force_off
    DisabledByManifest,          // manifest global_enabled=false
    DisabledUnsupportedVersion,  // version below min / above max supported
    DisabledBlockedVersion,      // version explicitly blocked
    DisabledByStagedRollout      // install bucket above the rollout threshold
};

// Rollout manifest. Loaded from a local cache file; present=false means no manifest (fail-open).
struct LiteRolloutManifest {
    bool present = false;        // a manifest file was found
    bool valid = false;          // it parsed and validated
    bool globalEnabled = true;   // master enable switch
    std::string minVersion;      // inclusive floor (empty = none)
    std::string maxVersion;      // inclusive ceiling (empty = none)
    std::vector<std::string> blockedVersions;
    int rolloutPermille = 1000;  // 0..1000; install allowed when bucket < permille (1000 = 100%)
    std::string message;         // user-facing reason shown when disabled
};

struct LiteRolloutInputs {
    LiteRolloutOverride override = LiteRolloutOverride::Auto;
    bool killSwitchEnv = false;
    LiteRolloutManifest manifest;
    std::string appVersion;
    int installBucket = 0;       // 0..999, stable per install
};

struct LiteRolloutDecision {
    bool allowed = true;
    LiteRolloutStatus status = LiteRolloutStatus::Allowed;
    std::string message;         // user-facing (empty when allowed)
};

// The pure decision. No I/O. Evaluation order: env kill-switch (absolute) → local override →
// manifest gates (global / version / blocked / staged rollout) → fail-open allow.
LiteRolloutDecision evaluateLiteRollout(const LiteRolloutInputs& inputs);

// Stable bucket 0..999 from an install id (FNV-1a). Deterministic; empty id -> 0.
int liteRolloutBucketFromInstallId(const std::string& installId);

// Compare dotted version cores, ignoring any "-suffix"/"+build". Returns -1 / 0 / 1.
int compareLiteVersions(const std::string& a, const std::string& b);

// Override <-> string ("auto"/"force_on"/"force_off"); unknown parses to Auto.
LiteRolloutOverride liteRolloutOverrideFromString(const std::string& value);
const char* liteRolloutOverrideToString(LiteRolloutOverride override);

const char* liteRolloutStatusName(LiteRolloutStatus status);

// Load + validate a manifest from a JSON file. Missing file -> {present=false}; parse error ->
// {present=true, valid=false}. Both are fail-open at evaluation time.
LiteRolloutManifest loadLiteRolloutManifestFromFile(const std::string& path);

} // namespace dragonx::wallet
