//! Response models for the ipdata.info API.
//!
//! The API omits null/empty fields, so most fields are optional and deserialize
//! as `None`/default when absent. Unknown fields are ignored automatically by
//! serde (the default behavior when no `deny_unknown_fields` attribute is set).

use serde::Deserialize;

/// Full geolocation record returned by [`crate::Client::lookup`].
#[derive(Debug, Clone, Default, Deserialize)]
pub struct IpInfo {
    #[serde(default)]
    pub ip: String,
    #[serde(default)]
    pub success: bool,
    /// Address family, e.g. `"IPv4"` / `"IPv6"`. Named `type_` because `type`
    /// is a reserved keyword in Rust.
    #[serde(default, rename = "type")]
    pub type_: String,
    #[serde(default)]
    pub continent: Option<String>,
    #[serde(default)]
    pub continent_code: Option<String>,
    #[serde(default)]
    pub country: Option<String>,
    #[serde(default)]
    pub country_code: Option<String>,
    #[serde(default)]
    pub region: Option<String>,
    #[serde(default)]
    pub city: Option<String>,
    #[serde(default)]
    pub latitude: Option<f64>,
    #[serde(default)]
    pub longitude: Option<f64>,
    #[serde(default)]
    pub is_eu: Option<bool>,
    #[serde(default)]
    pub timezone: Option<String>,
    #[serde(default)]
    pub zip: Option<String>,
    #[serde(default)]
    pub postal: Option<String>,
    #[serde(default)]
    pub calling_code: Option<String>,
    #[serde(default)]
    pub capital: Option<String>,
    #[serde(default)]
    pub borders: Option<String>,
    #[serde(default)]
    pub asn: Option<i64>,
    #[serde(default)]
    pub asn_org: Option<String>,
    #[serde(default)]
    pub isp: Option<String>,
    #[serde(default)]
    pub registry: Option<String>,
    #[serde(default)]
    pub is_proxy: Option<bool>,
    #[serde(default)]
    pub is_hosting: Option<bool>,
    #[serde(default)]
    pub network: Option<Network>,
    #[serde(default)]
    pub flag: Option<Flag>,
    #[serde(default)]
    pub connection: Option<Connection>,
    #[serde(default)]
    pub time_zone: Option<TimeZone>,
    #[serde(default)]
    pub currency: Option<Currency>,
    #[serde(default)]
    pub security: Option<Security>,
}

/// ASN/route block for the IP.
#[derive(Debug, Clone, Default, Deserialize)]
pub struct Network {
    #[serde(default)]
    pub asn: i64,
    #[serde(default)]
    pub as_name: String,
    #[serde(default)]
    pub route: String,
    #[serde(default)]
    pub registry_country: String,
}

/// Flag image + emoji representations of the country.
#[derive(Debug, Clone, Default, Deserialize)]
pub struct Flag {
    #[serde(default)]
    pub img: String,
    #[serde(default)]
    pub emoji: String,
    #[serde(default)]
    pub emoji_unicode: String,
}

/// Connection (ASN/org/ISP) block.
#[derive(Debug, Clone, Default, Deserialize)]
pub struct Connection {
    #[serde(default)]
    pub asn: i64,
    #[serde(default)]
    pub org: String,
    #[serde(default)]
    pub isp: String,
    #[serde(default)]
    pub domain: Option<String>,
}

/// Enriched timezone object.
#[derive(Debug, Clone, Default, Deserialize)]
pub struct TimeZone {
    #[serde(default)]
    pub id: String,
    #[serde(default)]
    pub abbr: String,
    #[serde(default)]
    pub is_dst: bool,
    #[serde(default)]
    pub offset: i64,
    #[serde(default)]
    pub utc: String,
    #[serde(default)]
    pub current_time: String,
}

/// Country currency block.
#[derive(Debug, Clone, Default, Deserialize)]
pub struct Currency {
    #[serde(default)]
    pub name: String,
    #[serde(default)]
    pub code: String,
    #[serde(default)]
    pub symbol: String,
}

/// Anonymity/threat flags for the IP.
#[derive(Debug, Clone, Default, Deserialize)]
pub struct Security {
    #[serde(default)]
    pub anonymous: bool,
    #[serde(default)]
    pub proxy: bool,
    #[serde(default)]
    pub vpn: bool,
    #[serde(default)]
    pub tor: bool,
    #[serde(default)]
    pub hosting: bool,
}

/// Compact geo subset returned by [`crate::Client::geo`].
#[derive(Debug, Clone, Default, Deserialize)]
pub struct GeoInfo {
    #[serde(default)]
    pub ip: String,
    #[serde(default)]
    pub city: Option<String>,
    #[serde(default)]
    pub region: Option<String>,
    #[serde(default)]
    pub country: Option<String>,
    #[serde(default)]
    pub country_code: Option<String>,
    #[serde(default)]
    pub latitude: Option<f64>,
    #[serde(default)]
    pub longitude: Option<f64>,
    #[serde(default)]
    pub timezone: Option<String>,
    #[serde(default)]
    pub zip: Option<String>,
}

/// Compact ASN subset returned by [`crate::Client::asn`].
#[derive(Debug, Clone, Default, Deserialize)]
pub struct AsnBrief {
    #[serde(default)]
    pub ip: String,
    #[serde(default)]
    pub asn: Option<i64>,
    #[serde(default)]
    pub asn_org: Option<String>,
    #[serde(default)]
    pub isp: Option<String>,
    #[serde(default)]
    pub registry: Option<String>,
}

/// Result of a threat-intel lookup. When `listed` is `false` the remaining
/// fields are absent.
#[derive(Debug, Clone, Default, Deserialize)]
pub struct ThreatMatch {
    #[serde(default)]
    pub value: String,
    #[serde(default)]
    pub ioc_type: String,
    #[serde(default)]
    pub listed: bool,
    #[serde(default)]
    pub threat_type: Option<String>,
    #[serde(default)]
    pub sources: Option<Vec<String>>,
    #[serde(default)]
    pub confidence: Option<i64>,
    #[serde(default)]
    pub first_seen: Option<String>,
    #[serde(default)]
    pub last_seen: Option<String>,
}
