//! # fialucci-oracle
//!
//! Opinionated SDK for building external oracles on the [Fialucci](https://github.com/fialucci)
//! chain. The SDK owns the network protocol; developers write only **business
//! logic** by implementing the [`OracleHandler`] trait.
//!
//! ## The design constraint
//!
//! Three things must be byte-identical between every oracle in the wild and
//! the chain node validating its submissions:
//!
//! 1. The proof body canonical JSON encoding.
//! 2. The signing-bytes derivation (domain separator + body JSON).
//! 3. The ed25519 signature over those bytes.
//!
//! Any drift breaks acceptance, silently — the oracle thinks it submitted,
//! the chain rejects. Letting individual oracle authors re-implement any of
//! these three things makes drift a question of when, not if. So the SDK
//! does all three itself, and the dev cannot override them:
//!
//! - [`OracleIdentity`] holds the signing key; its byte-level signing entry
//!   point is crate-private. There is no public method that signs arbitrary
//!   bytes.
//! - The runtime constructs the [`OracleDataSubmissionBody`] and signs it
//!   via `fialucci-types`'s authoritative `sign_oracle_data_submission` —
//!   the same call the chain's reference dev-tool binary uses, transitively
//!   bound to the same `fialucci-types` version the chain consumes.
//! - HTTP submission goes through the SDK's [`ChainClient`], which posts
//!   exactly the [`SignedOracleDataSubmission`] the signing call returned —
//!   nothing in between.
//!
//! What devs **do** control is what the oracle observes and what claim it
//! makes. That's the entire surface of [`OracleHandler::observe`]: given an
//! [`ObservationRequest`], decide whether to respond and, if so, with what
//! [`ProofClaim`] and what [`ProofEvidence`].
//!
//! ## Two submission paths
//!
//! 1. **Request-driven** (the default). [`Oracle::run`] polls
//!    `/oracle/observation-requests/matching` and calls
//!    [`OracleHandler::observe`] for each request the oracle is eligible to
//!    answer. Use this when your oracle should respond to upstream contract
//!    conditions.
//! 2. **Proactive**. Call [`Oracle::submit_proactive`] yourself, on whatever
//!    cadence makes sense, with the `domain` / `subject` / `claim` /
//!    `evidence` you want to assert. Use this when your oracle observes
//!    the world on its own schedule (e.g. a GitHub poller that submits
//!    when a PR is merged). The signing + HTTP + nonce + chain-id seam is
//!    still SDK-owned — you just skip the observation-request hop.
//!
//! ## Quick start
//!
//! ```no_run
//! use fialucci_oracle::{Oracle, OracleHandler, OracleIdentity, ObservationRequest, ProofClaimEvidence, HandlerError};
//! use fialucci_oracle::types::{ProofClaim, ProofEvidence, hash_evidence_bytes};
//! use async_trait::async_trait;
//!
//! struct MyOracle;
//!
//! #[async_trait]
//! impl OracleHandler for MyOracle {
//!     async fn observe(&self, _request: &ObservationRequest) -> Result<Option<ProofClaimEvidence>, HandlerError> {
//!         // Decide based on whatever off-chain data source the oracle wraps.
//!         let evidence_bytes = b"my custom evidence payload";
//!         Ok(Some(ProofClaimEvidence {
//!             claim: ProofClaim::WorkCompleted,
//!             evidence: ProofEvidence {
//!                 evidence_hash: hash_evidence_bytes(evidence_bytes),
//!                 evidence_uri: None,
//!                 content_type: Some("application/octet-stream".to_string()),
//!                 metadata: None,
//!             },
//!         }))
//!     }
//! }
//!
//! # async fn run() -> Result<(), Box<dyn std::error::Error>> {
//! let identity = OracleIdentity::load_from_file("oracle_key.json")?;
//! let oracle = Oracle::builder()
//!     .identity(identity)
//!     .node_url("http://127.0.0.1:8080")
//!     .handler(MyOracle)
//!     .build()
//!     .await?;
//! oracle.run().await?;
//! # Ok(()) }
//! ```

#![deny(missing_docs)]
#![warn(rust_2018_idioms)]

mod client;
mod handler;
mod identity;
mod proof_body;
mod runtime;

#[cfg(feature = "allora")]
mod allora_adapter;

pub use client::{ChainClient, ClientError, SubmissionAck};
pub use handler::{HandlerError, ObservationRequest, OracleHandler, ProofClaimEvidence};
pub use identity::{IdentityError, OracleIdentity};
pub use proof_body::{ProofBodyBuildError, ProofBodyBuilder};
pub use runtime::{BuildError, Oracle, OracleBuilder, RuntimeError};

/// Re-export of the canonical protocol types crate.
///
/// Use these types when constructing claims and evidence; the SDK and the
/// chain depend on the same `fialucci-types` version, so wire shapes match
/// by construction.
pub mod types {
    pub use fialucci_types::{
        derive_oracle_id, hash_evidence_bytes, OracleId, OracleObservationRequestId,
        OraclePublicKeyBytes, OracleSignatureBytes, ProofClaim, ProofDomain, ProofEvidence,
        ProofSubject,
    };
}

/// Allora-flavored EIP integration. Enabled by the `allora` feature
/// (`fialucci-oracle = { version = "...", features = ["allora"] }`).
///
/// Re-exports the EIP Outbound Channel Adapter that drops into an Allora
/// `service-activators:` block via `ref-name: fialucci_oracle_adapter`.
/// See the module-level docs on [`FialucciOracleAdapter`] for the full
/// Adapter-vs-Gateway design rationale.
#[cfg(feature = "allora")]
pub mod allora {
    pub use crate::allora_adapter::{
        AdapterAck, FialucciOracleAdapter, FialucciOracleSigner, OracleClaimPayload,
        SignedSubmissionEnvelope,
    };
}
