//! 认证服务

use crate::config::Config;
use crate::db::Database;
use crate::models::{UserRow, UserResponse};
use anyhow::Result;
use chrono::{Duration, Utc};
use jsonwebtoken::{decode, encode, DecodingKey, EncodingKey, Header, Validation};
use serde::{Deserialize, Serialize};
use uuid::Uuid;

/// JWT Claims
#[derive(Debug, Serialize, Deserialize)]
pub struct Claims {
    pub sub: String,         // 用户ID
    pub username: String,    // 用户名
    pub role: String,        // 角色
    pub exp: i64,            // 过期时间
    pub iat: i64,            // 签发时间
}

/// 认证服务
pub struct AuthService {
    jwt_secret: String,
    jwt_expiry: i64,
}

impl AuthService {
    pub fn new(config: &Config) -> Self {
        Self {
            jwt_secret: config.jwt_secret.clone(),
            jwt_expiry: config.jwt_expiry,
        }
    }

    /// 生成JWT令牌
    pub fn generate_token(&self, user: &UserRow) -> Result<String> {
        let now = Utc::now();
        let exp = now + Duration::seconds(self.jwt_expiry);

        let claims = Claims {
            sub: user.id.clone(),
            username: user.username.clone(),
            role: user.role.clone(),
            exp: exp.timestamp(),
            iat: now.timestamp(),
        };

        let token = encode(
            &Header::default(),
            &claims,
            &EncodingKey::from_secret(self.jwt_secret.as_bytes()),
        )?;

        Ok(token)
    }

    /// 验证JWT令牌
    pub fn verify_token(&self, token: &str) -> Result<Claims> {
        let token_data = decode::<Claims>(
            token,
            &DecodingKey::from_secret(self.jwt_secret.as_bytes()),
            &Validation::default(),
        )?;

        Ok(token_data.claims)
    }

    /// 哈希密码
    pub fn hash_password(password: &str) -> (String, String) {
        use argon2::{
            password_hash::{rand_core::OsRng, PasswordHasher, SaltString},
            Argon2,
        };

        let salt = SaltString::generate(&mut OsRng);
        let argon2 = Argon2::default();
        let hash = argon2
            .hash_password(password.as_bytes(), &salt)
            .expect("Failed to hash password")
            .to_string();

        (hash, salt.to_string())
    }

    /// 验证密码
    pub fn verify_password(password: &str, hash: &str) -> bool {
        use argon2::{
            password_hash::{PasswordHash, PasswordVerifier},
            Argon2,
        };

        let parsed_hash = match PasswordHash::new(hash) {
            Ok(h) => h,
            Err(_) => return false,
        };

        Argon2::default()
            .verify_password(password.as_bytes(), &parsed_hash)
            .is_ok()
    }
}

/// 用户仓储
pub struct UserRepository<'a> {
    db: &'a Database,
}

impl<'a> UserRepository<'a> {
    pub fn new(db: &'a Database) -> Self {
        Self { db }
    }

    /// 创建用户
    pub async fn create(&self, username: &str, password_hash: &str, salt: &str, email: Option<&str>) -> Result<UserRow> {
        let id = Uuid::new_v4().to_string();
        let now = Utc::now().to_rfc3339();

        sqlx::query(
            r#"
            INSERT INTO users (id, username, password_hash, salt, email, role, created_at)
            VALUES (?, ?, ?, ?, ?, 'user', ?)
            "#,
        )
        .bind(&id)
        .bind(username)
        .bind(password_hash)
        .bind(salt)
        .bind(email)
        .bind(&now)
        .execute(&self.db.pool)
        .await?;

        self.find_by_id(&id).await
    }

    /// 根据ID查找用户
    pub async fn find_by_id(&self, id: &str) -> Result<UserRow> {
        let user = sqlx::query_as::<_, UserRow>("SELECT * FROM users WHERE id = ?")
            .bind(id)
            .fetch_one(&self.db.pool)
            .await?;

        Ok(user)
    }

    /// 根据用户名查找用户
    pub async fn find_by_username(&self, username: &str) -> Result<Option<UserRow>> {
        let user = sqlx::query_as::<_, UserRow>("SELECT * FROM users WHERE username = ?")
            .bind(username)
            .fetch_optional(&self.db.pool)
            .await?;

        Ok(user)
    }

    /// 更新最后登录时间
    pub async fn update_last_login(&self, id: &str) -> Result<()> {
        let now = Utc::now().to_rfc3339();
        sqlx::query("UPDATE users SET last_login = ? WHERE id = ?")
            .bind(&now)
            .bind(id)
            .execute(&self.db.pool)
            .await?;

        Ok(())
    }

    /// 更新用户信息
    pub async fn update(&self, id: &str, email: Option<&str>, password_hash: Option<&str>) -> Result<()> {
        if let Some(email) = email {
            sqlx::query("UPDATE users SET email = ? WHERE id = ?")
                .bind(email)
                .bind(id)
                .execute(&self.db.pool)
                .await?;
        }

        if let Some(hash) = password_hash {
            sqlx::query("UPDATE users SET password_hash = ? WHERE id = ?")
                .bind(hash)
                .bind(id)
                .execute(&self.db.pool)
                .await?;
        }

        Ok(())
    }

    /// 设置用户角色
    pub async fn set_role(&self, id: &str, role: &str) -> Result<()> {
        sqlx::query("UPDATE users SET role = ? WHERE id = ?")
            .bind(role)
            .bind(id)
            .execute(&self.db.pool)
            .await?;

        Ok(())
    }

    /// 获取所有用户
    pub async fn find_all(&self, offset: u32, limit: u32) -> Result<(Vec<UserRow>, i64)> {
        let users = sqlx::query_as::<_, UserRow>(
            "SELECT * FROM users ORDER BY created_at DESC LIMIT ? OFFSET ?",
        )
        .bind(limit)
        .bind(offset)
        .fetch_all(&self.db.pool)
        .await?;

        let count: (i64,) = sqlx::query_as("SELECT COUNT(*) FROM users")
            .fetch_one(&self.db.pool)
            .await?;

        Ok((users, count.0))
    }

    /// 删除用户
    pub async fn delete(&self, id: &str) -> Result<()> {
        // 先解除用户与设备的绑定
        sqlx::query("UPDATE devices SET user_id = NULL WHERE user_id = ?")
            .bind(id)
            .execute(&self.db.pool)
            .await?;
        
        // 删除用户的控制历史记录
        sqlx::query("DELETE FROM control_history WHERE user_id = ?")
            .bind(id)
            .execute(&self.db.pool)
            .await?;
        
        // 最后删除用户
        sqlx::query("DELETE FROM users WHERE id = ?")
            .bind(id)
            .execute(&self.db.pool)
            .await?;

        Ok(())
    }
}

impl From<UserRow> for UserResponse {
    fn from(user: UserRow) -> Self {
        Self {
            id: user.id,
            username: user.username,
            email: user.email,
            role: user.role,
            created_at: user.created_at,
        }
    }
}
