use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};

/// Plesk configuration
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PleskConfig {
    pub host: String,
    pub port: u16,
    pub username: String,
    pub password: String,
    pub api_key: String,
    #[serde(default)]
    pub use_https: bool,
    #[serde(default)]
    pub verify_ssl: bool,
    #[serde(default)]
    pub two_factor_enabled: bool,
    pub two_factor_method: String,
    pub two_factor_secret: Option<String>,
    pub session_id: Option<String>,
}

/// SAP configuration
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SapConfig {
    pub host: String,
    pub port: u16,
    pub company_db: String,
    pub username: String,
    pub password: String,
    #[serde(default)]
    pub use_ssl: bool,
    pub timeout_seconds: u64,
}

/// Sync settings
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SyncSettings {
    pub sync_direction: String,
    pub sync_interval_minutes: u32,
    pub conflict_resolution: String,
    #[serde(default)]
    pub auto_sync_enabled: bool,
}

/// User database model
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UserDb {
    pub id: i32,
    pub username: String,
    pub email: String,
    pub role: String,
    pub password_hash: String,
    pub mfa_enabled: bool,
    pub failed_login_attempts: i32,
    pub locked_until: Option<DateTime<Utc>>,
}

/// Plesk test result
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum PleskTestResult {
    Success { message: String },
    Requires2FA { session_id: String, method: String },
    Error { message: String },
}

/// Setup configuration containing all subsystem configurations
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SetupConfig {
    pub plesk: PleskConfig,
    pub sap: SapConfig,
    pub sync: SyncSettings,
}

/// Form for starting a sync job
#[derive(Debug, Deserialize)]
pub struct SyncStartForm {
    pub job_type: String,
    pub sync_direction: String,
}

/// Form for updating configuration
#[derive(Debug, Deserialize)]
pub struct ConfigUpdate {
    pub key: String,
    pub value: String,
}

/// Form for two-factor verification
#[derive(Debug, Deserialize)]
pub struct TwoFactorVerify {
    pub code: String,
}

/// Sync job status enum
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum SyncJobStatus {
    Pending,
    Running,
    Completed,
    Failed,
    Cancelled,
}

/// Form for changing password
#[derive(Debug, Deserialize)]
pub struct PasswordChangeForm {
    pub current_password: String,
    pub new_password: String,
}

/// Billing record ID
#[derive(Debug, Deserialize)]
pub struct BillingRecordId {
    pub id: i32,
}

/// Test configuration (kept for backward compatibility with tests)
#[cfg(test)]
mod tests {
    use super::*;
    use chrono::NaiveDateTime;

    #[test]
    fn test_plesk_config_defaults() {
        let config = PleskConfig {
            host: "plesk.example.com".to_string(),
            port: 8443,
            username: "admin".to_string(),
            password: "password".to_string(),
            api_key: "".to_string(),
            use_https: true,
            verify_ssl: true,
            two_factor_enabled: false,
            two_factor_method: "none".to_string(),
            two_factor_secret: None,
            session_id: None,
        };

        assert_eq!(config.port, 8443);
        assert!(config.use_https);
        assert!(config.verify_ssl);
        assert!(!config.two_factor_enabled);
    }

    #[test]
    fn test_sap_config() {
        let config = SapConfig {
            host: "sap.example.com".to_string(),
            port: 50000,
            company_db: "SBODEMO".to_string(),
            username: "admin".to_string(),
            password: "password".to_string(),
            use_ssl: true,
            timeout_seconds: 30,
        };

        assert_eq!(config.port, 50000);
        assert_eq!(config.company_db, "SBODEMO");
        assert!(config.use_ssl);
        assert_eq!(config.timeout_seconds, 30);
    }

    #[test]
    fn test_sync_settings() {
        let settings = SyncSettings {
            sync_direction: "bidirectional".to_string(),
            sync_interval_minutes: 60,
            conflict_resolution: "timestamp_based".to_string(),
            auto_sync_enabled: true,
        };

        assert_eq!(settings.sync_direction, "bidirectional");
        assert_eq!(settings.sync_interval_minutes, 60);
        assert_eq!(settings.conflict_resolution, "timestamp_based");
        assert!(settings.auto_sync_enabled);
    }

    #[test]
    fn test_user_db() {
        let user = UserDb {
            id: 1,
            username: "admin".to_string(),
            email: "admin@example.com".to_string(),
            role: "admin".to_string(),
            password_hash: "hash".to_string(),
            mfa_enabled: true,
            failed_login_attempts: 0,
            locked_until: None,
        };

        assert_eq!(user.id, 1);
        assert_eq!(user.username, "admin");
        assert_eq!(user.email, "admin@example.com");
        assert_eq!(user.role, "admin");
        assert_eq!(user.password_hash, "hash");
        assert!(user.mfa_enabled);
        assert_eq!(user.failed_login_attempts, 0);
        assert!(user.locked_until.is_none());
    }

    #[test]
    fn test_plesk_test_result() {
        let success = PleskTestResult::Success {
            message: "Connected".to_string(),
        };
        let requires_2fa = PleskTestResult::Requires2FA {
            session_id: "session123".to_string(),
            method: "totp".to_string(),
        };
        let error = PleskTestResult::Error {
            message: "Connection failed".to_string(),
        };

        match success {
            PleskTestResult::Success { message } => assert_eq!(message, "Connected"),
            _ => panic!("Expected Success variant"),
        }

        match requires_2fa {
            PleskTestResult::Requires2FA { session_id, method } => {
                assert_eq!(session_id, "session123");
                assert_eq!(method, "totp");
            }
            _ => panic!("Expected Requires2FA variant"),
        }

        match error {
            PleskTestResult::Error { message } => assert_eq!(message, "Connection failed"),
            _ => panic!("Expected Error variant"),
        }
    }

    #[test]
    fn test_setup_config() {
        let config = SetupConfig {
            plesk: PleskConfig {
                host: "plesk.example.com".to_string(),
                port: 8443,
                username: "admin".to_string(),
                password: "password".to_string(),
                api_key: "".to_string(),
                use_https: true,
                verify_ssl: true,
                two_factor_enabled: false,
                two_factor_method: "none".to_string(),
                two_factor_secret: None,
                session_id: None,
            },
            sap: SapConfig {
                host: "sap.example.com".to_string(),
                port: 50000,
                company_db: "SBODEMO".to_string(),
                username: "admin".to_string(),
                password: "password".to_string(),
                use_ssl: true,
                timeout_seconds: 30,
            },
            sync: SyncSettings {
                sync_direction: "bidirectional".to_string(),
                sync_interval_minutes: 60,
                conflict_resolution: "timestamp_based".to_string(),
                auto_sync_enabled: true,
            },
        };

        assert_eq!(config.plesk.host, "plesk.example.com");
        assert_eq!(config.sap.port, 50000);
        assert_eq!(config.sync.sync_direction, "bidirectional");
    }
}
