use serde::Deserialize;
use validator::Validate;

/// Login form validation
#[derive(Debug, Validate, Deserialize)]
pub struct LoginForm {
    #[validate(length(min = 3, max = 50))]
    pub username: String,

    #[validate(length(min = 8))]
    pub password: String,

    #[validate(email)]
    pub email: String,
}

/// Password change form validation
#[derive(Debug, Validate, Deserialize)]
pub struct PasswordChangeForm {
    #[validate(length(min = 8))]
    pub current_password: String,

    #[validate(length(min = 8))]
    pub new_password: String,
}

/// Sync start request validation
#[derive(Debug, Validate, Deserialize)]
pub struct SyncStartRequest {
    #[validate(length(min = 1, max = 50))]
    pub job_type: String,

    #[validate(length(min = 1, max = 20))]
    pub sync_direction: String,

    #[validate(range(min = 1, max = 1000000))]
    pub plesk_server_id: Option<i32>,

    #[validate(range(min = 1, max = 1000000))]
    pub sap_server_id: Option<i32>,
}

/// Setup configuration validation
#[derive(Debug, Validate, Deserialize)]
pub struct SetupConfig {
    #[validate(length(min = 1, max = 255))]
    pub plesk_host: String,

    #[validate(range(min = 1, max = 65535))]
    pub plesk_port: u16,

    #[validate(length(min = 1, max = 255))]
    pub plesk_username: String,

    #[validate(length(min = 1, max = 255))]
    pub plesk_password: String,

    #[validate(length(min = 1, max = 255))]
    pub sap_host: String,

    #[validate(range(min = 1, max = 65535))]
    pub sap_port: u16,

    #[validate(length(min = 1, max = 255))]
    pub sap_username: String,

    #[validate(length(min = 1, max = 255))]
    pub sap_password: String,

    #[validate(length(min = 1, max = 50))]
    pub sync_direction: String,

    #[validate(range(min = 1, max = 1440))]
    pub sync_interval_minutes: u32,

    #[validate(length(min = 1, max = 50))]
    pub conflict_resolution: String,
}

/// Billing record request validation
#[derive(Debug, Validate, Deserialize)]
pub struct BillingRecordRequest {
    #[validate(range(min = 1))]
    pub customer_id: i32,

    #[validate(length(min = 1, max = 100))]
    pub period_start: String,

    #[validate(length(min = 1, max = 100))]
    pub period_end: String,
}

/// Alert threshold validation
#[derive(Debug, Validate, Deserialize)]
pub struct AlertThreshold {
    #[validate(range(min = 1))]
    pub subscription_id: i32,

    #[validate(length(min = 1, max = 50))]
    pub metric_type: String,

    #[validate(range(min = 0.0))]
    pub threshold_value: f64,

    #[validate(length(min = 1, max = 50))]
    pub action_type: String,
}

/// Webhook configuration validation
#[derive(Debug, Validate, Deserialize)]
pub struct WebhookConfig {
    #[validate(length(min = 1, max = 500))]
    pub url: String,

    #[validate(length(min = 1, max = 50))]
    pub event_type: String,
}

/// Pricing configuration validation
#[derive(Debug, Validate, Deserialize)]
pub struct PricingConfig {
    #[validate(length(min = 1, max = 50))]
    pub metric_type: String,

    #[validate(length(min = 1, max = 50))]
    pub unit: String,

    #[validate(range(min = 0.0))]
    pub price_per_unit: f64,

    #[validate(custom = "Self::validate_is_active")]
    pub is_active: bool,
}

impl PricingConfig {
    fn validate_is_active(is_active: &bool) -> Result<(), validator::ValidationError> {
        if !is_active {
            return Err(validator::ValidationError::new("is_active"));
        }
        Ok(())
    }
}

/// Customer mapping validation
#[derive(Debug, Validate, Deserialize)]
pub struct CustomerMapping {
    #[validate(length(min = 1))]
    pub sap_customer_code: String,

    #[validate(range(min = 1))]
    pub plesk_customer_id: i32,

    #[validate(range(min = 1))]
    pub plesk_subscription_id: i32,
}

/// Subscription validation
#[derive(Debug, Validate, Deserialize)]
pub struct Subscription {
    #[validate(length(min = 1))]
    pub sap_subscription_id: String,

    #[validate(range(min = 1))]
    pub plesk_subscription_id: i32,

    #[validate(length(min = 1, max = 255))]
    pub name: String,

    #[validate(length(min = 1, max = 50))]
    pub status: String,
}

/// Two-factor verification validation
#[derive(Debug, Validate, Deserialize)]
pub struct TwoFactorVerify {
    #[validate(length(min = 6, max = 6))]
    pub code: String,
}

/// Server configuration validation
#[derive(Debug, Validate, Deserialize)]
pub struct ServerConfig {
    #[validate(length(min = 1, max = 255))]
    pub hostname: String,

    #[validate(range(min = 1, max = 65535))]
    pub port: u16,

    #[validate(length(min = 1, max = 255))]
    pub username: String,

    #[validate(length(min = 1, max = 255))]
    pub password: String,

    pub use_ssl: bool,
    pub verify_ssl: bool,
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_valid_login_form() {
        let form = LoginForm {
            username: "testuser".to_string(),
            password: "Test1234!".to_string(),
            email: "test@example.com".to_string(),
        };
        assert!(form.validate().is_ok());
    }

    #[test]
    fn test_invalid_login_form() {
        let form = LoginForm {
            username: "ab".to_string(),    // Too short
            password: "short".to_string(), // Too short
            email: "invalid".to_string(),  // Invalid email
        };
        let errors = form.validate().unwrap_err();
        assert!(!errors.is_empty());
    }

    #[test]
    fn test_valid_sync_request() {
        let request = SyncStartRequest {
            job_type: "full_sync".to_string(),
            sync_direction: "bidirectional".to_string(),
            plesk_server_id: Some(1),
            sap_server_id: Some(1),
        };
        assert!(request.validate().is_ok());
    }

    #[test]
    fn test_invalid_sync_request() {
        let request = SyncStartRequest {
            job_type: "".to_string(),                        // Empty
            sync_direction: "invalid_direction".to_string(), // Too long
            plesk_server_id: Some(9999999),                  // Too large
            sap_server_id: None,
        };
        let errors = request.validate().unwrap_err();
        assert!(!errors.is_empty());
    }

    #[test]
    fn test_valid_pricing_config() {
        let config = PricingConfig {
            metric_type: "cpu_usage".to_string(),
            unit: "percent".to_string(),
            price_per_unit: 0.5,
            is_active: true,
        };
        assert!(config.validate().is_ok());
    }

    #[test]
    fn test_invalid_pricing_config() {
        let config = PricingConfig {
            metric_type: "".to_string(), // Empty
            unit: "".to_string(),        // Empty
            price_per_unit: -1.0,        // Negative
            is_active: false,            // Inactive
        };
        let errors = config.validate().unwrap_err();
        assert!(!errors.is_empty());
    }

    #[test]
    fn test_valid_billing_record() {
        let record = BillingRecordRequest {
            customer_id: 1,
            period_start: "2026-01-01".to_string(),
            period_end: "2026-01-31".to_string(),
        };
        assert!(record.validate().is_ok());
    }

    #[test]
    fn test_invalid_billing_record() {
        let record = BillingRecordRequest {
            customer_id: 0,                    // Zero
            period_start: "".to_string(),      // Empty
            period_end: "invalid".to_string(), // Invalid date format
        };
        let errors = record.validate().unwrap_err();
        assert!(!errors.is_empty());
    }
}
