use crate::domain::entities::{credit_account, credit_transaction};
use anyhow::Result;
use sea_orm::{
    sea_query::Expr, ActiveModelTrait, ColumnTrait, DatabaseConnection, EntityTrait, QueryFilter,
    QueryOrder, QuerySelect, Set,
};

/// 积分账户与流水数据访问
pub struct CreditRepository {
    db: DatabaseConnection,
}

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

    pub async fn find_account(&self, user_id: &str) -> Result<Option<credit_account::Model>> {
        Ok(credit_account::Entity::find()
            .filter(credit_account::Column::UserId.eq(user_id))
            .one(&self.db)
            .await?)
    }

    #[allow(dead_code)]
    pub async fn create_account(
        &self,
        user_id: String,
        balance: i64,
        total_granted: i64,
    ) -> Result<credit_account::Model> {
        let model = credit_account::ActiveModel {
            user_id: Set(user_id),
            balance: Set(balance),
            version: Set(0),
            total_granted: Set(total_granted),
            total_consumed: Set(0),
            ..Default::default()
        };
        Ok(model.insert(&self.db).await?)
    }

    /// 乐观锁扣减：仅当 version 匹配时更新。返回是否成功。
    #[allow(dead_code)]
    pub async fn debit_optimistic(
        &self,
        user_id: &str,
        expected_version: i64,
        new_balance: i64,
    ) -> Result<bool> {
        let res = credit_account::Entity::update_many()
            .col_expr(credit_account::Column::Balance, Expr::value(new_balance))
            .col_expr(
                credit_account::Column::TotalConsumed,
                Expr::col(credit_account::Column::TotalConsumed).add(1),
            )
            .col_expr(
                credit_account::Column::Version,
                Expr::value(expected_version + 1),
            )
            .filter(credit_account::Column::UserId.eq(user_id))
            .filter(credit_account::Column::Version.eq(expected_version))
            .exec(&self.db)
            .await?;
        Ok(res.rows_affected > 0)
    }

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

    #[allow(dead_code)]
    pub async fn list_transactions(
        &self,
        user_id: &str,
        limit: u64,
        offset: u64,
    ) -> Result<Vec<credit_transaction::Model>> {
        Ok(credit_transaction::Entity::find()
            .filter(credit_transaction::Column::UserId.eq(user_id))
            .order_by_desc(credit_transaction::Column::CreatedAt)
            .offset(offset)
            .limit(limit)
            .all(&self.db)
            .await?)
    }
}
