"""
密碼產生與驗證工具
"""
import secrets
import string
import re
import bcrypt


def generate_secure_password(length: int = 16) -> str:
    """
    產生安全的隨機密碼

    Args:
        length: 密碼長度（預設 16 字元）

    Returns:
        安全的隨機密碼

    範例:
        >>> pwd = generate_secure_password()
        >>> len(pwd)
        16
        >>> validate_password_strength(pwd)
        True
    """
    if length < 8:
        raise ValueError("密碼長度至少需要 8 個字元")

    # 字元集合
    lowercase = string.ascii_lowercase
    uppercase = string.ascii_uppercase
    digits = string.digits
    special = "!@#$%^&*()-_=+[]{}|;:,.<>?"

    # 確保至少包含每種類型各一個
    password = [
        secrets.choice(lowercase),
        secrets.choice(uppercase),
        secrets.choice(digits),
        secrets.choice(special)
    ]

    # 剩餘字元隨機選擇
    all_chars = lowercase + uppercase + digits + special
    password += [secrets.choice(all_chars) for _ in range(length - 4)]

    # 打亂順序
    secrets.SystemRandom().shuffle(password)

    return ''.join(password)


def hash_password(password: str) -> str:
    """
    使用 bcrypt 加密密碼

    Args:
        password: 明文密碼

    Returns:
        加密後的密碼 hash
    """
    password_bytes = password.encode('utf-8')
    salt = bcrypt.gensalt()
    hashed = bcrypt.hashpw(password_bytes, salt)
    return hashed.decode('utf-8')


def verify_password(plain_password: str, hashed_password: str) -> bool:
    """
    驗證密碼

    Args:
        plain_password: 明文密碼
        hashed_password: 加密密碼

    Returns:
        是否匹配
    """
    return bcrypt.checkpw(
        plain_password.encode('utf-8'),
        hashed_password.encode('utf-8')
    )


def validate_password_strength(password: str) -> tuple[bool, list[str]]:
    """
    驗證密碼強度

    Args:
        password: 待驗證的密碼

    Returns:
        (是否通過, 錯誤訊息列表)

    範例:
        >>> validate_password_strength("weak")
        (False, ['密碼長度至少需要 8 個字元', ...])
        >>> validate_password_strength("Strong@Pass123")
        (True, [])
    """
    errors = []

    # 長度檢查
    if len(password) < 8:
        errors.append("密碼長度至少需要 8 個字元")

    # 大寫字母
    if not re.search(r'[A-Z]', password):
        errors.append("密碼必須包含至少一個大寫字母")

    # 小寫字母
    if not re.search(r'[a-z]', password):
        errors.append("密碼必須包含至少一個小寫字母")

    # 數字
    if not re.search(r'\d', password):
        errors.append("密碼必須包含至少一個數字")

    # 特殊符號
    if not re.search(r'[!@#$%^&*()\-_=+\[\]{}|;:,.<>?]', password):
        errors.append("密碼必須包含至少一個特殊符號")

    # 常見弱密碼檢查
    common_weak_passwords = [
        'password', 'password123', '12345678', 'qwerty',
        'admin123', 'letmein', 'welcome', 'monkey'
    ]
    if password.lower() in common_weak_passwords:
        errors.append("此密碼過於常見，請使用更安全的密碼")

    return (len(errors) == 0, errors)


def validate_password_for_user(
    password: str,
    username: str = None,
    name: str = None,
    email: str = None
) -> tuple[bool, list[str]]:
    """
    驗證密碼（包含使用者資訊檢查）

    Args:
        password: 待驗證的密碼
        username: 使用者帳號
        name: 使用者姓名
        email: Email

    Returns:
        (是否通過, 錯誤訊息列表)
    """
    # 先檢查基本強度
    is_valid, errors = validate_password_strength(password)

    # 檢查是否包含使用者資訊
    password_lower = password.lower()

    if username and username.lower() in password_lower:
        errors.append("密碼不可包含帳號名稱")

    if name:
        name_parts = name.split()
        for part in name_parts:
            if len(part) >= 3 and part.lower() in password_lower:
                errors.append("密碼不可包含姓名")
                break

    if email:
        email_user = email.split('@')[0]
        if len(email_user) >= 3 and email_user.lower() in password_lower:
            errors.append("密碼不可包含 Email 使用者名稱")

    return (len(errors) == 0, errors)


if __name__ == "__main__":
    # 測試密碼產生
    print("=== 密碼產生測試 ===")
    for i in range(5):
        pwd = generate_secure_password()
        is_valid, errors = validate_password_strength(pwd)
        print(f"密碼 {i+1}: {pwd} - 有效: {is_valid}")

    # 測試密碼驗證
    print("\n=== 密碼驗證測試 ===")
    test_cases = [
        ("weak", False),
        ("WeakPass", False),
        ("WeakPass123", False),
        ("Strong@Pass123", True),
        ("admin@Pass123", True)
    ]

    for password, expected in test_cases:
        is_valid, errors = validate_password_strength(password)
        status = "✓" if is_valid == expected else "✗"
        print(f"{status} {password}: {is_valid}")
        if errors:
            for error in errors:
                print(f"  - {error}")

    # 測試加密與驗證
    print("\n=== 密碼加密測試 ===")
    plain_pwd = "TestPassword@123"
    hashed = hash_password(plain_pwd)
    print(f"明文密碼: {plain_pwd}")
    print(f"加密密碼: {hashed}")
    print(f"驗證正確密碼: {verify_password(plain_pwd, hashed)}")
    print(f"驗證錯誤密碼: {verify_password('WrongPassword', hashed)}")
