use std::collections::HashMap;

use crate::client::Client;
use crate::error::Error;
use crate::license::{decode_license, verify_license};
use crate::types::{
    LicenseActivatePayload, LicenseRefreshPayload, LicenseSnapshotPayload, SignedLicense,
};

pub struct ActivateOrRefreshOptions<'a> {
    pub product: &'a str,
    pub fingerprint: &'a str,
    pub device_type: &'a str,
    pub platform: Option<&'a str>,
    pub device_name: Option<&'a str>,
    pub app_version: Option<&'a str>,
}

#[derive(Debug, Clone)]
pub struct VerifiedLicense {
    pub signed: SignedLicense,
    pub payload: LicenseSnapshotPayload,
    pub plan: String,
    pub features: HashMap<String, bool>,
    pub device_id: String,
}

/// Refresh the device's signed license, falling back to activation when the
/// device is not yet registered (404), then verify the Ed25519 signature
/// against the supplied public keys (keyed by `key_id`) and decode the payload.
pub async fn activate_or_refresh(
    client: &Client,
    opts: &ActivateOrRefreshOptions<'_>,
    public_keys: &HashMap<String, String>,
) -> Result<VerifiedLicense, Error> {
    let response = match client
        .license_refresh(LicenseRefreshPayload {
            product: opts.product,
            fingerprint: opts.fingerprint,
        })
        .await
    {
        Ok(response) => response,
        Err(Error::Api { status: 404, .. }) => {
            client
                .license_activate(LicenseActivatePayload {
                    product: opts.product,
                    device_type: opts.device_type,
                    platform: opts.platform,
                    device_name: opts.device_name,
                    app_version: opts.app_version,
                    fingerprint: opts.fingerprint,
                })
                .await?
        }
        Err(e) => return Err(e),
    };

    let signed = response.license;
    let public_key = public_keys.get(&signed.key_id).ok_or_else(|| Error::Api {
        status: 0,
        code: format!("unknown signing key_id: {}", signed.key_id),
        body: None,
    })?;

    if !verify_license(&signed, public_key)? {
        return Err(Error::Api {
            status: 0,
            code: "license signature verification failed".to_string(),
            body: None,
        });
    }

    let decoded = decode_license(&signed)?;

    Ok(VerifiedLicense {
        signed,
        payload: decoded.payload,
        plan: response.plan,
        features: response.features,
        device_id: response.device.id,
    })
}
