use std::collections::HashMap;

use serde::{Deserialize, Serialize};

#[derive(Debug, Clone, Serialize)]
pub struct LicenseCheckPayload<'a> {
    pub product: &'a str,
    pub feature: &'a str,
}

#[derive(Debug, Clone, Deserialize)]
pub struct LicenseCheckResponse {
    pub allowed: bool,
    pub product: String,
    pub plan: Option<String>,
    pub feature: String,
    pub source: Option<String>,
}

#[derive(Debug, Clone, Serialize)]
pub struct LicenseActivatePayload<'a> {
    pub product: &'a str,
    pub device_type: &'a str,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub platform: Option<&'a str>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub device_name: Option<&'a str>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub app_version: Option<&'a str>,
    pub fingerprint: &'a str,
}

#[derive(Debug, Clone, Serialize)]
pub struct LicenseRefreshPayload<'a> {
    pub product: &'a str,
    pub fingerprint: &'a str,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SignedLicense {
    pub key_id: String,
    pub algorithm: String,
    pub payload: String,
    pub signature: String,
    pub valid_until: String,
}

#[derive(Debug, Clone, Deserialize)]
pub struct ActivatedDevice {
    pub id: String,
    #[serde(rename = "type")]
    pub device_type: String,
    pub slots_used: u32,
    pub slots_limit: Option<u32>,
}

#[derive(Debug, Clone, Deserialize)]
pub struct LicenseActivateResponse {
    pub allowed: bool,
    pub product: String,
    pub plan: String,
    #[serde(default)]
    pub features: HashMap<String, bool>,
    pub device: ActivatedDevice,
    pub license: SignedLicense,
}

#[derive(Debug, Clone, Deserialize)]
pub struct LicensePublicKey {
    pub key_id: String,
    pub algorithm: String,
    pub public_key_base64: String,
}

#[derive(Debug, Clone, Deserialize)]
pub struct LicensePublicKeysResponse {
    pub keys: Vec<LicensePublicKey>,
    pub active_key_id: Option<String>,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum LicensingMode {
    OfflineSnapshot,
    OnlineRealtime,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum UsagePeriod {
    Daily,
    Weekly,
    Monthly,
    Yearly,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum UsageFeatureState {
    Bool {
        enabled: bool,
    },
    Counter {
        allowance: u64,
        period: UsagePeriod,
        period_start: String,
        period_end: String,
        consumed_at_issue: u64,
    },
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LicenseSnapshotPayload {
    #[serde(default)]
    pub v: Option<u32>,
    pub key_id: String,
    pub customer_id: String,
    pub product_key: String,
    pub plan_key: String,
    #[serde(default)]
    pub licensing_mode: Option<LicensingMode>,
    #[serde(default)]
    pub features: HashMap<String, bool>,
    #[serde(default)]
    pub usage: HashMap<String, UsageFeatureState>,
    pub fingerprint_hash: String,
    #[serde(default)]
    pub serial: u64,
    pub issued_at: String,
    pub valid_until: String,
    #[serde(default)]
    pub paid_up_until: Option<String>,
    #[serde(default)]
    pub fallback_release_date: Option<String>,
    #[serde(default)]
    pub updates_window_days: Option<u32>,
    #[serde(default)]
    pub offline_grace_days: Option<u32>,
    #[serde(default)]
    pub device_limit: Option<u32>,
}

#[derive(Debug, Clone, Serialize)]
pub struct LicenseSyncUsagePayload<'a> {
    pub product: &'a str,
    pub fingerprint: &'a str,
    pub serial: u64,
    pub deltas: HashMap<String, u64>,
}

#[derive(Debug, Clone, Deserialize)]
pub struct LicenseSyncUsageResponse {
    pub license: SignedLicense,
    pub applied: HashMap<String, u64>,
    pub serial: u64,
}
