use crate::AppService;
use crate::error::AppError;
use chrono::Utc;
use models::users::{user_activity_log, user_notification};
use sea_orm::*;
use serde::{Deserialize, Serialize};
use session::Session;
use uuid::Uuid;

#[derive(Deserialize, Serialize, Clone, Debug, utoipa::ToSchema)]
pub struct NotificationPreferencesParams {
    pub email_enabled: Option<bool>,
    pub in_app_enabled: Option<bool>,
    pub push_enabled: Option<bool>,
    pub digest_mode: Option<String>,
    pub dnd_enabled: Option<bool>,
    pub dnd_start_minute: Option<i32>,
    pub dnd_end_minute: Option<i32>,
    pub marketing_enabled: Option<bool>,
    pub security_enabled: Option<bool>,
    pub product_enabled: Option<bool>,
}

#[derive(Deserialize, Serialize, Clone, Debug, utoipa::ToSchema)]
pub struct NotificationPreferencesResponse {
    pub user_id: Uuid,
    pub email_enabled: bool,
    pub in_app_enabled: bool,
    pub push_enabled: bool,
    pub digest_mode: String,
    pub dnd_enabled: bool,
    pub dnd_start_minute: Option<i32>,
    pub dnd_end_minute: Option<i32>,
    pub marketing_enabled: bool,
    pub security_enabled: bool,
    pub product_enabled: bool,
    pub created_at: chrono::DateTime<Utc>,
    pub updated_at: chrono::DateTime<Utc>,
}

impl From<user_notification::Model> for NotificationPreferencesResponse {
    fn from(prefs: user_notification::Model) -> Self {
        NotificationPreferencesResponse {
            user_id: prefs.user,
            email_enabled: prefs.email_enabled,
            in_app_enabled: prefs.in_app_enabled,
            push_enabled: prefs.push_enabled,
            digest_mode: prefs.digest_mode,
            dnd_enabled: prefs.dnd_enabled,
            dnd_start_minute: prefs.dnd_start_minute,
            dnd_end_minute: prefs.dnd_end_minute,
            marketing_enabled: prefs.marketing_enabled,
            security_enabled: prefs.security_enabled,
            product_enabled: prefs.product_enabled,
            created_at: prefs.created_at,
            updated_at: prefs.updated_at,
        }
    }
}

impl AppService {
    pub async fn user_get_notification_preferences(
        &self,
        context: &Session,
    ) -> Result<NotificationPreferencesResponse, AppError> {
        let user_uid = context.user().ok_or(AppError::Unauthorized)?;

        let prefs = user_notification::Entity::find_by_id(user_uid)
            .one(&self.db)
            .await?;

        if let Some(prefs) = prefs {
            Ok(NotificationPreferencesResponse::from(prefs))
        } else {
            self.user_create_default_notification_preferences(user_uid)
                .await
        }
    }

    pub async fn user_update_notification_preferences(
        &self,
        context: &Session,
        params: NotificationPreferencesParams,
    ) -> Result<NotificationPreferencesResponse, AppError> {
        let user_uid = context.user().ok_or(AppError::Unauthorized)?;

        let prefs = user_notification::Entity::find_by_id(user_uid)
            .one(&self.db)
            .await?;

        let updated_prefs = if let Some(prefs) = prefs {
            let mut active_prefs: user_notification::ActiveModel = prefs.into();

            if let Some(email_enabled) = params.email_enabled {
                active_prefs.email_enabled = Set(email_enabled);
            }
            if let Some(in_app_enabled) = params.in_app_enabled {
                active_prefs.in_app_enabled = Set(in_app_enabled);
            }
            if let Some(push_enabled) = params.push_enabled {
                active_prefs.push_enabled = Set(push_enabled);
            }
            if let Some(digest_mode) = params.digest_mode.clone() {
                active_prefs.digest_mode = Set(digest_mode);
            }
            if let Some(dnd_enabled) = params.dnd_enabled {
                active_prefs.dnd_enabled = Set(dnd_enabled);
            }
            if let Some(dnd_start_minute) = params.dnd_start_minute {
                active_prefs.dnd_start_minute = Set(Some(dnd_start_minute));
            }
            if let Some(dnd_end_minute) = params.dnd_end_minute {
                active_prefs.dnd_end_minute = Set(Some(dnd_end_minute));
            }
            if let Some(marketing_enabled) = params.marketing_enabled {
                active_prefs.marketing_enabled = Set(marketing_enabled);
            }
            if let Some(security_enabled) = params.security_enabled {
                active_prefs.security_enabled = Set(security_enabled);
            }
            if let Some(product_enabled) = params.product_enabled {
                active_prefs.product_enabled = Set(product_enabled);
            }
            active_prefs.updated_at = Set(Utc::now());

            active_prefs.update(&self.db).await?
        } else {
            let new_prefs = user_notification::ActiveModel {
                user: Set(user_uid),
                email_enabled: Set(params.email_enabled.unwrap_or(true)),
                in_app_enabled: Set(params.in_app_enabled.unwrap_or(true)),
                push_enabled: Set(params.push_enabled.unwrap_or(false)),
                digest_mode: Set(params
                    .digest_mode
                    .clone()
                    .unwrap_or_else(|| "daily".to_string())),
                dnd_enabled: Set(params.dnd_enabled.unwrap_or(false)),
                dnd_start_minute: Set(params.dnd_start_minute),
                dnd_end_minute: Set(params.dnd_end_minute),
                marketing_enabled: Set(params.marketing_enabled.unwrap_or(false)),
                security_enabled: Set(params.security_enabled.unwrap_or(true)),
                product_enabled: Set(params.product_enabled.unwrap_or(false)),
                created_at: Set(Utc::now()),
                updated_at: Set(Utc::now()),
            };

            new_prefs.insert(&self.db).await?
        };

        let _ = user_activity_log::ActiveModel {
            user_uid: Set(Some(user_uid)),
            action: Set("notification_preferences_update".to_string()),
            ip_address: Set(context.ip_address()),
            user_agent: Set(context.user_agent()),
            details: Set(serde_json::json!({
                "updated_fields": {
                    "email_enabled": params.email_enabled.is_some(),
                    "in_app_enabled": params.in_app_enabled.is_some(),
                    "push_enabled": params.push_enabled.is_some(),
                    "digest_mode": params.digest_mode.is_some(),
                    "dnd_enabled": params.dnd_enabled.is_some(),
                    "marketing_enabled": params.marketing_enabled.is_some(),
                    "security_enabled": params.security_enabled.is_some(),
                    "product_enabled": params.product_enabled.is_some(),
                }
            })),
            created_at: Set(Utc::now()),
            ..Default::default()
        }
        .insert(&self.db)
        .await;

        Ok(NotificationPreferencesResponse::from(updated_prefs))
    }

    async fn user_create_default_notification_preferences(
        &self,
        user_uid: Uuid,
    ) -> Result<NotificationPreferencesResponse, AppError> {
        let prefs = user_notification::ActiveModel {
            user: Set(user_uid),
            email_enabled: Set(true),
            in_app_enabled: Set(true),
            push_enabled: Set(false),
            digest_mode: Set("daily".to_string()),
            dnd_enabled: Set(false),
            dnd_start_minute: Set(None),
            dnd_end_minute: Set(None),
            marketing_enabled: Set(false),
            security_enabled: Set(true),
            product_enabled: Set(false),
            created_at: Set(Utc::now()),
            updated_at: Set(Utc::now()),
        };

        let created_prefs = prefs.insert(&self.db).await?;

        Ok(NotificationPreferencesResponse::from(created_prefs))
    }
}
