//! 设备服务

use crate::db::Database;
use crate::models::{DeviceRow, DeviceResponse};
use anyhow::Result;
use chrono::Utc;
use uuid::Uuid;

/// 设备仓储
pub struct DeviceRepository<'a> {
    db: &'a Database,
}

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

    /// 注册设备
    pub async fn register(
        &self,
        device_id: &str,
        name: &str,
        os_type: &str,
        os_version: &str,
    ) -> Result<DeviceRow> {
        // 检查设备是否已存在
        if let Some(existing) = self.find_by_device_id(device_id).await? {
            // 更新设备信息
            self.update_last_seen(device_id).await?;
            return Ok(existing);
        }

        let id = Uuid::new_v4().to_string();
        let now = Utc::now().to_rfc3339();
        let verification_code = generate_verification_code();

        sqlx::query(
            r#"
            INSERT INTO devices (id, device_id, name, os_type, os_version, verification_code, last_seen, created_at)
            VALUES (?, ?, ?, ?, ?, ?, ?, ?)
            "#,
        )
        .bind(&id)
        .bind(device_id)
        .bind(name)
        .bind(os_type)
        .bind(os_version)
        .bind(&verification_code)
        .bind(&now)
        .bind(&now)
        .execute(&self.db.pool)
        .await?;

        self.find_by_id(&id).await
    }

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

        Ok(device)
    }

    /// 根据设备ID查找设备
    pub async fn find_by_device_id(&self, device_id: &str) -> Result<Option<DeviceRow>> {
        let device = sqlx::query_as::<_, DeviceRow>("SELECT * FROM devices WHERE device_id = ?")
            .bind(device_id)
            .fetch_optional(&self.db.pool)
            .await?;

        Ok(device)
    }

    /// 获取用户的所有设备
    pub async fn find_by_user(&self, user_id: &str) -> Result<Vec<DeviceRow>> {
        let devices = sqlx::query_as::<_, DeviceRow>(
            "SELECT * FROM devices WHERE user_id = ? ORDER BY last_seen DESC",
        )
        .bind(user_id)
        .fetch_all(&self.db.pool)
        .await?;

        Ok(devices)
    }

    /// 绑定设备到用户
    pub async fn bind_to_user(&self, device_id: &str, user_id: &str) -> Result<()> {
        sqlx::query("UPDATE devices SET user_id = ? WHERE device_id = ?")
            .bind(user_id)
            .bind(device_id)
            .execute(&self.db.pool)
            .await?;

        Ok(())
    }

    /// 解绑设备
    pub async fn unbind(&self, device_id: &str) -> Result<()> {
        sqlx::query("UPDATE devices SET user_id = NULL WHERE device_id = ?")
            .bind(device_id)
            .execute(&self.db.pool)
            .await?;

        Ok(())
    }

    /// 更新设备在线状态
    pub async fn set_online(&self, device_id: &str, online: bool) -> Result<()> {
        let now = Utc::now().to_rfc3339();
        sqlx::query("UPDATE devices SET is_online = ?, last_seen = ? WHERE device_id = ?")
            .bind(online)
            .bind(&now)
            .bind(device_id)
            .execute(&self.db.pool)
            .await?;

        Ok(())
    }
    
    /// 将所有设备设为离线（服务器启动时调用）
    pub async fn set_all_offline(&self) -> Result<u64> {
        let result = sqlx::query("UPDATE devices SET is_online = false WHERE is_online = true")
            .execute(&self.db.pool)
            .await?;

        Ok(result.rows_affected())
    }

    /// 更新设备允许远程状态
    pub async fn set_allow_remote(&self, device_id: &str, allow: bool) -> Result<()> {
        sqlx::query("UPDATE devices SET allow_remote = ? WHERE device_id = ?")
            .bind(allow)
            .bind(device_id)
            .execute(&self.db.pool)
            .await?;

        Ok(())
    }

    /// 更新验证码
    pub async fn update_verification_code(&self, device_id: &str) -> Result<String> {
        let code = generate_verification_code();
        sqlx::query("UPDATE devices SET verification_code = ? WHERE device_id = ?")
            .bind(&code)
            .bind(device_id)
            .execute(&self.db.pool)
            .await?;

        Ok(code)
    }

    /// 验证设备验证码
    pub async fn verify_code(&self, device_id: &str, code: &str) -> Result<bool> {
        let device = self.find_by_device_id(device_id).await?;
        if let Some(device) = device {
            Ok(device.verification_code.as_deref() == Some(code))
        } else {
            Ok(false)
        }
    }

    /// 更新最后访问时间
    pub async fn update_last_seen(&self, device_id: &str) -> Result<()> {
        let now = Utc::now().to_rfc3339();
        sqlx::query("UPDATE devices SET last_seen = ? WHERE device_id = ?")
            .bind(&now)
            .bind(device_id)
            .execute(&self.db.pool)
            .await?;

        Ok(())
    }

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

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

        Ok((devices, count.0))
    }

    /// 获取所有设备（包含用户名）
    pub async fn find_all_with_username(&self, offset: u32, limit: u32) -> Result<(Vec<DeviceWithUsername>, i64)> {
        let devices = sqlx::query_as::<_, DeviceWithUsername>(
            r#"
            SELECT d.*, u.username
            FROM devices d
            LEFT JOIN users u ON d.user_id = u.id
            ORDER BY d.last_seen DESC
            LIMIT ? OFFSET ?
            "#,
        )
        .bind(limit)
        .bind(offset)
        .fetch_all(&self.db.pool)
        .await?;

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

        Ok((devices, count.0))
    }

    /// 获取在线设备数量
    pub async fn count_online(&self) -> Result<i64> {
        let count: (i64,) = sqlx::query_as("SELECT COUNT(*) FROM devices WHERE is_online = 1")
            .fetch_one(&self.db.pool)
            .await?;

        Ok(count.0)
    }

    /// 删除设备
    pub async fn delete(&self, device_id: &str) -> Result<()> {
        sqlx::query("DELETE FROM devices WHERE device_id = ?")
            .bind(device_id)
            .execute(&self.db.pool)
            .await?;

        Ok(())
    }
}

