//! Common types used across the Cloudflare API.

use serde::{Deserialize, Serialize};

/// Standard Cloudflare API response wrapper.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ApiResponse<T> {
    /// Whether the request was successful
    pub success: bool,

    /// The result data
    #[serde(skip_serializing_if = "Option::is_none")]
    pub result: Option<T>,

    /// Any errors that occurred
    #[serde(default)]
    pub errors: Vec<ApiErrorDetail>,

    /// Any messages from the API
    #[serde(default)]
    pub messages: Vec<String>,

    /// Result metadata (pagination, etc.)
    #[serde(skip_serializing_if = "Option::is_none")]
    pub result_info: Option<ResultInfo>,
}

/// Error detail from Cloudflare API.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ApiErrorDetail {
    /// Error code
    pub code: i32,

    /// Error message
    pub message: String,
}

/// Pagination and result metadata.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ResultInfo {
    /// Current page number
    pub page: u32,

    /// Number of items per page
    pub per_page: u32,

    /// Total number of pages
    pub total_pages: u32,

    /// Total number of items
    pub count: u32,

    /// Total count across all pages
    pub total_count: u32,
}

/// Represents a change to be made (for diff output).
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ChangeAction {
    /// Create a new resource
    Create,

    /// Update an existing resource
    Update,

    /// Delete a resource
    Delete,

    /// No change needed
    NoChange,
}

impl ChangeAction {
    /// Check if this action will modify resources
    pub fn is_mutating(&self) -> bool {
        matches!(
            self,
            ChangeAction::Create | ChangeAction::Update | ChangeAction::Delete
        )
    }
}

/// Represents a pending change (for dry-run/diff mode).
#[derive(Debug, Clone)]
pub struct Change<T> {
    /// The action to be performed
    pub action: ChangeAction,

    /// The current state (if exists)
    pub current: Option<T>,

    /// The desired state (if applicable)
    pub desired: Option<T>,

    /// Human-readable description of the change
    pub description: String,
}

impl<T> Change<T> {
    /// Create a new creation change
    pub fn create(desired: T, description: String) -> Self {
        Self {
            action: ChangeAction::Create,
            current: None,
            desired: Some(desired),
            description,
        }
    }

    /// Create a new update change
    pub fn update(current: T, desired: T, description: String) -> Self {
        Self {
            action: ChangeAction::Update,
            current: Some(current),
            desired: Some(desired),
            description,
        }
    }

    /// Create a no-change entry
    pub fn no_change(current: T, description: String) -> Self {
        Self {
            action: ChangeAction::NoChange,
            current: Some(current),
            desired: None,
            description,
        }
    }
}
