#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
用户管理模块
提供用户认证、注册、密码管理等功能
"""

import hashlib
import secrets
import datetime
from typing import Optional, List, Dict, Any
import pymysql
from database_config import DatabaseConfig


class User:
    """用户类"""
    
    def __init__(self, user_id: int = None, username: str = "", password_hash: str = "", 
                 salt: str = "", role: str = "user", created_at: datetime.datetime = None,
                 last_login: datetime.datetime = None, is_active: bool = True):
        """
        初始化用户对象
        
        Args:
            user_id: 用户ID
            username: 用户名
            password_hash: 密码哈希值
            salt: 密码盐值
            role: 用户角色 (admin, user)
            created_at: 创建时间
            last_login: 最后登录时间
            is_active: 是否激活
        """
        self.user_id = user_id
        self.username = username
        self.password_hash = password_hash
        self.salt = salt
        self.role = role
        self.created_at = created_at or datetime.datetime.now()
        self.last_login = last_login
        self.is_active = is_active
    
    def to_dict(self) -> Dict[str, Any]:
        """转换为字典格式"""
        return {
            'user_id': self.user_id,
            'username': self.username,
            'role': self.role,
            'created_at': self.created_at.isoformat() if self.created_at else None,
            'last_login': self.last_login.isoformat() if self.last_login else None,
            'is_active': self.is_active
        }


class UserManager:
    """用户管理器"""
    
    def __init__(self, host: str, port: int, user: str, password: str, 
                 database: str, charset: str = 'utf8mb4'):
        """
        初始化用户管理器
        
        Args:
            host: 数据库主机
            port: 数据库端口
            user: 数据库用户名
            password: 数据库密码
            database: 数据库名
            charset: 字符集
        """
        self.host = host
        self.port = port
        self.user = user
        self.password = password
        self.database = database
        self.charset = charset
        
        # 初始化数据库表
        self._create_tables()
        
        # 创建默认管理员账户
        self._create_default_admin()
    
    def _get_connection(self):
        """获取数据库连接"""
        return pymysql.connect(
            host=self.host,
            port=self.port,
            user=self.user,
            password=self.password,
            database=self.database,
            charset=self.charset,
            autocommit=True
        )
    
    def _create_tables(self):
        """创建用户表"""
        connection = self._get_connection()
        try:
            cursor = connection.cursor()
            
            # 创建用户表
            create_users_table = """
            CREATE TABLE IF NOT EXISTS users (
                user_id INT AUTO_INCREMENT PRIMARY KEY,
                username VARCHAR(50) UNIQUE NOT NULL,
                password_hash VARCHAR(255) NOT NULL,
                salt VARCHAR(255) NOT NULL,
                role ENUM('admin', 'user') DEFAULT 'user',
                created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
                last_login TIMESTAMP NULL,
                is_active BOOLEAN DEFAULT TRUE,
                INDEX idx_username (username),
                INDEX idx_role (role)
            ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
            """
            
            cursor.execute(create_users_table)
            print("✓ 用户表创建/验证完成")
            
        except Exception as e:
            print(f"创建用户表失败: {e}")
            raise
        finally:
            connection.close()
    
    def _create_default_admin(self):
        """创建默认管理员账户"""
        try:
            # 检查是否已有管理员账户
            if self.get_user_by_username("admin"):
                return
            
            # 创建默认管理员：admin/admin123
            salt = self._generate_salt()
            password_hash = self._hash_password("admin123", salt)
            
            admin_user = User(
                username="admin",
                password_hash=password_hash,
                salt=salt,
                role="admin"
            )
            
            user_id = self._create_user_in_db(admin_user)
            if user_id:
                print("✓ 默认管理员账户已创建 (用户名: admin, 密码: admin123)")
                print("  请登录后立即修改密码！")
            
        except Exception as e:
            print(f"创建默认管理员账户失败: {e}")
    
    def _generate_salt(self) -> str:
        """生成随机盐值"""
        return secrets.token_hex(32)
    
    def _hash_password(self, password: str, salt: str) -> str:
        """
        对密码进行哈希加密
        
        Args:
            password: 原始密码
            salt: 盐值
            
        Returns:
            加密后的密码哈希值
        """
        # 使用SHA-256进行多轮哈希
        password_bytes = (password + salt).encode('utf-8')
        
        # 进行10000轮哈希增强安全性
        for _ in range(10000):
            password_bytes = hashlib.sha256(password_bytes).digest()
        
        return password_bytes.hex()
    
    def verify_password(self, password: str, password_hash: str, salt: str) -> bool:
        """
        验证密码
        
        Args:
            password: 输入的密码
            password_hash: 存储的密码哈希值
            salt: 盐值
            
        Returns:
            密码正确返回True
        """
        computed_hash = self._hash_password(password, salt)
        return computed_hash == password_hash
    
    def create_user(self, username: str, password: str, role: str = "user") -> Optional[int]:
        """
        创建新用户
        
        Args:
            username: 用户名
            password: 密码
            role: 用户角色
            
        Returns:
            成功返回用户ID，失败返回None
        """
        try:
            # 检查用户名是否已存在
            if self.get_user_by_username(username):
                raise ValueError(f"用户名 '{username}' 已存在")
            
            # 生成盐值和密码哈希
            salt = self._generate_salt()
            password_hash = self._hash_password(password, salt)
            
            # 创建用户对象
            user = User(
                username=username,
                password_hash=password_hash,
                salt=salt,
                role=role
            )
            
            # 保存到数据库
            return self._create_user_in_db(user)
            
        except Exception as e:
            print(f"创建用户失败: {e}")
            return None
    
    def _create_user_in_db(self, user: User) -> Optional[int]:
        """将用户保存到数据库"""
        connection = self._get_connection()
        try:
            cursor = connection.cursor()
            
            insert_sql = """
            INSERT INTO users (username, password_hash, salt, role, created_at, is_active)
            VALUES (%s, %s, %s, %s, %s, %s)
            """
            
            cursor.execute(insert_sql, (
                user.username,
                user.password_hash,
                user.salt,
                user.role,
                user.created_at,
                user.is_active
            ))
            
            return cursor.lastrowid
            
        except Exception as e:
            print(f"保存用户到数据库失败: {e}")
            return None
        finally:
            connection.close()
    
    def authenticate(self, username: str, password: str) -> Optional[User]:
        """
        用户认证
        
        Args:
            username: 用户名
            password: 密码
            
        Returns:
            认证成功返回User对象，失败返回None
        """
        try:
            user = self.get_user_by_username(username)
            if not user:
                return None
            
            if not user.is_active:
                print(f"用户 '{username}' 已被禁用")
                return None
            
            if self.verify_password(password, user.password_hash, user.salt):
                # 更新最后登录时间
                self._update_last_login(user.user_id)
                user.last_login = datetime.datetime.now()
                return user
            
            return None
            
        except Exception as e:
            print(f"用户认证失败: {e}")
            return None
    
    def get_user_by_username(self, username: str) -> Optional[User]:
        """根据用户名获取用户"""
        connection = self._get_connection()
        try:
            cursor = connection.cursor()
            
            select_sql = """
            SELECT user_id, username, password_hash, salt, user_type, 
                   created_at, last_login, is_active
            FROM users WHERE username = %s
            """
            
            cursor.execute(select_sql, (username,))
            row = cursor.fetchone()
            
            if row:
                return User(
                    user_id=row[0],
                    username=row[1],
                    password_hash=row[2],
                    salt=row[3],
                    role=row[4],
                    created_at=row[5],
                    last_login=row[6],
                    is_active=row[7]
                )
            
            return None
            
        except Exception as e:
            print(f"获取用户失败: {e}")
            return None
        finally:
            connection.close()
    
    def get_user_by_id(self, user_id: int) -> Optional[User]:
        """根据用户ID获取用户"""
        connection = self._get_connection()
        try:
            cursor = connection.cursor()
            
            select_sql = """
            SELECT user_id, username, password_hash, salt, user_type, 
                   created_at, last_login, is_active
            FROM users WHERE user_id = %s
            """
            
            cursor.execute(select_sql, (user_id,))
            row = cursor.fetchone()
            
            if row:
                return User(
                    user_id=row[0],
                    username=row[1],
                    password_hash=row[2],
                    salt=row[3],
                    role=row[4],
                    created_at=row[5],
                    last_login=row[6],
                    is_active=row[7]
                )
            
            return None
            
        except Exception as e:
            print(f"获取用户失败: {e}")
            return None
        finally:
            connection.close()
    
    def _update_last_login(self, user_id: int):
        """更新最后登录时间"""
        connection = self._get_connection()
        try:
            cursor = connection.cursor()
            
            update_sql = """
            UPDATE users SET last_login = CURRENT_TIMESTAMP
            WHERE user_id = %s
            """
            
            cursor.execute(update_sql, (user_id,))
            
        except Exception as e:
            print(f"更新登录时间失败: {e}")
        finally:
            connection.close()
    
    def change_password(self, user_id: int, old_password: str, new_password: str) -> bool:
        """
        修改密码
        
        Args:
            user_id: 用户ID
            old_password: 旧密码
            new_password: 新密码
            
        Returns:
            修改成功返回True
        """
        try:
            user = self.get_user_by_id(user_id)
            if not user:
                return False
            
            # 验证旧密码
            if not self.verify_password(old_password, user.password_hash, user.salt):
                return False
            
            # 生成新的盐值和密码哈希
            new_salt = self._generate_salt()
            new_password_hash = self._hash_password(new_password, new_salt)
            
            # 更新数据库
            connection = self._get_connection()
            try:
                cursor = connection.cursor()
                
                update_sql = """
                UPDATE users SET password_hash = %s, salt = %s
                WHERE user_id = %s
                """
                
                cursor.execute(update_sql, (new_password_hash, new_salt, user_id))
                return True
                
            finally:
                connection.close()
            
        except Exception as e:
            print(f"修改密码失败: {e}")
            return False
    
    def get_all_users(self) -> List[User]:
        """获取所有用户列表"""
        connection = self._get_connection()
        try:
            cursor = connection.cursor()
            
            select_sql = """
            SELECT user_id, username, password_hash, salt, user_type, 
                   created_at, last_login, is_active
            FROM users ORDER BY created_at DESC
            """
            
            cursor.execute(select_sql)
            rows = cursor.fetchall()
            
            users = []
            for row in rows:
                users.append(User(
                    user_id=row[0],
                    username=row[1],
                    password_hash=row[2],
                    salt=row[3],
                    role=row[4],
                    created_at=row[5],
                    last_login=row[6],
                    is_active=row[7]
                ))
            
            return users
            
        except Exception as e:
            print(f"获取用户列表失败: {e}")
            return []
        finally:
            connection.close()
    
    def test_connection(self) -> bool:
        """测试数据库连接"""
        try:
            connection = self._get_connection()
            connection.close()
            return True
        except Exception as e:
            print(f"数据库连接测试失败: {e}")
            return False


def create_user_manager() -> Optional[UserManager]:
    """创建用户管理器实例"""
    try:
        # 加载数据库配置
        config_manager = DatabaseConfig()
        if not config_manager.validate_config():
            print("数据库配置无效，请运行 python database_config.py 进行配置")
            return None
        
        mysql_config = config_manager.get_mysql_config()
        
        # 创建用户管理器
        user_manager = UserManager(**mysql_config)
        
        # 测试连接
        if user_manager.test_connection():
            print("✓ 用户管理器初始化成功")
            return user_manager
        else:
            print("✗ 用户管理器连接失败")
            return None
            
    except Exception as e:
        print(f"创建用户管理器失败: {e}")
        return None


if __name__ == "__main__":
    # 测试用户管理器
    print("=== 用户管理器测试 ===")
    
    user_manager = create_user_manager()
    if user_manager:
        print("用户管理器创建成功！")
        
        # 显示现有用户
        users = user_manager.get_all_users()
        print(f"\n当前系统中有 {len(users)} 个用户:")
        for user in users:
            print(f"  - {user.username} ({user.role}) - 创建时间: {user.created_at}")
    else:
        print("用户管理器创建失败！") 