use crate::domain::entities::mailbox;
use anyhow::Result;
use sea_orm::{
    ActiveModelTrait, ColumnTrait, DatabaseConnection, EntityTrait, PaginatorTrait, QueryFilter,
    QueryOrder, Set,
};

/// 临时邮箱地址数据访问
pub struct MailboxRepository {
    db: DatabaseConnection,
}

impl MailboxRepository {
    pub fn new(db: DatabaseConnection) -> Self {
        Self { db }
    }

    /// 按地址查询有效邮箱（status=active 且未过期）—— SMTP 收信校验用
    pub async fn find_active_by_address(&self, address: &str) -> Result<Option<mailbox::Model>> {
        let now = chrono::Utc::now().naive_utc();
        let m = mailbox::Entity::find()
            .filter(mailbox::Column::Address.eq(address))
            .filter(mailbox::Column::Status.eq("active"))
            .filter(mailbox::Column::ExpiresAt.gt(now))
            .one(&self.db)
            .await?;
        Ok(m)
    }

    /// 按地址查询（不限状态，用于 token 校验）
    #[allow(dead_code)]
    pub async fn find_by_address(&self, address: &str) -> Result<Option<mailbox::Model>> {
        Ok(mailbox::Entity::find()
            .filter(mailbox::Column::Address.eq(address))
            .one(&self.db)
            .await?)
    }

    pub async fn find_by_id(&self, id: i64) -> Result<Option<mailbox::Model>> {
        Ok(mailbox::Entity::find_by_id(id).one(&self.db).await?)
    }

    pub async fn list_by_user(&self, user_id: &str) -> Result<Vec<mailbox::Model>> {
        Ok(mailbox::Entity::find()
            .filter(mailbox::Column::UserId.eq(user_id))
            .order_by_desc(mailbox::Column::CreatedAt)
            .all(&self.db)
            .await?)
    }

    #[allow(dead_code)]
    pub async fn count_by_user(&self, user_id: &str) -> Result<i64> {
        let c = mailbox::Entity::find()
            .filter(mailbox::Column::UserId.eq(user_id))
            .count(&self.db)
            .await?;
        Ok(c as i64)
    }

    #[allow(dead_code)]
    pub async fn count_by_address(&self, address: &str) -> Result<i64> {
        let c = mailbox::Entity::find()
            .filter(mailbox::Column::Address.eq(address))
            .count(&self.db)
            .await?;
        Ok(c as i64)
    }

    #[allow(dead_code)]
    pub async fn insert(&self, model: mailbox::ActiveModel) -> Result<mailbox::Model> {
        Ok(model.insert(&self.db).await?)
    }

    /// 吊销邮箱（软删除）
    pub async fn revoke(&self, id: i64) -> Result<()> {
        let m = mailbox::Entity::find_by_id(id)
            .one(&self.db)
            .await?
            .ok_or_else(|| anyhow::anyhow!("邮箱不存在"))?;
        let mut active: mailbox::ActiveModel = m.into();
        active.status = Set("revoked".into());
        active.update(&self.db).await?;
        Ok(())
    }

    /// 轮换 access_token_hash
    pub async fn update_token_hash(&self, id: i64, token_hash: String) -> Result<()> {
        let m = mailbox::Entity::find_by_id(id)
            .one(&self.db)
            .await?
            .ok_or_else(|| anyhow::anyhow!("邮箱不存在"))?;
        let mut active: mailbox::ActiveModel = m.into();
        active.access_token_hash = Set(token_hash);
        active.update(&self.db).await?;
        Ok(())
    }

    /// 累加已用容量
    #[allow(dead_code)]
    pub async fn add_used_bytes(&self, id: i64, delta: i64) -> Result<()> {
        let m = mailbox::Entity::find_by_id(id)
            .one(&self.db)
            .await?
            .ok_or_else(|| anyhow::anyhow!("邮箱不存在"))?;
        let new_used = m.used_bytes + delta;
        let mut active: mailbox::ActiveModel = m.into();
        active.used_bytes = Set(new_used);
        active.update(&self.db).await?;
        Ok(())
    }

    /// 列出已过期但仍标记为 active 的邮箱（清理任务用）
    pub async fn list_expired_active(&self) -> Result<Vec<mailbox::Model>> {
        let now = chrono::Utc::now().naive_utc();
        Ok(mailbox::Entity::find()
            .filter(mailbox::Column::Status.eq("active"))
            .filter(mailbox::Column::ExpiresAt.lte(now))
            .all(&self.db)
            .await?)
    }

    /// 标记为 expired
    pub async fn mark_expired(&self, id: i64) -> Result<()> {
        let m = mailbox::Entity::find_by_id(id).one(&self.db).await?;
        if let Some(m) = m {
            let mut active: mailbox::ActiveModel = m.into();
            active.status = Set("expired".into());
            active.update(&self.db).await?;
        }
        Ok(())
    }
}