/// 生成验证码
fn generate_verification_code() -> String {
    use rand::Rng;
    let mut rng = rand::thread_rng();
    (0..8)
        .map(|_| {
            let idx = rng.gen_range(0..36);
            if idx < 10 {
                (b'0' + idx) as char
            } else {
                (b'a' + idx - 10) as char
            }
        })
        .collect()
}

impl From<DeviceRow> for DeviceResponse {
    fn from(device: DeviceRow) -> Self {
        Self {
            id: device.id,
            device_id: device.device_id,
            name: device.name,
            os_type: device.os_type,
            os_version: device.os_version,
            is_online: device.is_online,
            allow_remote: device.allow_remote,
            last_seen: device.last_seen,
            user_id: device.user_id,
            username: None,
        }
    }
}

/// 设备及用户名的联合查询结果
#[derive(Debug, Clone, sqlx::FromRow)]
pub struct DeviceWithUsername {
    pub id: String,
    pub device_id: String,
    pub name: String,
    pub os_type: String,
    pub os_version: String,
    pub user_id: Option<String>,
    pub is_online: bool,
    pub allow_remote: bool,
    pub verification_code: Option<String>,
    pub last_seen: String,
    pub created_at: String,
    pub username: Option<String>,
}

impl From<DeviceWithUsername> for DeviceResponse {
    fn from(device: DeviceWithUsername) -> Self {
        Self {
            id: device.id,
            device_id: device.device_id,
            name: device.name,
            os_type: device.os_type,
            os_version: device.os_version,
            is_online: device.is_online,
            allow_remote: device.allow_remote,
            last_seen: device.last_seen,
            user_id: device.user_id,
            username: device.username,
        }
    }
}
